=== modified file 'beagled/Server.cs' --- beagled/Server.cs +++ beagled/Server.cs @@ -38,7 +38,8 @@ namespace Beagle.Daemon { class HttpConnectionHandler : ConnectionHandler { - private HttpListenerContext context; //The object that we use for getting the request and sending the response + private HttpListenerContext context; //The object that we use for getting the request and sending the response + private HttpListener listener; //The listener public HttpConnectionHandler (HttpListenerContext context) { @@ -47,51 +48,10 @@ public override void HandleConnection() { - - } - - public override void Close () - { - } - - public override void SetupWatch () - { - - } - - public override bool SendResponse (ResponseMessage response) - { - return false; - } - - - - - - } - - class UnixConnectionHandler : ConnectionHandler { - private UnixClient client; - - public UnixConnectionHandler (UnixClient client) - { - this.client = client; - } - - public override bool SendResponse(ResponseMessage response) - { - bool result = base.SendResponse(response, this.client.GetStream () ); - - if (result) { - // Send an end of message marker - this.client.GetStream().WriteByte (0xff); - this.client.GetStream().Flush (); - } - return result; - } - - public override void HandleConnection () - { + Logger.Log.Debug ("webserver: serving request for " + context.Request.Url); + + //Query request: read content and forward to HandleRequest for processing + this.thread = Thread.CurrentThread; bool force_close_connection = false; @@ -116,8 +76,8 @@ lock (this.client_lock) { // The connection may have been closed within this loop. - if (this.client != null) - bytes_read = this.client.GetStream ().Read (network_data, 0, 4096); + if (this.listener != null) + bytes_read = this.context.Request.InputStream.Read (network_data, 0, 4096); } lock (this.blocking_read_lock) @@ -146,6 +106,123 @@ } } while (bytes_read > 0 && end_index == -1); + buffer_stream.Seek (0, SeekOrigin.Begin); + HandleRequest(buffer_stream); + + cleanup: + buffer_stream.Close (); + + if (force_close_connection) + Close (); + else + SetupWatch (); + + Server.MarkHandlerAsKilled (this); + Shutdown.WorkerFinished (network_data); + } + + public override void Close () + { + } + + public override void SetupWatch () + { + + } + + public override bool SendResponse (ResponseMessage response) + { + return SendResponse (response, context.Response.OutputStream); + } + + + + + + } + + class UnixConnectionHandler : ConnectionHandler { + private UnixClient client; + + public UnixConnectionHandler (UnixClient client) + { + this.client = client; + } + + public override bool SendResponse(ResponseMessage response) + { + bool result = false; + + lock (this.client_lock) { + if (this.client == null) + return false; + result = base.SendResponse(response, this.client.GetStream () ); + } + + if (result) { + // Send an end of message marker + this.client.GetStream().WriteByte (0xff); + this.client.GetStream().Flush (); + } + return result; + } + + public override void HandleConnection () + { + this.thread = Thread.CurrentThread; + + bool force_close_connection = false; + + // Read the data off the socket and store it in a + // temporary memory buffer. Once the end-of-message + // character has been read, discard remaining data + // and deserialize the request. + byte[] network_data = new byte [4096]; + MemoryStream buffer_stream = new MemoryStream (); + int bytes_read, total_bytes = 0, end_index = -1; + + // We use the network_data array as an object to represent this worker. + Shutdown.WorkerStart (network_data, String.Format ("HandleConnection ({0})", ++connection_count)); + + do { + bytes_read = 0; + + try { + lock (this.blocking_read_lock) + this.in_blocking_read = true; + + lock (this.client_lock) { + // The connection may have been closed within this loop. + if (this.client != null) + bytes_read = this.client.GetStream ().Read (network_data, 0, 4096); + } + + lock (this.blocking_read_lock) + this.in_blocking_read = false; + } catch (Exception e) { + // Aborting the thread mid-read will + // cause an IOException to be thorwn, + // which sets the ThreadAbortException + // as its InnerException.MemoryStream + if (!(e is IOException || e is ThreadAbortException)) + throw; + + Logger.Log.Debug ("Bailing out of HandleConnection -- shutdown requested"); + Server.MarkHandlerAsKilled (this); + return; + } + + total_bytes += bytes_read; + + if (bytes_read > 0) { + // 0xff signifies end of message + end_index = ArrayFu.IndexOfByte (network_data, (byte) 0xff); + + buffer_stream.Write (network_data, 0, + end_index == -1 ? bytes_read : end_index); + } + } while (bytes_read > 0 && end_index == -1); + // Something just connected to our socket and then // hung up. The IndexHelper (among other things) does // this to check that a server is still running. It's @@ -237,11 +314,9 @@ protected bool in_blocking_read; - public bool SendResponse (ResponseMessage response, NetworkStream stream) - { - lock (this.client_lock) { - //if (this.client == null) XXX - ///return false; + public bool SendResponse (ResponseMessage response, Stream stream) + { + try { #if ENABLE_XML_DUMP @@ -262,7 +337,6 @@ } return true; - } } static XmlSerializer req_serializer = new XmlSerializer (typeof (RequestWrapper), RequestMessage.Types); @@ -422,8 +496,8 @@ { Logger.Log.Debug("Running in HTTP mode"); //TODO: For now, it's either http (networked) or unix sockets mode. We should be able to run both in parallel. - - string prefix = "http://127.0.0.1:80/beagled/"; + //TODO: The port number should be random >1024. If taken, retry. + string prefix = "http://127.0.0.1:4000/beagled/"; http_listener.Prefixes.Add(prefix); this.http_listener.Start(); @@ -506,7 +580,11 @@ public void Start (bool enable_http) { - this.enable_http = enable_http; + if (enable_http) + { + this.enable_http = true; + http_listener = new HttpListener (); + } if (!Shutdown.ShutdownRequested) ExceptionHandlingThread.Start (new ThreadStart (this.Run));