コード例 #1
0
        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);
        }
コード例 #2
0
        // 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);
        }
コード例 #3
0
        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);
            }
        }
コード例 #4
0
        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);
        }
コード例 #5
0
        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);
        }
コード例 #6
0
        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;
        }
コード例 #7
0
        private Task HandleBadHttpRequestExceptionAsync(HttpContext httpContext, BadHttpRequestException e)
        {
            httpContext.Response.ContentType = "application/json";
            httpContext.Response.StatusCode  = (int)e.StatusCode;

            return(httpContext.Response.WriteAsync(e.Message));
        }
コード例 #8
0
        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);
            }
        }
コード例 #9
0
 protected override void OnReadStarting()
 {
     if (_contentLength > _context.MaxRequestBodySize)
     {
         BadHttpRequestException.Throw(RequestRejectionReason.RequestBodyTooLarge);
     }
 }
コード例 #10
0
        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);
            }
        }
コード例 #11
0
            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);
                }
            }
コード例 #12
0
        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);
        }
コード例 #13
0
            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
            }
コード例 #14
0
        public void RejectRequest(string message)
        {
            var ex = new BadHttpRequestException(message);

            SetBadRequestState(ex);
            throw ex;
        }
コード例 #15
0
        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);
        }
コード例 #16
0
 protected override void OnReadStarting()
 {
     // Note ContentLength or MaxRequestBodySize may be null
     if (_context.RequestHeaders.ContentLength > _context.MaxRequestBodySize)
     {
         BadHttpRequestException.Throw(RequestRejectionReason.RequestBodyTooLarge);
     }
 }
コード例 #17
0
        protected void AddAndCheckConsumedBytes(long consumedBytes)
        {
            _consumedBytes += consumedBytes;

            if (_consumedBytes > _context.MaxRequestBodySize)
            {
                BadHttpRequestException.Throw(RequestRejectionReason.RequestBodyTooLarge);
            }
        }
コード例 #18
0
        private static long ParseContentLength(string value)
        {
            if (!HeaderUtilities.TryParseNonNegativeInt64(value, out var parsed))
            {
                BadHttpRequestException.Throw(RequestRejectionReason.InvalidContentLength, value);
            }

            return(parsed);
        }
コード例 #19
0
        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;
        }
コード例 #20
0
        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);
        }
コード例 #21
0
            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);
            }
コード例 #22
0
        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);
            }
        }
コード例 #23
0
ファイル: Http1MessageBody.cs プロジェクト: FFx0001/HtcSharp
        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);
        }
コード例 #24
0
        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);
            }
        }
コード例 #25
0
 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);
         }
     }
 }
コード例 #26
0
    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);
    }
コード例 #27
0
        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;
        }
コード例 #28
0
        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);
        }
コード例 #29
0
        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);
        }
コード例 #30
0
        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;
        }