diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/BadHttpRequestException.cs b/src/Microsoft.AspNetCore.Server.Kestrel/BadHttpRequestException.cs index 8e70e90c66..cb37af76c1 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/BadHttpRequestException.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/BadHttpRequestException.cs @@ -78,9 +78,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel case RequestRejectionReason.RequestTimeout: ex = new BadHttpRequestException("Request timed out.", 408); break; - case RequestRejectionReason.PayloadTooLarge: - ex = new BadHttpRequestException("Payload too large.", 413); - break; default: ex = new BadHttpRequestException("Bad request.", 400); break; diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.cs index 9966b60c9e..0b37975bc3 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.cs @@ -115,7 +115,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http private DateHeaderValueManager DateHeaderValueManager => ConnectionContext.ListenerContext.ServiceContext.DateHeaderValueManager; private ServerAddress ServerAddress => ConnectionContext.ListenerContext.ServerAddress; // Hold direct reference to ServerOptions since this is used very often in the request processing path - public KestrelServerOptions ServerOptions { get; } + private KestrelServerOptions ServerOptions { get; } private IPEndPoint LocalEndPoint => ConnectionContext.LocalEndPoint; private IPEndPoint RemoteEndPoint => ConnectionContext.RemoteEndPoint; protected string ConnectionId => ConnectionContext.ConnectionId; diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/MessageBody.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/MessageBody.cs index f4a260dcc6..50cb468741 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/MessageBody.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/MessageBody.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure; using Microsoft.Extensions.Internal; +using Microsoft.Extensions.Primitives; namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http { @@ -271,12 +272,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http try { var contentLength = FrameHeaders.ParseContentLength(unparsedContentLength); - - if (contentLength > context.ServerOptions.Limits.MaxRequestBodySize) - { - context.RejectRequest(RequestRejectionReason.PayloadTooLarge); - } - return new ForContentLength(keepAlive, contentLength, context); } catch (InvalidOperationException) @@ -286,7 +281,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http } // Avoid slowing down most common case - if (!ReferenceEquals(context.Method, HttpMethods.Get)) + 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. @@ -399,7 +394,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http private readonly SocketInput _input; private readonly FrameRequestHeaders _requestHeaders; - private long _inputBytesRead; private int _inputLength; private Mode _mode = Mode.Prefix; @@ -420,12 +414,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http protected override void OnConsumedBytes(int count) { _inputLength -= count; - _inputBytesRead += count; - - if (_inputBytesRead > _context.ServerOptions.Limits.MaxRequestBodySize) - { - _context.RejectRequest(RequestRejectionReason.PayloadTooLarge); - } } private async Task> PeekStateMachineAsync() diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/RequestRejectionReason.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/RequestRejectionReason.cs index f774e5d6a3..0c05a6b8ea 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/RequestRejectionReason.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/RequestRejectionReason.cs @@ -30,6 +30,5 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http FinalTransferCodingNotChunked, LengthRequired, LengthRequiredHttp10, - PayloadTooLarge } } diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServerLimits.cs b/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServerLimits.cs index b85e3875d8..ac8a047542 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServerLimits.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/KestrelServerLimits.cs @@ -23,10 +23,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel // Matches the default LimitRequestFields in Apache httpd. private int _maxRequestHeaderCount = 100; - // Matches default HttpRuntimeSection.MaxRequestLength. - // https://msdn.microsoft.com/en-us/library/system.web.configuration.httpruntimesection.maxrequestlength%28v=vs.100%29.aspx - private long _maxRequestBodySize = 4 * 1024 * 1024; - // Matches the default http.sys connectionTimeout. private TimeSpan _keepAliveTimeout = TimeSpan.FromMinutes(2); @@ -148,28 +144,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel } } - /// - /// Gets or sets the maximum request body size, in bytes. - /// - /// - /// Defaults to 4MB. - /// - public long MaxRequestBodySize - { - get - { - return _maxRequestBodySize; - } - set - { - if (value <= 0) - { - throw new ArgumentOutOfRangeException(nameof(value), "Value must a positive integer."); - } - _maxRequestBodySize = value; - } - } - /// /// Gets or sets the keep-alive timeout. /// diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/KeepAliveTimeoutTests.cs b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/KeepAliveTimeoutTests.cs index 77adb2b983..ee4a72cc57 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/KeepAliveTimeoutTests.cs +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/KeepAliveTimeoutTests.cs @@ -178,10 +178,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests AddServerHeader = false, Limits = { - KeepAliveTimeout = KeepAliveTimeout, - // Prevent request rejection if ConnectionNotTimedOutWhileRequestBeingSent - // sends more bytes than the default body size limit. - MaxRequestBodySize = long.MaxValue + KeepAliveTimeout = KeepAliveTimeout } } }); diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/MaxRequestBodySizeTests.cs b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/MaxRequestBodySizeTests.cs deleted file mode 100644 index c54c9b2ad5..0000000000 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/MaxRequestBodySizeTests.cs +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Text; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Testing; -using Xunit; - -namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests -{ - public class MaxRequestBodySizeTests - { - private const int MaxRequestBodySize = 128; - - [Theory] - [InlineData(MaxRequestBodySize - 1, 0)] - [InlineData(MaxRequestBodySize, 0)] - [InlineData(MaxRequestBodySize - 1, 1)] - [InlineData(MaxRequestBodySize, 1)] - [InlineData(MaxRequestBodySize - 1, 2)] - [InlineData(MaxRequestBodySize, 2)] - public async Task ServerAcceptsRequestBodyWithinLimit(int requestBodySize, int chunks) - { - using (var server = CreateServer(MaxRequestBodySize, async httpContext => await httpContext.Response.WriteAsync("hello, world"))) - { - using (var connection = new TestConnection(server.Port)) - { - await connection.SendAll(BuildRequest(connection, requestBodySize, chunks)); - - await connection.Receive( - "HTTP/1.1 200 OK", - $"Date: {server.Context.DateHeaderValue}", - "Transfer-Encoding: chunked", - "", - "c", - "hello, world", - "0", - "", - ""); - } - } - } - - [Theory] - [InlineData(MaxRequestBodySize + 1, 0)] - [InlineData(MaxRequestBodySize + 1, 1)] - [InlineData(MaxRequestBodySize + 1, 2)] - public async Task ServerRejectsRequestBodyExceedingLimit(int requestBodySize, int chunks) - { - using (var server = CreateServer(MaxRequestBodySize, async httpContext => - { - var received = 0; - while (received < requestBodySize) - { - received += await httpContext.Request.Body.ReadAsync(new byte[1024], 0, 1024); - } - - // Should never get here - await httpContext.Response.WriteAsync("hello, world"); - })) - { - using (var connection = new TestConnection(server.Port)) - { - await connection.SendAll(BuildRequest(connection, requestBodySize, chunks)); - - await connection.ReceiveForcedEnd( - "HTTP/1.1 413 Payload Too Large", - "Connection: close", - $"Date: {server.Context.DateHeaderValue}", - "Content-Length: 0", - "", - ""); - } - } - } - - [Fact] - public async Task MaxRequestBodySizeNotEnforcedOnUpgradedConnection() - { - var sendBytes = MaxRequestBodySize + 1; - - using (var server = CreateServer(MaxRequestBodySize, async httpContext => - { - var stream = await httpContext.Features.Get().UpgradeAsync(); - - var received = 0; - while (received < sendBytes) - { - received += await stream.ReadAsync(new byte[1024], 0, 1024); - } - - var response = Encoding.ASCII.GetBytes($"{received}"); - await stream.WriteAsync(response, 0, response.Length); - })) - { - using (var connection = new TestConnection(server.Port)) - { - await connection.Send( - "GET / HTTP/1.1", - "Connection: upgrade", - "", - new string('a', sendBytes)); - - await connection.Receive( - "HTTP/1.1 101 Switching Protocols", - "Connection: Upgrade", - $"Date: {server.Context.DateHeaderValue}", - "", - $"{sendBytes}"); - } - } - } - - private string BuildRequest(TestConnection connection, int requestBodySize, int chunks) - { - var request = new StringBuilder(); - - request.Append("POST / HTTP/1.1\r\n"); - - if (chunks == 0) - { - request.Append($"Content-Length: {requestBodySize}\r\n\r\n"); - request.Append(new string('a', requestBodySize)); - } - else - { - request.Append("Transfer-Encoding: chunked\r\n\r\n"); - - var bytesSent = 0; - while (bytesSent < requestBodySize) - { - var chunkSize = Math.Min(requestBodySize / chunks, requestBodySize - bytesSent); - - request.Append($"{chunkSize:X}\r\n"); - request.Append(new string('a', chunkSize)); - request.Append("\r\n"); - - bytesSent += chunkSize; - } - - // Make sure we sent the right amount of data - Assert.Equal(requestBodySize, bytesSent); - - request.Append("0\r\n\r\n"); - } - - return request.ToString(); - } - - private TestServer CreateServer(int maxRequestBodySize, RequestDelegate app) - { - return new TestServer(app, new TestServiceContext - { - ServerOptions = new KestrelServerOptions - { - AddServerHeader = false, - Limits = - { - MaxRequestBodySize = maxRequestBodySize - } - } - }); - } - } -} diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/MaxRequestBufferSizeTests.cs b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/MaxRequestBufferSizeTests.cs index 4a19b8cd10..d78f60a7cd 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/MaxRequestBufferSizeTests.cs +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/MaxRequestBufferSizeTests.cs @@ -169,7 +169,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests .UseKestrel(options => { options.Limits.MaxRequestBufferSize = maxRequestBufferSize; - options.Limits.MaxRequestBodySize = _dataLength; options.UseHttps(@"TestResources/testCert.pfx", "testPassword"); if (maxRequestBufferSize.HasValue && diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs index 9434429926..645f7c5205 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs @@ -43,10 +43,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests Assert.True(bufferLength % 256 == 0, $"{nameof(bufferLength)} must be evenly divisible by 256"); var builder = new WebHostBuilder() - .UseKestrel(options => - { - options.Limits.MaxRequestBodySize = contentLength; - }) + .UseKestrel() .UseUrls("http://127.0.0.1:0/") .Configure(app => { diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/KestrelServerLimitsTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/KestrelServerLimitsTests.cs index ae17670ba3..0b9363b58f 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/KestrelServerLimitsTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/KestrelServerLimitsTests.cs @@ -149,34 +149,6 @@ namespace Microsoft.AspNetCore.Server.KestrelTests Assert.Equal(value, o.MaxRequestHeaderCount); } - [Fact] - public void MaxRequestBodySizeDefault() - { - Assert.Equal(4 * 1024 * 1024, (new KestrelServerLimits()).MaxRequestBodySize); - } - - [Theory] - [InlineData(long.MinValue)] - [InlineData(-1)] - [InlineData(0)] - public void MaxRequestBodySizeInvalid(long value) - { - Assert.Throws(() => - { - (new KestrelServerLimits()).MaxRequestBodySize = value; - }); - } - - [Theory] - [InlineData(1)] - [InlineData(long.MaxValue)] - public void MaxRequestBodySizeValid(long value) - { - var o = new KestrelServerLimits(); - o.MaxRequestBodySize = value; - Assert.Equal(value, o.MaxRequestBodySize); - } - [Fact] public void KeepAliveTimeoutDefault() {