public async Task RequestBodyTooLargeContentLengthExceedsGlobalLimit() { var globalMaxRequestBodySize = 0x100000000; BadHttpRequestException exception = null; using (var testServer = await TestServer.Create( async ctx => { try { await ctx.Request.Body.ReadAsync(new byte[2000]); } catch (BadHttpRequestException ex) { exception = ex; throw ex; } }, LoggerFactory)) { using (var connection = testServer.CreateConnection()) { await connection.Send( "POST / HTTP/1.1", $"Content-Length: {globalMaxRequestBodySize + 1}", "Host: localhost", "", ""); await connection.Receive("HTTP/1.1 413 Payload Too Large"); } } Assert.Equal(CoreStrings.BadRequest_RequestBodyTooLarge, exception.Message); }
// The lead '[' was already checked private static void ValidateIPv6Host(string hostText) { for (var i = 1; i < hostText.Length; i++) { var ch = hostText[i]; if (ch == ']') { // [::1] is the shortest valid IPv6 host if (i < 4) { BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText); } else if (i + 1 < hostText.Length) { // Tail call ValidateHostPort(hostText, i + 1); } return; } if (!IsHex(ch) && ch != ':' && ch != '.') { BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText); } } // Must contain a ']' BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText); }
private void ParseChunkedSuffix(ReadOnlySequence <byte> buffer, out SequencePosition consumed, out SequencePosition examined) { consumed = buffer.Start; examined = buffer.Start; if (buffer.Length < 2) { examined = buffer.End; return; } var suffixBuffer = buffer.Slice(0, 2); var suffixSpan = suffixBuffer.ToSpan(); // Advance examined before possibly throwing, so we don't risk examining less than the previous call to ParseChunkedSuffix. examined = suffixBuffer.End; if (suffixSpan[0] == '\r' && suffixSpan[1] == '\n') { consumed = suffixBuffer.End; AddAndCheckConsumedBytes(2); _mode = Mode.Prefix; } else { BadHttpRequestException.Throw(RequestRejectionReason.BadChunkSuffix); } }
public bool TakeMessageHeaders(ReadOnlySequence <byte> buffer, out SequencePosition consumed, out SequencePosition examined) { // Make sure the buffer is limited bool overLength = false; if (buffer.Length >= _remainingRequestHeadersBytesAllowed) { buffer = buffer.Slice(buffer.Start, _remainingRequestHeadersBytesAllowed); // If we sliced it means the current buffer bigger than what we're // allowed to look at overLength = true; } var result = _parser.ParseHeaders(new Http1ParsingHandler(this), buffer, out consumed, out examined, out var consumedBytes); _remainingRequestHeadersBytesAllowed -= consumedBytes; if (!result && overLength) { BadHttpRequestException.Throw(RequestRejectionReason.HeadersExceedMaxTotalSize); } if (result) { TimeoutControl.CancelTimeout(); } return(result); }
private async Task TestBadRequest(string request, string expectedResponseStatusCode, string expectedExceptionMessage, string expectedAllowHeader = null) { BadHttpRequestException loggedException = null; var mockKestrelTrace = new Mock <IKestrelTrace>(); mockKestrelTrace .Setup(trace => trace.IsEnabled(LogLevel.Information)) .Returns(true); mockKestrelTrace .Setup(trace => trace.ConnectionBadRequest(It.IsAny <string>(), It.IsAny <BadHttpRequestException>())) .Callback <string, BadHttpRequestException>((connectionId, exception) => loggedException = exception); using (var server = new TestServer(context => Task.CompletedTask, new TestServiceContext { Log = mockKestrelTrace.Object })) { using (var connection = server.CreateConnection()) { await connection.SendAll(request); await ReceiveBadRequestResponse(connection, expectedResponseStatusCode, server.Context.DateHeaderValue, expectedAllowHeader); } } mockKestrelTrace.Verify(trace => trace.ConnectionBadRequest(It.IsAny <string>(), It.IsAny <BadHttpRequestException>())); Assert.Equal(expectedExceptionMessage, loggedException.Message); }
private void OnAuthorityFormTarget(HttpMethod method, Span <byte> target) { _requestTargetForm = HttpRequestTarget.AuthorityForm; // This is not complete validation. It is just a quick scan for invalid characters // but doesn't check that the target fully matches the URI spec. if (HttpCharacters.ContainsInvalidAuthorityChar(target)) { ThrowRequestTargetRejected(target); } // The authority-form of request-target is only used for CONNECT // requests (https://tools.ietf.org/html/rfc7231#section-4.3.6). if (method != HttpMethod.Connect) { BadHttpRequestException.Throw(RequestRejectionReason.ConnectMethodRequired); } // When making a CONNECT request to establish a tunnel through one or // more proxies, a client MUST send only the target URI's authority // component (excluding any userinfo and its "@" delimiter) as the // request-target.For example, // // CONNECT www.example.com:80 HTTP/1.1 // // Allowed characters in the 'host + port' section of authority. // See https://tools.ietf.org/html/rfc3986#section-3.2 RawTarget = target.GetAsciiStringNonNullCharacters(); Path = string.Empty; QueryString = string.Empty; }
private Task HandleBadHttpRequestExceptionAsync(HttpContext httpContext, BadHttpRequestException e) { httpContext.Response.ContentType = "application/json"; httpContext.Response.StatusCode = (int)e.StatusCode; return(httpContext.Response.WriteAsync(e.Message)); }
internal void EnsureHostHeaderExists() { // https://tools.ietf.org/html/rfc7230#section-5.4 // A server MUST respond with a 400 (Bad Request) status code to any // HTTP/1.1 request message that lacks a Host header field and to any // request message that contains more than one Host header field or a // Host header field with an invalid field-value. var hostCount = HttpRequestHeaders.HostCount; var hostText = HttpRequestHeaders.HeaderHost.ToString(); if (hostCount <= 0) { if (_httpVersion == Http.HttpVersion.Http10) { return; } BadHttpRequestException.Throw(RequestRejectionReason.MissingHostHeader); } else if (hostCount > 1) { BadHttpRequestException.Throw(RequestRejectionReason.MultipleHostHeaders); } else if (_requestTargetForm != HttpRequestTarget.OriginForm) { // Tail call ValidateNonOrginHostHeader(hostText); } else if (!HttpUtilities.IsHostHeaderValid(hostText)) { BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText); } }
protected override void OnReadStarting() { if (_contentLength > _context.MaxRequestBodySize) { BadHttpRequestException.Throw(RequestRejectionReason.RequestBodyTooLarge); } }
private void ValidateNonOrginHostHeader(string hostText) { if (_requestTargetForm == HttpRequestTarget.AuthorityForm) { if (hostText != RawTarget) { BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText); } } else if (_requestTargetForm == HttpRequestTarget.AbsoluteForm) { // If the target URI includes an authority component, then a // client MUST send a field - value for Host that is identical to that // authority component, excluding any userinfo subcomponent and its "@" // delimiter. // System.Uri doesn't not tell us if the port was in the original string or not. // When IsDefaultPort = true, we will allow Host: with or without the default port if (hostText != _absoluteRequestTarget.Authority) { if (!_absoluteRequestTarget.IsDefaultPort || hostText != _absoluteRequestTarget.Authority + ":" + _absoluteRequestTarget.Port.ToString(CultureInfo.InvariantCulture)) { BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText); } } } if (!HttpUtilities.IsHostHeaderValid(hostText)) { BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText); } }
private void ParseChunkedSuffix(ReadOnlySequence <byte> buffer, out SequencePosition consumed, out SequencePosition examined) { consumed = buffer.Start; examined = buffer.Start; if (buffer.Length < 2) { examined = buffer.End; return; } var suffixBuffer = buffer.Slice(0, 2); var suffixSpan = suffixBuffer.ToSpan(); if (suffixSpan[0] == '\r' && suffixSpan[1] == '\n') { consumed = suffixBuffer.End; examined = suffixBuffer.End; AddAndCheckConsumedBytes(2); _mode = Mode.Prefix; } else { BadHttpRequestException.Throw(RequestRejectionReason.BadChunkSuffix); } }
private Message SavePostedFile(string postedFilePath, SessionModel model) { var fileInfo = new FileInfo(postedFilePath); if (fileInfo.Length > Convert.ToInt64(_config["MaxUploadSizeBytes"])) { BadHttpRequestException.Throw(RequestRejectionReason.InvalidContentLength, HttpMethod.Post); } var message = GetMessageFromModel(model, true); var uploadDir = Helper.GetUploadFolder(model.SessionId, _env.WebRootPath); if (!Directory.Exists(uploadDir)) { Directory.CreateDirectory(uploadDir); } // Use original file name var fileName = message.Text; if (IOFile.Exists(Path.Combine(uploadDir, fileName))) { // if exist then append digits from the session id fileName = Path.GetFileNameWithoutExtension(message.Text) + "_" + message.Id.Substring(0, 6) + Path.GetExtension(message.Text); } var destUploadPath = Path.Combine(uploadDir, fileName); message.Text = fileName; message.HasFile = true; message.FileSizeBytes = fileInfo.Length; IOFile.Move(postedFilePath, destUploadPath); return(message); }
private int CalculateChunkSize(int extraHexDigit, int currentParsedSize) { try { checked { if (extraHexDigit >= '0' && extraHexDigit <= '9') { return(currentParsedSize * 0x10 + (extraHexDigit - '0')); } else if (extraHexDigit >= 'A' && extraHexDigit <= 'F') { return(currentParsedSize * 0x10 + (extraHexDigit - ('A' - 10))); } else if (extraHexDigit >= 'a' && extraHexDigit <= 'f') { return(currentParsedSize * 0x10 + (extraHexDigit - ('a' - 10))); } } } catch (OverflowException ex) { throw new IOException(CoreStrings.BadRequest_BadChunkSizeData, ex); } BadHttpRequestException.Throw(RequestRejectionReason.BadChunkSizeData); return(-1); // can't happen, but compiler complains }
public void RejectRequest(string message) { var ex = new BadHttpRequestException(message); SetBadRequestState(ex); throw ex; }
private void ParseChunkedPrefix(ReadOnlySequence <byte> buffer, out SequencePosition consumed, out SequencePosition examined) { consumed = buffer.Start; examined = buffer.Start; var reader = new SequenceReader <byte>(buffer); if (!reader.TryRead(out var ch1) || !reader.TryRead(out var ch2)) { examined = reader.Position; return; } // Assigned this before calculating the chunk size since that can throw examined = reader.Position; var chunkSize = CalculateChunkSize(ch1, 0); ch1 = ch2; while (reader.Consumed < MaxChunkPrefixBytes) { if (ch1 == ';') { consumed = reader.Position; examined = reader.Position; AddAndCheckConsumedBytes(reader.Consumed); _inputLength = chunkSize; _mode = Mode.Extension; return; } if (!reader.TryRead(out ch2)) { examined = reader.Position; return; } if (ch1 == '\r' && ch2 == '\n') { consumed = reader.Position; examined = reader.Position; AddAndCheckConsumedBytes(reader.Consumed); _inputLength = chunkSize; _mode = chunkSize > 0 ? Mode.Data : Mode.Trailer; return; } chunkSize = CalculateChunkSize(ch1, chunkSize); ch1 = ch2; } // Set examined so that we capture the progress that way made examined = reader.Position; // At this point, 10 bytes have been consumed which is enough to parse the max value "7FFFFFFF\r\n". BadHttpRequestException.Throw(RequestRejectionReason.BadChunkSizeData); }
protected override void OnReadStarting() { // Note ContentLength or MaxRequestBodySize may be null if (_context.RequestHeaders.ContentLength > _context.MaxRequestBodySize) { BadHttpRequestException.Throw(RequestRejectionReason.RequestBodyTooLarge); } }
protected void AddAndCheckConsumedBytes(long consumedBytes) { _consumedBytes += consumedBytes; if (_consumedBytes > _context.MaxRequestBodySize) { BadHttpRequestException.Throw(RequestRejectionReason.RequestBodyTooLarge); } }
private static long ParseContentLength(string value) { if (!HeaderUtilities.TryParseNonNegativeInt64(value, out var parsed)) { BadHttpRequestException.Throw(RequestRejectionReason.InvalidContentLength, value); } return(parsed); }
private int ThrowBadRequestException(string message) { // returns int so can be used as item non-void function var ex = new BadHttpRequestException(message); _context.ReportCorruptedHttpRequest(ex); throw ex; }
public unsafe static string GetAsciiString(this MemoryPoolIterator start, MemoryPoolIterator end) { if (start.IsDefault || end.IsDefault) { return(null); } var length = start.GetLength(end); if (length == 0) { return(null); } var inputOffset = start.Index; var block = start.Block; var asciiString = new string('\0', length); fixed(char *outputStart = asciiString) { var output = outputStart; var remaining = length; var endBlock = end.Block; var endIndex = end.Index; var outputOffset = 0; while (true) { int following = (block != endBlock ? block.End : endIndex) - inputOffset; if (following > 0) { if (!AsciiUtilities.TryGetAsciiString(block.DataFixedPtr + inputOffset, output + outputOffset, following)) { throw BadHttpRequestException.GetException(RequestRejectionReason.NonAsciiOrNullCharactersInInputString); } outputOffset += following; remaining -= following; } if (remaining == 0) { break; } block = block.Next; inputOffset = block.Start; } } return(asciiString); }
private void ParseChunkedPrefix(ReadOnlySequence <byte> buffer, out SequencePosition consumed, out SequencePosition examined) { consumed = buffer.Start; examined = buffer.Start; var reader = new BufferReader(buffer); var ch1 = reader.Read(); var ch2 = reader.Read(); if (ch1 == -1 || ch2 == -1) { examined = reader.Position; return; } var chunkSize = CalculateChunkSize(ch1, 0); ch1 = ch2; while (reader.ConsumedBytes < MaxChunkPrefixBytes) { if (ch1 == ';') { consumed = reader.Position; examined = reader.Position; AddAndCheckConsumedBytes(reader.ConsumedBytes); _inputLength = chunkSize; _mode = Mode.Extension; return; } ch2 = reader.Read(); if (ch2 == -1) { examined = reader.Position; return; } if (ch1 == '\r' && ch2 == '\n') { consumed = reader.Position; examined = reader.Position; AddAndCheckConsumedBytes(reader.ConsumedBytes); _inputLength = chunkSize; _mode = chunkSize > 0 ? Mode.Data : Mode.Trailer; return; } chunkSize = CalculateChunkSize(ch1, chunkSize); ch1 = ch2; } // At this point, 10 bytes have been consumed which is enough to parse the max value "7FFFFFFF\r\n". BadHttpRequestException.Throw(RequestRejectionReason.BadChunkSizeData); }
internal void EnsureHostHeaderExists() { // https://tools.ietf.org/html/rfc7230#section-5.4 // A server MUST respond with a 400 (Bad Request) status code to any // HTTP/1.1 request message that lacks a Host header field and to any // request message that contains more than one Host header field or a // Host header field with an invalid field-value. var host = HttpRequestHeaders.HeaderHost; var hostText = host.ToString(); if (host.Count <= 0) { if (_httpVersion == Http.HttpVersion.Http10) { return; } BadHttpRequestException.Throw(RequestRejectionReason.MissingHostHeader); } else if (host.Count > 1) { BadHttpRequestException.Throw(RequestRejectionReason.MultipleHostHeaders); } else if (_requestTargetForm == HttpRequestTarget.AuthorityForm) { if (!host.Equals(RawTarget)) { BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText); } } else if (_requestTargetForm == HttpRequestTarget.AbsoluteForm) { // If the target URI includes an authority component, then a // client MUST send a field - value for Host that is identical to that // authority component, excluding any userinfo subcomponent and its "@" // delimiter. // System.Uri doesn't not tell us if the port was in the original string or not. // When IsDefaultPort = true, we will allow Host: with or without the default port if (host != _absoluteRequestTarget.Authority) { if (!_absoluteRequestTarget.IsDefaultPort || host != _absoluteRequestTarget.Authority + ":" + _absoluteRequestTarget.Port.ToString(CultureInfo.InvariantCulture)) { BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText); } } } if (!HttpUtilities.IsValidHostHeader(hostText)) { BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText); } }
protected void ThrowUnexpectedEndOfRequestContent() { // OnInputOrOutputCompleted() is an idempotent method that closes the connection. Sometimes // input completion is observed here before the Input.OnWriterCompleted() callback is fired, // so we call OnInputOrOutputCompleted() now to prevent a race in our tests where a 400 // response is written after observing the unexpected end of request content instead of just // closing the connection without a response as expected. _context.OnInputOrOutputCompleted(); BadHttpRequestException.Throw(RequestRejectionReason.UnexpectedEndOfRequestContent); }
private async Task ReadBody() { Exception error = null; try { while (true) { var memory = _bodyInputPipe.Writer.GetMemory(); var read = await AsyncIO.ReadAsync(memory); // End of body if (read == 0) { break; } // Read was not canceled because of incoming write or IO stopping if (read != -1) { _consumedBytes += read; _bodyInputPipe.Writer.Advance(read); } if (_consumedBytes > MaxRequestBodySize) { BadHttpRequestException.Throw(RequestRejectionReason.RequestBodyTooLarge); } var result = await _bodyInputPipe.Writer.FlushAsync(); if (result.IsCompleted || result.IsCanceled) { break; } } } catch (ConnectionResetException ex) { AbortIO(clientDisconnect: true); error = ex; } catch (Exception ex) { error = ex; Log.UnexpectedError(_logger, nameof(IISHttpContext), ex); } finally { _bodyInputPipe.Writer.Complete(error); } }
private static unsafe void GetHeaderName(Span <char> buffer, IntPtr state) { fixed(char *output = &MemoryMarshal.GetReference(buffer)) { // This version if AsciiUtilities returns null if there are any null (0 byte) characters // in the string if (!StringUtilities.TryGetAsciiString((byte *)state.ToPointer(), output, buffer.Length)) { BadHttpRequestException.Throw(RequestRejectionReason.InvalidCharactersInHeaderName); } } }
internal static BadHttpRequestException GetException(RequestRejectionReason reason, string detail) { BadHttpRequestException ex; switch (reason) { case RequestRejectionReason.TlsOverHttpError: ex = new BadHttpRequestException(CoreStrings.HttpParserTlsOverHttpError, StatusCodes.Status400BadRequest, reason); break; case RequestRejectionReason.InvalidRequestLine: ex = new BadHttpRequestException(CoreStrings.FormatBadRequest_InvalidRequestLine_Detail(detail), StatusCodes.Status400BadRequest, reason); break; case RequestRejectionReason.InvalidRequestTarget: ex = new BadHttpRequestException(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(detail), StatusCodes.Status400BadRequest, reason); break; case RequestRejectionReason.InvalidRequestHeader: ex = new BadHttpRequestException(CoreStrings.FormatBadRequest_InvalidRequestHeader_Detail(detail), StatusCodes.Status400BadRequest, reason); break; case RequestRejectionReason.InvalidContentLength: ex = new BadHttpRequestException(CoreStrings.FormatBadRequest_InvalidContentLength_Detail(detail), StatusCodes.Status400BadRequest, reason); break; case RequestRejectionReason.UnrecognizedHTTPVersion: ex = new BadHttpRequestException(CoreStrings.FormatBadRequest_UnrecognizedHTTPVersion(detail), StatusCodes.Status505HttpVersionNotsupported, reason); break; case RequestRejectionReason.FinalTransferCodingNotChunked: ex = new BadHttpRequestException(CoreStrings.FormatBadRequest_FinalTransferCodingNotChunked(detail), StatusCodes.Status400BadRequest, reason); break; case RequestRejectionReason.LengthRequiredHttp10: ex = new BadHttpRequestException(CoreStrings.FormatBadRequest_LengthRequiredHttp10(detail), StatusCodes.Status400BadRequest, reason); break; case RequestRejectionReason.InvalidHostHeader: ex = new BadHttpRequestException(CoreStrings.FormatBadRequest_InvalidHostHeader_Detail(detail), StatusCodes.Status400BadRequest, reason); break; case RequestRejectionReason.RequestBodyTooLarge: ex = new BadHttpRequestException(CoreStrings.FormatBadRequest_RequestBodyTooLarge(detail), StatusCodes.Status413PayloadTooLarge, reason); break; default: ex = new BadHttpRequestException(CoreStrings.BadRequest, StatusCodes.Status400BadRequest, reason); break; } return(ex); }
private void OnAuthorityFormTarget(HttpMethod method, Span <byte> target) { _requestTargetForm = HttpRequestTarget.AuthorityForm; // This is not complete validation. It is just a quick scan for invalid characters // but doesn't check that the target fully matches the URI spec. if (HttpCharacters.ContainsInvalidAuthorityChar(target)) { ThrowRequestTargetRejected(target); } // The authority-form of request-target is only used for CONNECT // requests (https://tools.ietf.org/html/rfc7231#section-4.3.6). if (method != HttpMethod.Connect) { BadHttpRequestException.Throw(RequestRejectionReason.ConnectMethodRequired); } // When making a CONNECT request to establish a tunnel through one or // more proxies, a client MUST send only the target URI's authority // component (excluding any userinfo and its "@" delimiter) as the // request-target.For example, // // CONNECT www.example.com:80 HTTP/1.1 // // Allowed characters in the 'host + port' section of authority. // See https://tools.ietf.org/html/rfc3986#section-3.2 var previousValue = _parsedRawTarget; if (ServerOptions.DisableStringReuse || previousValue == null || previousValue.Length != target.Length || !StringUtilities.BytesOrdinalEqualsStringAndAscii(previousValue, target)) { // The previous string does not match what the bytes would convert to, // so we will need to generate a new string. RawTarget = _parsedRawTarget = target.GetAsciiStringNonNullCharacters(); } else { // Reuse previous value RawTarget = _parsedRawTarget; } Path = string.Empty; QueryString = string.Empty; // Clear parsedData for path and queryString as we won't check it if we come via this path again, // an setting to null is fast as it doesn't need to use a GC write barrier. _parsedPath = _parsedQueryString = null; }
public async Task RejectsRequestWithContentLengthHeaderExceedingPerRequestLimit() { // 8 GiB var globalMaxRequestBodySize = 0x200000000; // 4 GiB var perRequestMaxRequestBodySize = 0x100000000; BadHttpRequestException requestRejectedEx = null; using (var server = new TestServer(async context => { var feature = context.Features.Get <IHttpMaxRequestBodySizeFeature>(); Assert.Equal(globalMaxRequestBodySize, feature.MaxRequestBodySize); // Disable the MaxRequestBodySize prior to calling Request.Body.ReadAsync(); feature.MaxRequestBodySize = perRequestMaxRequestBodySize; var buffer = new byte[1]; requestRejectedEx = await Assert.ThrowsAsync <BadHttpRequestException>( async() => await context.Request.Body.ReadAsync(buffer, 0, 1)); throw requestRejectedEx; }, new TestServiceContext(LoggerFactory) { ServerOptions = { Limits = { MaxRequestBodySize = globalMaxRequestBodySize } } })) { using (var connection = server.CreateConnection()) { await connection.Send( "POST / HTTP/1.1", "Host:", "Content-Length: " + (perRequestMaxRequestBodySize + 1), "", ""); await connection.ReceiveEnd( "HTTP/1.1 413 Payload Too Large", "Connection: close", $"Date: {server.Context.DateHeaderValue}", "Content-Length: 0", "", ""); } await server.StopAsync(); } Assert.NotNull(requestRejectedEx); Assert.Equal(CoreStrings.BadRequest_RequestBodyTooLarge, requestRejectedEx.Message); }
private unsafe void AppendUnknownHeaders(byte *pKeyBytes, int keyLength, string value) { string key = new string('\0', keyLength); fixed(char *keyBuffer = key) { if (!StringUtilities.TryGetAsciiString(pKeyBytes, keyBuffer, keyLength)) { BadHttpRequestException.Throw(RequestRejectionReason.InvalidCharactersInHeaderName); } } Unknown.TryGetValue(key, out var existing); Unknown[key] = AppendValue(existing, value); }
private void OnAsteriskFormTarget(HttpMethod method) { _requestTargetForm = HttpRequestTarget.AsteriskForm; // The asterisk-form of request-target is only used for a server-wide // OPTIONS request (https://tools.ietf.org/html/rfc7231#section-4.3.7). if (method != HttpMethod.Options) { BadHttpRequestException.Throw(RequestRejectionReason.OptionsMethodRequired); } RawTarget = Asterisk; Path = string.Empty; QueryString = string.Empty; }