Check that MaxRequestBufferSize is greater than or equal to MaxRequestHeadersTotalSize (#1491).

This commit is contained in:
Cesar Blum Silveira 2017-03-21 19:25:56 -07:00 committed by GitHub
parent 6c131ea240
commit 72587baac3
3 changed files with 71 additions and 22 deletions

View File

@ -247,6 +247,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel
throw new InvalidOperationException( throw new InvalidOperationException(
$"Maximum request buffer size ({Options.Limits.MaxRequestBufferSize.Value}) must be greater than or equal to maximum request line size ({Options.Limits.MaxRequestLineSize})."); $"Maximum request buffer size ({Options.Limits.MaxRequestBufferSize.Value}) must be greater than or equal to maximum request line size ({Options.Limits.MaxRequestLineSize}).");
} }
if (Options.Limits.MaxRequestBufferSize.HasValue &&
Options.Limits.MaxRequestBufferSize < Options.Limits.MaxRequestHeadersTotalSize)
{
throw new InvalidOperationException(
$"Maximum request buffer size ({Options.Limits.MaxRequestBufferSize.Value}) must be greater than or equal to maximum request headers size ({Options.Limits.MaxRequestHeadersTotalSize}).");
}
} }
private void StartLocalhost(KestrelEngine engine, ServerAddress parsedAddress) private void StartLocalhost(KestrelEngine engine, ServerAddress parsedAddress)

View File

@ -6,9 +6,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Security;
using System.Net.Sockets; using System.Net.Sockets;
using System.Security.Authentication;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -24,13 +22,22 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
private const int _dataLength = 20 * 1024 * 1024; private const int _dataLength = 20 * 1024 * 1024;
private static readonly string[] _requestLines = new[]
{
"POST / HTTP/1.0\r\n",
$"Content-Length: {_dataLength}\r\n",
"\r\n"
};
public static IEnumerable<object[]> LargeUploadData public static IEnumerable<object[]> LargeUploadData
{ {
get get
{ {
var maxRequestBufferSizeValues = new Tuple<long?, bool>[] { var maxRequestBufferSizeValues = new Tuple<long?, bool>[] {
// Smallest buffer that can hold a POST request line to the root. // Smallest buffer that can hold a test request line without causing
Tuple.Create((long?)"POST / HTTP/1.1\r\n".Length, true), // the server to hang waiting for the end of the request line or
// a header line.
Tuple.Create((long?)(_requestLines.Max(line => line.Length)), true),
// Small buffer, but large enough to hold all request headers. // Small buffer, but large enough to hold all request headers.
Tuple.Create((long?)16 * 1024, true), Tuple.Create((long?)16 * 1024, true),
@ -186,6 +193,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
options.Limits.MaxRequestLineSize = (int)maxRequestBufferSize; options.Limits.MaxRequestLineSize = (int)maxRequestBufferSize;
} }
if (maxRequestBufferSize.HasValue &&
maxRequestBufferSize.Value < options.Limits.MaxRequestHeadersTotalSize)
{
options.Limits.MaxRequestHeadersTotalSize = (int)maxRequestBufferSize;
}
}) })
.UseContentRoot(Directory.GetCurrentDirectory()) .UseContentRoot(Directory.GetCurrentDirectory())
.Configure(app => app.Run(async context => .Configure(app => app.Run(async context =>
@ -246,9 +259,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize: 1024, leaveOpen: true)) using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize: 1024, leaveOpen: true))
{ {
await writer.WriteAsync("POST / HTTP/1.0\r\n"); foreach (var line in _requestLines)
await writer.WriteAsync($"Content-Length: {contentLength}\r\n"); {
await writer.WriteAsync("\r\n"); await writer.WriteAsync(line);
}
} }
} }
} }

View File

@ -24,25 +24,30 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
public void StartWithNonPositiveThreadCountThrows(int threadCount) public void StartWithNonPositiveThreadCountThrows(int threadCount)
{ {
var testLogger = new TestApplicationErrorLogger { ThrowOnCriticalErrors = false }; var testLogger = new TestApplicationErrorLogger { ThrowOnCriticalErrors = false };
var server = CreateServer(new KestrelServerOptions() { ThreadCount = threadCount }, testLogger);
var exception = Assert.Throws<ArgumentOutOfRangeException>(() => StartDummyApplication(server)); using (var server = CreateServer(new KestrelServerOptions() { ThreadCount = threadCount }, testLogger))
{
var exception = Assert.Throws<ArgumentOutOfRangeException>(() => StartDummyApplication(server));
Assert.Equal("threadCount", exception.ParamName); Assert.Equal("threadCount", exception.ParamName);
Assert.Equal(1, testLogger.CriticalErrorsLogged); Assert.Equal(1, testLogger.CriticalErrorsLogged);
}
} }
[Fact] [Fact]
public void StartWithInvalidAddressThrows() public void StartWithInvalidAddressThrows()
{ {
var testLogger = new TestApplicationErrorLogger { ThrowOnCriticalErrors = false }; var testLogger = new TestApplicationErrorLogger { ThrowOnCriticalErrors = false };
var server = CreateServer(new KestrelServerOptions(), testLogger);
server.Features.Get<IServerAddressesFeature>().Addresses.Add("http:/asdf");
var exception = Assert.Throws<FormatException>(() => StartDummyApplication(server)); using (var server = CreateServer(new KestrelServerOptions(), testLogger))
{
server.Features.Get<IServerAddressesFeature>().Addresses.Add("http:/asdf");
Assert.Contains("Invalid URL", exception.Message); var exception = Assert.Throws<FormatException>(() => StartDummyApplication(server));
Assert.Equal(1, testLogger.CriticalErrorsLogged);
Assert.Contains("Invalid URL", exception.Message);
Assert.Equal(1, testLogger.CriticalErrorsLogged);
}
} }
[Theory] [Theory]
@ -77,14 +82,37 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
options.Limits.MaxRequestBufferSize = maxRequestBufferSize; options.Limits.MaxRequestBufferSize = maxRequestBufferSize;
options.Limits.MaxRequestLineSize = maxRequestLineSize; options.Limits.MaxRequestLineSize = maxRequestLineSize;
var server = CreateServer(options, testLogger); using (var server = CreateServer(options, testLogger))
{
var exception = Assert.Throws<InvalidOperationException>(() => StartDummyApplication(server));
var exception = Assert.Throws<InvalidOperationException>(() => StartDummyApplication(server)); Assert.Equal(
$"Maximum request buffer size ({maxRequestBufferSize}) must be greater than or equal to maximum request line size ({maxRequestLineSize}).",
exception.Message);
Assert.Equal(1, testLogger.CriticalErrorsLogged);
}
}
Assert.Equal( [Theory]
$"Maximum request buffer size ({maxRequestBufferSize}) must be greater than or equal to maximum request line size ({maxRequestLineSize}).", [InlineData(1, 2)]
exception.Message); [InlineData(int.MaxValue - 1, int.MaxValue)]
Assert.Equal(1, testLogger.CriticalErrorsLogged); public void StartWithMaxRequestBufferSizeLessThanMaxRequestHeadersTotalSizeThrows(long maxRequestBufferSize, int maxRequestHeadersTotalSize)
{
var testLogger = new TestApplicationErrorLogger { ThrowOnCriticalErrors = false };
var options = new KestrelServerOptions();
options.Limits.MaxRequestBufferSize = maxRequestBufferSize;
options.Limits.MaxRequestLineSize = (int)maxRequestBufferSize;
options.Limits.MaxRequestHeadersTotalSize = maxRequestHeadersTotalSize;
using (var server = CreateServer(options, testLogger))
{
var exception = Assert.Throws<InvalidOperationException>(() => StartDummyApplication(server));
Assert.Equal(
$"Maximum request buffer size ({maxRequestBufferSize}) must be greater than or equal to maximum request headers size ({maxRequestHeadersTotalSize}).",
exception.Message);
Assert.Equal(1, testLogger.CriticalErrorsLogged);
}
} }
[Fact] [Fact]