Example #1
0
 /// <summary>
 /// Created only by  HttpServer
 /// </summary>
 internal HttpContext(TcpClient client, HttpReader reader, HttpWriter writer, bool isSecure)
 {
     mTcpClient = client;
     mReader    = reader;
     mWriter    = writer;
     IsSecure   = isSecure;
 }
Example #2
0
        async void TryProcessRequestsAsync(TcpClient client, X509Certificate certificate)
        {
            int concurrentRequests = Interlocked.Add(ref mConcurrentRequests, 1);

            Thread.VolatileWrite(ref mMaxConcurrentRequests, Math.Max(concurrentRequests, Thread.VolatileRead(ref mMaxConcurrentRequests)));

            using (client)
            {
                HttpContext context = null;
                try
                {
                    // Setup stream or SSL stream
                    client.NoDelay = true;
                    var  tcpStream = (Stream)client.GetStream();
                    bool isSecure  = false;
                    if (certificate != null)
                    {
                        // Wrap stream in an SSL stream, and authenticate
                        var sslStream = new SslStream(tcpStream, false);
                        await sslStream.AuthenticateAsServerAsync(certificate);

                        tcpStream = sslStream;
                        isSecure  = true;
                    }
                    // Process requests on this possibly persistent TCP stream
                    var reader = new HttpReader(tcpStream, mCancellationToken, Sync);
                    var writer = new HttpWriter(tcpStream, mCancellationToken, Sync);
                    context = new HttpContext(client, reader, writer, isSecure);
                    await ProcessRequests(context, reader, writer).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    try
                    {
                        await ProcessExceptionAsync(context, ex);
                    }
                    catch (Exception doubleFaultEx)
                    {
                        Log.Write("DOUBLE FAULT EXCEPTION", doubleFaultEx);
                    }
                }
            }
            Interlocked.Add(ref mConcurrentRequests, -1);
        }
Example #3
0
        /// <summary>
        /// Only called by HttpContext
        /// </summary>
        internal WebSocket(HttpContext context, string protocol)
        {
            mState   = WebSocketState.Open;
            mContext = context;

            var request         = context.Request;
            var requestProtocol = request.Headers["sec-websocket-protocol"]; // TBD: Split "," separated list

            if (protocol != requestProtocol)
            {
                throw new HttpException(400, "Invalid websocket protocol.  Client requested '" + requestProtocol + "', server accepted '" + protocol + "'");
            }

            // RFC 6455, 4.2.1 and 4.2.2
            string key = request.Headers["sec-websocket-key"];

            if (key == "")
            {
                throw new HttpException(400, "Websocket key not sent by client");
            }
            string keyHash;

            using (var sha = SHA1.Create())
                keyHash = Convert.ToBase64String(sha.ComputeHash(Encoding.UTF8.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")));

            var response = mContext.Response;

            response.StatusCode         = 101;
            response.StatusMessage      = "Switching Protocols";
            response.Connection         = "Upgrade";
            response.Headers["upgrade"] = "websocket";
            response.Headers["Sec-WebSocket-Accept"]   = keyHash;
            response.Headers["Sec-WebSocket-Protocol"] = protocol;
            request.ContentLength = long.MaxValue; // Stream never ends
            mWriter = mContext.GetWriter(long.MaxValue);
            mReader = mContext.GetReader();
        }
Example #4
0
        /// <summary>
        /// Process requests as long as there is not an error
        /// </summary>
        async Task ProcessRequests(HttpContext context, HttpReader reader, HttpWriter writer)
        {
            int persistentConnections = 0;

            do
            {
                persistentConnections++;
                try
                {
                    // Read header
                    reader.ReadTimeout = HeaderTimeout;
                    var buffer = await reader.ReadHttpHeaderAsyncInternal();

                    reader.PositionInternal = 0;
                    reader.LengthInternal   = HttpContext.HTTP_HEADER_MAX_SIZE;
                    if (buffer.Count == 0)
                    {
                        return;  // Connection closed
                    }
                    // Parse header
                    context.ResetRequestInternal(HttpRequest.Parse(buffer), new HttpResponse());
                }
                catch (Exception ex)
                {
                    Log.Write("HTTP header exception: " + ex.GetType() + " - " + ex.Message);
                    return; // Close connection
                }

                // Handle body
                reader.ReadTimeout  = BodyTimeout;
                writer.WriteTimeout = BodyTimeout;
                try
                {
                    // Process HTTP request
                    var handler = HttpHandler;
                    if (handler == null)
                    {
                        throw new HttpException(503, "HTTP request handler not installed");
                    }
                    await handler(context).ConfigureAwait(false);
                }
                catch (HttpException ex) when(ex.KeepConnectionOpen && !context.Response.HeaderSent)
                {
                    // Keep the persistent connection open only if it's OK to do so.
                    await ProcessExceptionAsync(context, ex);
                }
                await writer.FlushAsync();

                // Any of these problems will terminate a persistent connection
                var response    = context.Response;
                var request     = context.Request;
                var isWebsocket = request.IsWebSocketRequest;
                if (!response.HeaderSent)
                {
                    throw new HttpException(500, "Request handler did not send a response for: " + context.Request.Path);
                }
                if (!isWebsocket && reader.Position != request.ContentLength && request.ContentLength >= 0)
                {
                    throw new HttpException(500, "Request handler did not read correct number of bytes: " + request.Path);
                }
                if (!isWebsocket && writer.Position != response.ContentLength)
                {
                    throw new HttpException(500, "Request handler did not write correct number of bytes: " + request.Path);
                }
            } while (!context.Request.IsWebSocketRequest && context.Response.Connection == "keep-alive");
        }