Example #1
0
        public void Reset()
        {
            FrameRequestHeaders?.Reset();
            FrameResponseHeaders?.Reset();

            _onStarting  = null;
            _onCompleted = null;

            _requestProcessingStatus = RequestProcessingStatus.RequestPending;
            _keepAlive            = false;
            _autoChunk            = false;
            _applicationException = null;

            ResetFeatureCollection();

            Scheme       = null;
            Method       = null;
            PathBase     = null;
            Path         = null;
            QueryString  = null;
            _httpVersion = HttpVersionType.Unset;
            StatusCode   = 200;
            ReasonPhrase = null;

            RemoteIpAddress = RemoteEndPoint?.Address;
            RemotePort      = RemoteEndPoint?.Port ?? 0;

            LocalIpAddress      = LocalEndPoint?.Address;
            LocalPort           = LocalEndPoint?.Port ?? 0;
            ConnectionIdFeature = ConnectionId;

            PrepareRequest?.Invoke(this);

            _manuallySetRequestAbortToken = null;
            _abortedCts = null;
        }
Example #2
0
        public static MessageBody For(
            HttpVersion httpVersion,
            FrameRequestHeaders headers,
            Frame context)
        {
            // see also http://tools.ietf.org/html/rfc2616#section-4.4
            var keepAlive = httpVersion != HttpVersion.Http10;

            var connection = headers.HeaderConnection;

            if (connection.Count > 0)
            {
                var connectionOptions = FrameHeaders.ParseConnection(connection);

                if ((connectionOptions & ConnectionOptions.Upgrade) == ConnectionOptions.Upgrade)
                {
                    return(new ForRemainingData(true, context));
                }

                keepAlive = (connectionOptions & ConnectionOptions.KeepAlive) == ConnectionOptions.KeepAlive;
            }

            var transferEncoding = headers.HeaderTransferEncoding;

            if (transferEncoding.Count > 0)
            {
                var transferCoding = FrameHeaders.GetFinalTransferCoding(headers.HeaderTransferEncoding);

                // https://tools.ietf.org/html/rfc7230#section-3.3.3
                // If a Transfer-Encoding header field
                // is present in a request and the chunked transfer coding is not
                // the final encoding, the message body length cannot be determined
                // reliably; the server MUST respond with the 400 (Bad Request)
                // status code and then close the connection.
                if (transferCoding != TransferCoding.Chunked)
                {
                    context.RejectRequest(RequestRejectionReason.FinalTransferCodingNotChunked, transferEncoding.ToString());
                }

                return(new ForChunkedEncoding(keepAlive, headers, context));
            }

            var unparsedContentLength = headers.HeaderContentLength;

            if (unparsedContentLength.Count > 0)
            {
                try
                {
                    var contentLength = FrameHeaders.ParseContentLength(unparsedContentLength);
                    return(new ForContentLength(keepAlive, contentLength, context));
                }
                catch (InvalidOperationException)
                {
                    context.RejectRequest(RequestRejectionReason.InvalidContentLength, unparsedContentLength);
                }
            }

            // Avoid slowing down most common case
            if (!object.ReferenceEquals(context.Method, HttpMethods.Get))
            {
                // If we got here, request contains no Content-Length or Transfer-Encoding header.
                // Reject with 411 Length Required.
                if (HttpMethods.IsPost(context.Method) || HttpMethods.IsPut(context.Method))
                {
                    var requestRejectionReason = httpVersion == HttpVersion.Http11 ? RequestRejectionReason.LengthRequired : RequestRejectionReason.LengthRequiredHttp10;
                    context.RejectRequest(requestRejectionReason, context.Method);
                }
            }

            return(new ForContentLength(keepAlive, 0, context));
        }
Example #3
0
        public bool TakeMessageHeaders(SocketInput input, FrameRequestHeaders requestHeaders)
        {
            var scan     = input.ConsumingStart();
            var consumed = scan;

            try
            {
                while (!scan.IsEnd)
                {
                    var ch = scan.Peek();
                    if (ch == -1)
                    {
                        return(false);
                    }
                    else if (ch == '\r')
                    {
                        // Check for final CRLF.
                        scan.Take();
                        ch = scan.Take();

                        if (ch == -1)
                        {
                            return(false);
                        }
                        else if (ch == '\n')
                        {
                            consumed = scan;
                            return(true);
                        }

                        // Headers don't end in CRLF line.
                        RejectRequest("Headers corrupted, invalid header sequence.");
                    }
                    else if (ch == ' ' || ch == '\t')
                    {
                        RejectRequest("Header line must not start with whitespace.");
                    }

                    var beginName = scan;
                    if (scan.Seek(ref _vectorColons, ref _vectorCRs) == -1)
                    {
                        return(false);
                    }
                    var endName = scan;

                    ch = scan.Take();
                    if (ch != ':')
                    {
                        RejectRequest("No ':' character found in header line.");
                    }

                    var validateName = beginName;
                    if (validateName.Seek(ref _vectorSpaces, ref _vectorTabs, ref _vectorColons) != ':')
                    {
                        RejectRequest("Whitespace is not allowed in header name.");
                    }

                    var beginValue = scan;
                    ch = scan.Peek();

                    if (ch == -1)
                    {
                        return(false);
                    }

                    // Skip header value leading whitespace.
                    while (ch == ' ' || ch == '\t')
                    {
                        scan.Take();
                        beginValue = scan;

                        ch = scan.Peek();
                        if (ch == -1)
                        {
                            return(false);
                        }
                    }

                    scan = beginValue;
                    if (scan.Seek(ref _vectorCRs) == -1)
                    {
                        // no "\r" in sight, burn used bytes and go back to await more data
                        return(false);
                    }

                    scan.Take();      // we know this is '\r'
                    ch = scan.Take(); // expecting '\n'

                    if (ch == -1)
                    {
                        return(false);
                    }
                    else if (ch != '\n')
                    {
                        RejectRequest("Header line must end in CRLF; only CR found.");
                    }

                    var next = scan.Peek();
                    if (next == -1)
                    {
                        return(false);
                    }
                    else if (next == ' ' || next == '\t')
                    {
                        // From https://tools.ietf.org/html/rfc7230#section-3.2.4:
                        //
                        // Historically, HTTP header field values could be extended over
                        // multiple lines by preceding each extra line with at least one space
                        // or horizontal tab (obs-fold).  This specification deprecates such
                        // line folding except within the message/http media type
                        // (Section 8.3.1).  A sender MUST NOT generate a message that includes
                        // line folding (i.e., that has any field-value that contains a match to
                        // the obs-fold rule) unless the message is intended for packaging
                        // within the message/http media type.
                        //
                        // A server that receives an obs-fold in a request message that is not
                        // within a message/http container MUST either reject the message by
                        // sending a 400 (Bad Request), preferably with a representation
                        // explaining that obsolete line folding is unacceptable, or replace
                        // each received obs-fold with one or more SP octets prior to
                        // interpreting the field value or forwarding the message downstream.
                        RejectRequest("Header value line folding not supported.");
                    }

                    // Trim trailing whitespace from header value by repeatedly advancing to next
                    // whitespace or CR.
                    //
                    // - If CR is found, this is the end of the header value.
                    // - If whitespace is found, this is the _tentative_ end of the header value.
                    //   If non-whitespace is found after it and it's not CR, seek again to the next
                    //   whitespace or CR for a new (possibly tentative) end of value.
                    var ws       = beginValue;
                    var endValue = scan;
                    do
                    {
                        ws.Seek(ref _vectorSpaces, ref _vectorTabs, ref _vectorCRs);
                        endValue = ws;

                        ch = ws.Take();
                        while (ch == ' ' || ch == '\t')
                        {
                            ch = ws.Take();
                        }
                    } while (ch != '\r');

                    var name  = beginName.GetArraySegment(endName);
                    var value = beginValue.GetAsciiString(endValue);

                    consumed = scan;
                    requestHeaders.Append(name.Array, name.Offset, name.Count, value);
                }

                return(false);
            }
            finally
            {
                input.ConsumingComplete(consumed, scan);
            }
        }
 public ForChunkedEncoding(bool keepAlive, FrameRequestHeaders headers, Frame context)
     : base(context)
 {
     RequestKeepAlive = keepAlive;
     _requestHeaders  = headers;
 }