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; }
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)); }
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; }