/// <summary> /// Begin processing the request by dispatching a <code>BeginProcessRequest</code> /// invocation to an instance of an IHttpHandler class. If the processing fails /// for any reason, the server responds with HTTP 400 Bad Request. /// </summary> /// <param name="wr"></param> private void ProcessRequest(TcpServerWorkerRequest wr) { try { var context = new HttpContext(wr); var app = _getInstance(context); app.BeginProcessRequest(context, _handlerCompletionCallback, wr); } catch { try { // Send a bad request response if the context cannot // be created for any reason. wr.SendStatus(400, "Bad Request"); wr.SendKnownResponseHeader("Content-Type", "text/html; charset=utf8"); var body = Encoding.ASCII.GetBytes("<html><body>Bad Request</body></html>"); wr.SendResponseFromMemory(body, body.Length); var response = wr.FlushResponse(); SendResponse(response); wr.EndOfRequest(); } finally { } } }
/// <summary> /// Completes the request processing and initiates the process of /// sending a response back to the client. /// </summary> /// <param name="wr"></param> private void FinishRequest(TcpServerWorkerRequest wr) { // The following lines are a temporary stand-in while the rest // of the application processing capabilities are being written. wr.SendStatus(200, "OK"); wr.SendKnownResponseHeader("Content-Type", "text/html; charset=utf8"); var body = Encoding.ASCII.GetBytes("<html><body>Hello, world</body></html>"); wr.SendResponseFromMemory(body, body.Length); var response = wr.FlushResponse(); SendResponse(response); wr.EndOfRequest(); }
/// <summary> /// Factory to create instances of the <code>TcpServerWorkerRequest</code> class. /// </summary> /// <param name="segment">An serialized byte array of the incoming request.</param> /// <returns></returns> internal static TcpServerWorkerRequest CreateWorkerRequest(byte[] segment) { if (null == segment) { throw new ArgumentNullException(nameof(segment)); } if (0 == segment.Length) { throw new ArgumentException(nameof(segment.Length)); } var wr = new TcpServerWorkerRequest(segment); if (null != wr) { wr.Initialize(); } return(wr); }
/// <summary> /// Initiates the incoming connection socket for the network server /// and initialises an instance of the HttpApplication. /// </summary> /// <returns></returns> public async void Start <T>(HttpApplicationFactory <T> factory) where T : IHttpAsyncHandler, new() { _getInstance = factory.GetApplicationInstance; try { // Find an IPv4 address on the host computer and attempt to establish // an incoming network socket over it on the specified port number. var entries = await Dns.GetHostEntryAsync(_host); if (0 == entries.AddressList.Length) { throw new Exception($"Could not bind to address on host {_host}"); } IPAddress address = null; foreach (var a in entries.AddressList) { if (AddressFamily.InterNetwork == a.AddressFamily) { address = a; break; } } var localEndPoint = new IPEndPoint(address, _port); var listener = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); listener.Bind(localEndPoint); listener.Listen(10); var incomingBuffer = new ArraySegment <byte>(new byte[1024]); var message = new StringBuilder(); _handlerCompletionCallback = new AsyncCallback(OnHandlerCompletion); // Go into an infinite loop and wait for incoming // connections. When a connection is made, the application // receives the message sent by the client and pumps it // into the processing pipeline. while (true) { _client = await listener.AcceptAsync(); var length = await _client.ReceiveAsync(incomingBuffer, SocketFlags.None); message.Append(Encoding.ASCII.GetString(incomingBuffer.Array, 0, length)); Log.Verbose(message.ToString()); Log.Information("Received {length} bytes from client", length); // Deserialize the incoming message buffer into a TcpServerWorkerRequest instance var wr = TcpServerWorkerRequest.CreateWorkerRequest(incomingBuffer.Array); ProcessRequest(wr); } } catch (SocketException exception) { Log.Fatal($"Could not start a server at {_host}:{_port}.\r\nError: {exception.Message}"); } catch (SecurityException exception) { Log.Fatal($"A security violation occurred while starting a server at {_host}:{_port}.\r\nError: {exception.Message}"); } }