Add header limit options (#475).
This commit is contained in:
parent
2f9bf9bb87
commit
08f98f4790
|
|
@ -49,8 +49,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
||||||
case RequestRejectionReason.WhitespaceIsNotAllowedInHeaderName:
|
case RequestRejectionReason.WhitespaceIsNotAllowedInHeaderName:
|
||||||
ex = new BadHttpRequestException("Whitespace is not allowed in header name.");
|
ex = new BadHttpRequestException("Whitespace is not allowed in header name.");
|
||||||
break;
|
break;
|
||||||
case RequestRejectionReason.HeaderLineMustEndInCRLFOnlyCRFound:
|
case RequestRejectionReason.HeaderValueMustNotContainCR:
|
||||||
ex = new BadHttpRequestException("Header line must end in CRLF; only CR found.");
|
ex = new BadHttpRequestException("Header value must not contain CR characters.");
|
||||||
break;
|
break;
|
||||||
case RequestRejectionReason.HeaderValueLineFoldingNotSupported:
|
case RequestRejectionReason.HeaderValueLineFoldingNotSupported:
|
||||||
ex = new BadHttpRequestException("Header value line folding not supported.");
|
ex = new BadHttpRequestException("Header value line folding not supported.");
|
||||||
|
|
@ -91,6 +91,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
||||||
case RequestRejectionReason.MissingCrAfterVersion:
|
case RequestRejectionReason.MissingCrAfterVersion:
|
||||||
ex = new BadHttpRequestException("Missing CR in request line.");
|
ex = new BadHttpRequestException("Missing CR in request line.");
|
||||||
break;
|
break;
|
||||||
|
case RequestRejectionReason.HeadersExceedMaxTotalSize:
|
||||||
|
ex = new BadHttpRequestException("Request headers too long.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.MissingCRInHeaderLine:
|
||||||
|
ex = new BadHttpRequestException("No CR character found in header line.");
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.TooManyHeaders:
|
||||||
|
ex = new BadHttpRequestException("Request contains too many headers.");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ex = new BadHttpRequestException("Bad request.");
|
ex = new BadHttpRequestException("Bad request.");
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
|
|
||||||
private readonly string _pathBase;
|
private readonly string _pathBase;
|
||||||
|
|
||||||
|
private int _remainingRequestHeadersBytesAllowed;
|
||||||
|
private int _requestHeadersParsed;
|
||||||
|
|
||||||
public Frame(ConnectionContext context)
|
public Frame(ConnectionContext context)
|
||||||
: base(context)
|
: base(context)
|
||||||
{
|
{
|
||||||
|
|
@ -305,6 +308,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
|
|
||||||
_manuallySetRequestAbortToken = null;
|
_manuallySetRequestAbortToken = null;
|
||||||
_abortedCts = null;
|
_abortedCts = null;
|
||||||
|
|
||||||
|
_remainingRequestHeadersBytesAllowed = ServerOptions.Limits.MaxRequestHeadersTotalSize;
|
||||||
|
_requestHeadersParsed = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1083,63 +1089,63 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
RejectRequest(RequestRejectionReason.HeaderLineMustNotStartWithWhitespace);
|
RejectRequest(RequestRejectionReason.HeaderLineMustNotStartWithWhitespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
var beginName = scan;
|
// If we've parsed the max allowed numbers of headers and we're starting a new
|
||||||
if (scan.Seek(ref _vectorColons, ref _vectorCRs) == -1)
|
// one, we've gone over the limit.
|
||||||
|
if (_requestHeadersParsed == ServerOptions.Limits.MaxRequestHeaderCount)
|
||||||
{
|
{
|
||||||
return false;
|
RejectRequest(RequestRejectionReason.TooManyHeaders);
|
||||||
}
|
|
||||||
var endName = scan;
|
|
||||||
|
|
||||||
ch = scan.Take();
|
|
||||||
if (ch != ':')
|
|
||||||
{
|
|
||||||
RejectRequest(RequestRejectionReason.NoColonCharacterFoundInHeaderLine);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var validateName = beginName;
|
var end = scan;
|
||||||
if (validateName.Seek(ref _vectorSpaces, ref _vectorTabs, ref _vectorColons) != ':')
|
int bytesScanned;
|
||||||
|
if (end.Seek(ref _vectorLFs, out bytesScanned, _remainingRequestHeadersBytesAllowed) == -1)
|
||||||
{
|
{
|
||||||
RejectRequest(RequestRejectionReason.WhitespaceIsNotAllowedInHeaderName);
|
if (bytesScanned >= _remainingRequestHeadersBytesAllowed)
|
||||||
}
|
{
|
||||||
|
RejectRequest(RequestRejectionReason.HeadersExceedMaxTotalSize);
|
||||||
var beginValue = scan;
|
}
|
||||||
ch = scan.Peek();
|
else
|
||||||
|
|
||||||
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scan = beginValue;
|
var beginName = scan;
|
||||||
if (scan.Seek(ref _vectorCRs) == -1)
|
if (scan.Seek(ref _vectorColons, ref end) == -1)
|
||||||
{
|
{
|
||||||
// no "\r" in sight, burn used bytes and go back to await more data
|
RejectRequest(RequestRejectionReason.NoColonCharacterFoundInHeaderLine);
|
||||||
return false;
|
}
|
||||||
|
var endName = scan;
|
||||||
|
|
||||||
|
scan.Take();
|
||||||
|
|
||||||
|
var validateName = beginName;
|
||||||
|
if (validateName.Seek(ref _vectorSpaces, ref _vectorTabs, ref endName) != -1)
|
||||||
|
{
|
||||||
|
RejectRequest(RequestRejectionReason.WhitespaceIsNotAllowedInHeaderName);
|
||||||
|
}
|
||||||
|
|
||||||
|
var beginValue = scan;
|
||||||
|
ch = scan.Take();
|
||||||
|
|
||||||
|
while (ch == ' ' || ch == '\t')
|
||||||
|
{
|
||||||
|
beginValue = scan;
|
||||||
|
ch = scan.Take();
|
||||||
|
}
|
||||||
|
|
||||||
|
scan = beginValue;
|
||||||
|
if (scan.Seek(ref _vectorCRs, ref end) == -1)
|
||||||
|
{
|
||||||
|
RejectRequest(RequestRejectionReason.MissingCRInHeaderLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
scan.Take(); // we know this is '\r'
|
scan.Take(); // we know this is '\r'
|
||||||
ch = scan.Take(); // expecting '\n'
|
ch = scan.Take(); // expecting '\n'
|
||||||
|
|
||||||
if (ch == -1)
|
if (ch != '\n')
|
||||||
{
|
{
|
||||||
return false;
|
RejectRequest(RequestRejectionReason.HeaderValueMustNotContainCR);
|
||||||
}
|
|
||||||
else if (ch != '\n')
|
|
||||||
{
|
|
||||||
RejectRequest(RequestRejectionReason.HeaderLineMustEndInCRLFOnlyCRFound);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var next = scan.Peek();
|
var next = scan.Peek();
|
||||||
|
|
@ -1195,6 +1201,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
|
|
||||||
consumed = scan;
|
consumed = scan;
|
||||||
requestHeaders.Append(name.Array, name.Offset, name.Count, value);
|
requestHeaders.Append(name.Array, name.Offset, name.Count, value);
|
||||||
|
|
||||||
|
_remainingRequestHeadersBytesAllowed -= bytesScanned;
|
||||||
|
_requestHeadersParsed++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
HeaderLineMustNotStartWithWhitespace,
|
HeaderLineMustNotStartWithWhitespace,
|
||||||
NoColonCharacterFoundInHeaderLine,
|
NoColonCharacterFoundInHeaderLine,
|
||||||
WhitespaceIsNotAllowedInHeaderName,
|
WhitespaceIsNotAllowedInHeaderName,
|
||||||
HeaderLineMustEndInCRLFOnlyCRFound,
|
HeaderValueMustNotContainCR,
|
||||||
HeaderValueLineFoldingNotSupported,
|
HeaderValueLineFoldingNotSupported,
|
||||||
MalformedRequestLineStatus,
|
MalformedRequestLineStatus,
|
||||||
MalformedRequestInvalidHeaders,
|
MalformedRequestInvalidHeaders,
|
||||||
|
|
@ -31,5 +31,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
MissingSpaceAfterMethod,
|
MissingSpaceAfterMethod,
|
||||||
MissingSpaceAfterTarget,
|
MissingSpaceAfterTarget,
|
||||||
MissingCrAfterVersion,
|
MissingCrAfterVersion,
|
||||||
|
HeadersExceedMaxTotalSize,
|
||||||
|
MissingCRInHeaderLine,
|
||||||
|
TooManyHeaders,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
||||||
// Matches the default large_client_header_buffers in nginx.
|
// Matches the default large_client_header_buffers in nginx.
|
||||||
private int _maxRequestLineSize = 8 * 1024;
|
private int _maxRequestLineSize = 8 * 1024;
|
||||||
|
|
||||||
|
// Matches the default large_client_header_buffers in nginx.
|
||||||
|
private int _maxRequestHeadersTotalSize = 32 * 1024;
|
||||||
|
|
||||||
|
// Matches the default LimitRequestFields in Apache httpd.
|
||||||
|
private int _maxRequestHeaderCount = 100;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the maximum size of the request buffer.
|
/// Gets or sets the maximum size of the request buffer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -58,5 +64,49 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
||||||
_maxRequestLineSize = value;
|
_maxRequestLineSize = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the maximum allowed size for the HTTP request headers.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Defaults to 32,768 bytes (32 KB).
|
||||||
|
/// </remarks>
|
||||||
|
public int MaxRequestHeadersTotalSize
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _maxRequestHeadersTotalSize;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value <= 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(value), "Value must a positive integer.");
|
||||||
|
}
|
||||||
|
_maxRequestHeadersTotalSize = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the maximum allowed number of headers per HTTP request.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Defaults to 100.
|
||||||
|
/// </remarks>
|
||||||
|
public int MaxRequestHeaderCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _maxRequestHeaderCount;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value <= 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(value), "Value must a positive integer.");
|
||||||
|
}
|
||||||
|
_maxRequestHeaderCount = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
// 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.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Testing;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
|
{
|
||||||
|
public class RequestHeaderLimitsTests
|
||||||
|
{
|
||||||
|
[Theory]
|
||||||
|
[InlineData(0, 1)]
|
||||||
|
[InlineData(0, 1337)]
|
||||||
|
[InlineData(1, 0)]
|
||||||
|
[InlineData(1, 1)]
|
||||||
|
[InlineData(1, 1337)]
|
||||||
|
[InlineData(5, 0)]
|
||||||
|
[InlineData(5, 1)]
|
||||||
|
[InlineData(5, 1337)]
|
||||||
|
public async Task ServerAcceptsRequestWithHeaderTotalSizeWithinLimit(int headerCount, int extraLimit)
|
||||||
|
{
|
||||||
|
var headers = MakeHeaders(headerCount);
|
||||||
|
|
||||||
|
using (var host = BuildWebHost(options =>
|
||||||
|
{
|
||||||
|
options.Limits.MaxRequestHeadersTotalSize = headers.Length + extraLimit;
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
host.Start();
|
||||||
|
|
||||||
|
using (var connection = new TestConnection(host.GetPort()))
|
||||||
|
{
|
||||||
|
await connection.SendEnd($"GET / HTTP/1.1\r\n{headers}\r\n");
|
||||||
|
await connection.Receive($"HTTP/1.1 200 OK\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(0, 1)]
|
||||||
|
[InlineData(0, 1337)]
|
||||||
|
[InlineData(1, 1)]
|
||||||
|
[InlineData(1, 2)]
|
||||||
|
[InlineData(1, 1337)]
|
||||||
|
[InlineData(5, 5)]
|
||||||
|
[InlineData(5, 6)]
|
||||||
|
[InlineData(5, 1337)]
|
||||||
|
public async Task ServerAcceptsRequestWithHeaderCountWithinLimit(int headerCount, int maxHeaderCount)
|
||||||
|
{
|
||||||
|
var headers = MakeHeaders(headerCount);
|
||||||
|
|
||||||
|
using (var host = BuildWebHost(options =>
|
||||||
|
{
|
||||||
|
options.Limits.MaxRequestHeaderCount = maxHeaderCount;
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
host.Start();
|
||||||
|
|
||||||
|
using (var connection = new TestConnection(host.GetPort()))
|
||||||
|
{
|
||||||
|
await connection.SendEnd($"GET / HTTP/1.1\r\n{headers}\r\n");
|
||||||
|
await connection.Receive($"HTTP/1.1 200 OK\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(1)]
|
||||||
|
[InlineData(5)]
|
||||||
|
public async Task ServerRejectsRequestWithHeaderTotalSizeOverLimit(int headerCount)
|
||||||
|
{
|
||||||
|
var headers = MakeHeaders(headerCount);
|
||||||
|
|
||||||
|
using (var host = BuildWebHost(options =>
|
||||||
|
{
|
||||||
|
options.Limits.MaxRequestHeadersTotalSize = headers.Length - 1;
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
host.Start();
|
||||||
|
|
||||||
|
using (var connection = new TestConnection(host.GetPort()))
|
||||||
|
{
|
||||||
|
await connection.SendAllTryEnd($"GET / HTTP/1.1\r\n{headers}\r\n");
|
||||||
|
await connection.Receive($"HTTP/1.1 400 Bad Request\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(2, 1)]
|
||||||
|
[InlineData(5, 1)]
|
||||||
|
[InlineData(5, 4)]
|
||||||
|
public async Task ServerRejectsRequestWithHeaderCountOverLimit(int headerCount, int maxHeaderCount)
|
||||||
|
{
|
||||||
|
var headers = MakeHeaders(headerCount);
|
||||||
|
|
||||||
|
using (var host = BuildWebHost(options =>
|
||||||
|
{
|
||||||
|
options.Limits.MaxRequestHeaderCount = maxHeaderCount;
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
host.Start();
|
||||||
|
|
||||||
|
using (var connection = new TestConnection(host.GetPort()))
|
||||||
|
{
|
||||||
|
await connection.SendAllTryEnd($"GET / HTTP/1.1\r\n{headers}\r\n");
|
||||||
|
await connection.Receive($"HTTP/1.1 400 Bad Request\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string MakeHeaders(int count)
|
||||||
|
{
|
||||||
|
return string.Join("", Enumerable
|
||||||
|
.Range(0, count)
|
||||||
|
.Select(i => $"Header-{i}: value{i}\r\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IWebHost BuildWebHost(Action<KestrelServerOptions> options)
|
||||||
|
{
|
||||||
|
var host = new WebHostBuilder()
|
||||||
|
.UseKestrel(options)
|
||||||
|
.UseUrls("http://127.0.0.1:0/")
|
||||||
|
.Configure(app => app.Run(async context =>
|
||||||
|
{
|
||||||
|
await context.Response.WriteAsync("hello, world");
|
||||||
|
}))
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -255,6 +255,89 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(ConnectionFilterData))]
|
||||||
|
public async Task TrailingHeadersCountTowardsHeadersTotalSizeLimit(TestServiceContext testContext)
|
||||||
|
{
|
||||||
|
const string transferEncodingHeaderLine = "Transfer-Encoding: chunked";
|
||||||
|
const string headerLine = "Header: value";
|
||||||
|
const string trailingHeaderLine = "Trailing-Header: trailing-value";
|
||||||
|
|
||||||
|
testContext.ServerOptions.Limits.MaxRequestHeadersTotalSize =
|
||||||
|
transferEncodingHeaderLine.Length + 2 +
|
||||||
|
headerLine.Length + 2 +
|
||||||
|
trailingHeaderLine.Length + 1;
|
||||||
|
|
||||||
|
using (var server = new TestServer(async context =>
|
||||||
|
{
|
||||||
|
var buffer = new byte[128];
|
||||||
|
while (await context.Request.Body.ReadAsync(buffer, 0, buffer.Length) != 0) ; // read to end
|
||||||
|
}, testContext))
|
||||||
|
{
|
||||||
|
using (var connection = server.CreateConnection())
|
||||||
|
{
|
||||||
|
await connection.SendAllTryEnd(
|
||||||
|
"POST / HTTP/1.1",
|
||||||
|
$"{transferEncodingHeaderLine}",
|
||||||
|
$"{headerLine}",
|
||||||
|
"",
|
||||||
|
"2",
|
||||||
|
"42",
|
||||||
|
"0",
|
||||||
|
$"{trailingHeaderLine}",
|
||||||
|
"",
|
||||||
|
"");
|
||||||
|
await connection.ReceiveForcedEnd(
|
||||||
|
"HTTP/1.1 400 Bad Request",
|
||||||
|
"Connection: close",
|
||||||
|
$"Date: {testContext.DateHeaderValue}",
|
||||||
|
"Content-Length: 0",
|
||||||
|
"",
|
||||||
|
"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(ConnectionFilterData))]
|
||||||
|
public async Task TrailingHeadersCountTowardsHeaderCountLimit(TestServiceContext testContext)
|
||||||
|
{
|
||||||
|
const string transferEncodingHeaderLine = "Transfer-Encoding: chunked";
|
||||||
|
const string headerLine = "Header: value";
|
||||||
|
const string trailingHeaderLine = "Trailing-Header: trailing-value";
|
||||||
|
|
||||||
|
testContext.ServerOptions.Limits.MaxRequestHeaderCount = 2;
|
||||||
|
|
||||||
|
using (var server = new TestServer(async context =>
|
||||||
|
{
|
||||||
|
var buffer = new byte[128];
|
||||||
|
while (await context.Request.Body.ReadAsync(buffer, 0, buffer.Length) != 0) ; // read to end
|
||||||
|
}, testContext))
|
||||||
|
{
|
||||||
|
using (var connection = server.CreateConnection())
|
||||||
|
{
|
||||||
|
await connection.SendAllTryEnd(
|
||||||
|
"POST / HTTP/1.1",
|
||||||
|
$"{transferEncodingHeaderLine}",
|
||||||
|
$"{headerLine}",
|
||||||
|
"",
|
||||||
|
"2",
|
||||||
|
"42",
|
||||||
|
"0",
|
||||||
|
$"{trailingHeaderLine}",
|
||||||
|
"",
|
||||||
|
"");
|
||||||
|
await connection.ReceiveForcedEnd(
|
||||||
|
"HTTP/1.1 400 Bad Request",
|
||||||
|
"Connection: close",
|
||||||
|
$"Date: {testContext.DateHeaderValue}",
|
||||||
|
"Content-Length: 0",
|
||||||
|
"",
|
||||||
|
"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(ConnectionFilterData))]
|
[MemberData(nameof(ConnectionFilterData))]
|
||||||
public async Task ExtensionsAreIgnored(TestServiceContext testContext)
|
public async Task ExtensionsAreIgnored(TestServiceContext testContext)
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,11 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
var connectionContext = new ConnectionContext()
|
var connectionContext = new ConnectionContext()
|
||||||
{
|
{
|
||||||
DateHeaderValueManager = new DateHeaderValueManager(),
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
ServerAddress = ServerAddress.FromUrl("http://localhost:5000")
|
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
||||||
|
ServerOptions = new KestrelServerOptions(),
|
||||||
};
|
};
|
||||||
var frame = new Frame<object>(application: null, context: connectionContext);
|
var frame = new Frame<object>(application: null, context: connectionContext);
|
||||||
|
frame.Reset();
|
||||||
frame.InitializeHeaders();
|
frame.InitializeHeaders();
|
||||||
|
|
||||||
var headerArray = Encoding.ASCII.GetBytes("Header:value\r\n\r\n");
|
var headerArray = Encoding.ASCII.GetBytes("Header:value\r\n\r\n");
|
||||||
|
|
@ -68,9 +70,11 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
var connectionContext = new ConnectionContext()
|
var connectionContext = new ConnectionContext()
|
||||||
{
|
{
|
||||||
DateHeaderValueManager = new DateHeaderValueManager(),
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
ServerAddress = ServerAddress.FromUrl("http://localhost:5000")
|
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
||||||
|
ServerOptions = new KestrelServerOptions(),
|
||||||
};
|
};
|
||||||
var frame = new Frame<object>(application: null, context: connectionContext);
|
var frame = new Frame<object>(application: null, context: connectionContext);
|
||||||
|
frame.Reset();
|
||||||
frame.InitializeHeaders();
|
frame.InitializeHeaders();
|
||||||
|
|
||||||
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
||||||
|
|
@ -109,8 +113,10 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
{
|
{
|
||||||
DateHeaderValueManager = new DateHeaderValueManager(),
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
||||||
|
ServerOptions = new KestrelServerOptions(),
|
||||||
};
|
};
|
||||||
var frame = new Frame<object>(application: null, context: connectionContext);
|
var frame = new Frame<object>(application: null, context: connectionContext);
|
||||||
|
frame.Reset();
|
||||||
frame.InitializeHeaders();
|
frame.InitializeHeaders();
|
||||||
|
|
||||||
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
||||||
|
|
@ -148,8 +154,10 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
{
|
{
|
||||||
DateHeaderValueManager = new DateHeaderValueManager(),
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
||||||
|
ServerOptions = new KestrelServerOptions(),
|
||||||
};
|
};
|
||||||
var frame = new Frame<object>(application: null, context: connectionContext);
|
var frame = new Frame<object>(application: null, context: connectionContext);
|
||||||
|
frame.Reset();
|
||||||
frame.InitializeHeaders();
|
frame.InitializeHeaders();
|
||||||
|
|
||||||
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
||||||
|
|
@ -187,23 +195,23 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
{
|
{
|
||||||
DateHeaderValueManager = new DateHeaderValueManager(),
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
||||||
|
ServerOptions = new KestrelServerOptions(),
|
||||||
Log = trace
|
Log = trace
|
||||||
};
|
};
|
||||||
var frame = new Frame<object>(application: null, context: connectionContext);
|
var frame = new Frame<object>(application: null, context: connectionContext);
|
||||||
|
frame.Reset();
|
||||||
frame.InitializeHeaders();
|
frame.InitializeHeaders();
|
||||||
|
|
||||||
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
||||||
socketInput.IncomingData(headerArray, 0, headerArray.Length);
|
socketInput.IncomingData(headerArray, 0, headerArray.Length);
|
||||||
|
|
||||||
Assert.Throws<BadHttpRequestException>(() => frame.TakeMessageHeaders(socketInput, (FrameRequestHeaders)frame.RequestHeaders));
|
var exception = Assert.Throws<BadHttpRequestException>(() => frame.TakeMessageHeaders(socketInput, (FrameRequestHeaders)frame.RequestHeaders));
|
||||||
|
Assert.Equal("Header value line folding not supported.", exception.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Fact]
|
||||||
[InlineData("Header-1: value1\r\r\n")]
|
public void ThrowsOnHeaderValueWithLineFolding_CharacterNotAvailableOnFirstAttempt()
|
||||||
[InlineData("Header-1: value1\rHeader-2: value2\r\n\r\n")]
|
|
||||||
[InlineData("Header-1: value1\r\nHeader-2: value2\r\r\n")]
|
|
||||||
public void ThrowsOnHeaderLineNotEndingInCRLF(string rawHeaders)
|
|
||||||
{
|
{
|
||||||
var trace = new KestrelTrace(new TestKestrelTrace());
|
var trace = new KestrelTrace(new TestKestrelTrace());
|
||||||
var ltp = new LoggingThreadPool(trace);
|
var ltp = new LoggingThreadPool(trace);
|
||||||
|
|
@ -214,15 +222,54 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
{
|
{
|
||||||
DateHeaderValueManager = new DateHeaderValueManager(),
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
||||||
|
ServerOptions = new KestrelServerOptions(),
|
||||||
Log = trace
|
Log = trace
|
||||||
};
|
};
|
||||||
var frame = new Frame<object>(application: null, context: connectionContext);
|
var frame = new Frame<object>(application: null, context: connectionContext);
|
||||||
|
frame.Reset();
|
||||||
|
frame.InitializeHeaders();
|
||||||
|
|
||||||
|
var headerArray = Encoding.ASCII.GetBytes("Header-1: value1\r\n");
|
||||||
|
socketInput.IncomingData(headerArray, 0, headerArray.Length);
|
||||||
|
|
||||||
|
Assert.False(frame.TakeMessageHeaders(socketInput, (FrameRequestHeaders)frame.RequestHeaders));
|
||||||
|
|
||||||
|
socketInput.IncomingData(Encoding.ASCII.GetBytes(" "), 0, 1);
|
||||||
|
|
||||||
|
var exception = Assert.Throws<BadHttpRequestException>(() => frame.TakeMessageHeaders(socketInput, (FrameRequestHeaders)frame.RequestHeaders));
|
||||||
|
Assert.Equal("Header value line folding not supported.", exception.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("Header-1: value1\r\r\n")]
|
||||||
|
[InlineData("Header-1: val\rue1\r\n")]
|
||||||
|
[InlineData("Header-1: value1\rHeader-2: value2\r\n\r\n")]
|
||||||
|
[InlineData("Header-1: value1\r\nHeader-2: value2\r\r\n")]
|
||||||
|
[InlineData("Header-1: value1\r\nHeader-2: v\ralue2\r\n")]
|
||||||
|
public void ThrowsOnHeaderValueContainingCR(string rawHeaders)
|
||||||
|
{
|
||||||
|
var trace = new KestrelTrace(new TestKestrelTrace());
|
||||||
|
var ltp = new LoggingThreadPool(trace);
|
||||||
|
using (var pool = new MemoryPool())
|
||||||
|
using (var socketInput = new SocketInput(pool, ltp))
|
||||||
|
{
|
||||||
|
var connectionContext = new ConnectionContext()
|
||||||
|
{
|
||||||
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
|
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
||||||
|
ServerOptions = new KestrelServerOptions(),
|
||||||
|
Log = trace
|
||||||
|
};
|
||||||
|
var frame = new Frame<object>(application: null, context: connectionContext);
|
||||||
|
frame.Reset();
|
||||||
frame.InitializeHeaders();
|
frame.InitializeHeaders();
|
||||||
|
|
||||||
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
||||||
socketInput.IncomingData(headerArray, 0, headerArray.Length);
|
socketInput.IncomingData(headerArray, 0, headerArray.Length);
|
||||||
|
|
||||||
Assert.Throws<BadHttpRequestException>(() => frame.TakeMessageHeaders(socketInput, (FrameRequestHeaders)frame.RequestHeaders));
|
var exception = Assert.Throws<BadHttpRequestException>(() => frame.TakeMessageHeaders(socketInput, (FrameRequestHeaders)frame.RequestHeaders));
|
||||||
|
Assert.Equal("Header value must not contain CR characters.", exception.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -241,15 +288,18 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
{
|
{
|
||||||
DateHeaderValueManager = new DateHeaderValueManager(),
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
||||||
|
ServerOptions = new KestrelServerOptions(),
|
||||||
Log = trace
|
Log = trace
|
||||||
};
|
};
|
||||||
var frame = new Frame<object>(application: null, context: connectionContext);
|
var frame = new Frame<object>(application: null, context: connectionContext);
|
||||||
|
frame.Reset();
|
||||||
frame.InitializeHeaders();
|
frame.InitializeHeaders();
|
||||||
|
|
||||||
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
||||||
socketInput.IncomingData(headerArray, 0, headerArray.Length);
|
socketInput.IncomingData(headerArray, 0, headerArray.Length);
|
||||||
|
|
||||||
Assert.Throws<BadHttpRequestException>(() => frame.TakeMessageHeaders(socketInput, (FrameRequestHeaders)frame.RequestHeaders));
|
var exception = Assert.Throws<BadHttpRequestException>(() => frame.TakeMessageHeaders(socketInput, (FrameRequestHeaders)frame.RequestHeaders));
|
||||||
|
Assert.Equal("No ':' character found in header line.", exception.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -258,8 +308,6 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
[InlineData("\tHeader: value\r\n\r\n")]
|
[InlineData("\tHeader: value\r\n\r\n")]
|
||||||
[InlineData(" Header-1: value1\r\nHeader-2: value2\r\n\r\n")]
|
[InlineData(" Header-1: value1\r\nHeader-2: value2\r\n\r\n")]
|
||||||
[InlineData("\tHeader-1: value1\r\nHeader-2: value2\r\n\r\n")]
|
[InlineData("\tHeader-1: value1\r\nHeader-2: value2\r\n\r\n")]
|
||||||
[InlineData("Header-1: value1\r\n Header-2: value2\r\n\r\n")]
|
|
||||||
[InlineData("Header-1: value1\r\n\tHeader-2: value2\r\n\r\n")]
|
|
||||||
public void ThrowsOnHeaderLineStartingWithWhitespace(string rawHeaders)
|
public void ThrowsOnHeaderLineStartingWithWhitespace(string rawHeaders)
|
||||||
{
|
{
|
||||||
var trace = new KestrelTrace(new TestKestrelTrace());
|
var trace = new KestrelTrace(new TestKestrelTrace());
|
||||||
|
|
@ -271,15 +319,18 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
{
|
{
|
||||||
DateHeaderValueManager = new DateHeaderValueManager(),
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
||||||
|
ServerOptions = new KestrelServerOptions(),
|
||||||
Log = trace
|
Log = trace
|
||||||
};
|
};
|
||||||
var frame = new Frame<object>(application: null, context: connectionContext);
|
var frame = new Frame<object>(application: null, context: connectionContext);
|
||||||
|
frame.Reset();
|
||||||
frame.InitializeHeaders();
|
frame.InitializeHeaders();
|
||||||
|
|
||||||
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
||||||
socketInput.IncomingData(headerArray, 0, headerArray.Length);
|
socketInput.IncomingData(headerArray, 0, headerArray.Length);
|
||||||
|
|
||||||
Assert.Throws<BadHttpRequestException>(() => frame.TakeMessageHeaders(socketInput, (FrameRequestHeaders)frame.RequestHeaders));
|
var exception = Assert.Throws<BadHttpRequestException>(() => frame.TakeMessageHeaders(socketInput, (FrameRequestHeaders)frame.RequestHeaders));
|
||||||
|
Assert.Equal("Header line must not start with whitespace.", exception.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -303,21 +354,25 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
{
|
{
|
||||||
DateHeaderValueManager = new DateHeaderValueManager(),
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
||||||
|
ServerOptions = new KestrelServerOptions(),
|
||||||
Log = trace
|
Log = trace
|
||||||
};
|
};
|
||||||
var frame = new Frame<object>(application: null, context: connectionContext);
|
var frame = new Frame<object>(application: null, context: connectionContext);
|
||||||
|
frame.Reset();
|
||||||
frame.InitializeHeaders();
|
frame.InitializeHeaders();
|
||||||
|
|
||||||
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
||||||
socketInput.IncomingData(headerArray, 0, headerArray.Length);
|
socketInput.IncomingData(headerArray, 0, headerArray.Length);
|
||||||
|
|
||||||
Assert.Throws<BadHttpRequestException>(() => frame.TakeMessageHeaders(socketInput, (FrameRequestHeaders)frame.RequestHeaders));
|
var exception = Assert.Throws<BadHttpRequestException>(() => frame.TakeMessageHeaders(socketInput, (FrameRequestHeaders)frame.RequestHeaders));
|
||||||
|
Assert.Equal("Whitespace is not allowed in header name.", exception.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
[InlineData("Header-1: value1\r\nHeader-2: value2\r\n\r\r")]
|
||||||
[InlineData("Header-1: value1\r\nHeader-2: value2\r\n\r ")]
|
[InlineData("Header-1: value1\r\nHeader-2: value2\r\n\r ")]
|
||||||
[InlineData("Header-1: value1\r\nHeader-2: value2\r\nEnd\r\n")]
|
[InlineData("Header-1: value1\r\nHeader-2: value2\r\n\r \n")]
|
||||||
public void ThrowsOnHeadersNotEndingInCRLFLine(string rawHeaders)
|
public void ThrowsOnHeadersNotEndingInCRLFLine(string rawHeaders)
|
||||||
{
|
{
|
||||||
var trace = new KestrelTrace(new TestKestrelTrace());
|
var trace = new KestrelTrace(new TestKestrelTrace());
|
||||||
|
|
@ -329,15 +384,84 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
{
|
{
|
||||||
DateHeaderValueManager = new DateHeaderValueManager(),
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
||||||
|
ServerOptions = new KestrelServerOptions(),
|
||||||
Log = trace
|
Log = trace
|
||||||
};
|
};
|
||||||
var frame = new Frame<object>(application: null, context: connectionContext);
|
var frame = new Frame<object>(application: null, context: connectionContext);
|
||||||
|
frame.Reset();
|
||||||
frame.InitializeHeaders();
|
frame.InitializeHeaders();
|
||||||
|
|
||||||
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
||||||
socketInput.IncomingData(headerArray, 0, headerArray.Length);
|
socketInput.IncomingData(headerArray, 0, headerArray.Length);
|
||||||
|
|
||||||
Assert.Throws<BadHttpRequestException>(() => frame.TakeMessageHeaders(socketInput, (FrameRequestHeaders)frame.RequestHeaders));
|
var exception = Assert.Throws<BadHttpRequestException>(() => frame.TakeMessageHeaders(socketInput, (FrameRequestHeaders)frame.RequestHeaders));
|
||||||
|
Assert.Equal("Headers corrupted, invalid header sequence.", exception.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ThrowsWhenHeadersExceedTotalSizeLimit()
|
||||||
|
{
|
||||||
|
var trace = new KestrelTrace(new TestKestrelTrace());
|
||||||
|
var ltp = new LoggingThreadPool(trace);
|
||||||
|
using (var pool = new MemoryPool())
|
||||||
|
using (var socketInput = new SocketInput(pool, ltp))
|
||||||
|
{
|
||||||
|
const string headerLine = "Header: value\r\n";
|
||||||
|
|
||||||
|
var options = new KestrelServerOptions();
|
||||||
|
options.Limits.MaxRequestHeadersTotalSize = headerLine.Length - 1;
|
||||||
|
|
||||||
|
var connectionContext = new ConnectionContext()
|
||||||
|
{
|
||||||
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
|
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
||||||
|
ServerOptions = options,
|
||||||
|
Log = trace
|
||||||
|
};
|
||||||
|
|
||||||
|
var frame = new Frame<object>(application: null, context: connectionContext);
|
||||||
|
frame.Reset();
|
||||||
|
frame.InitializeHeaders();
|
||||||
|
|
||||||
|
var headerArray = Encoding.ASCII.GetBytes($"{headerLine}\r\n");
|
||||||
|
socketInput.IncomingData(headerArray, 0, headerArray.Length);
|
||||||
|
|
||||||
|
var exception = Assert.Throws<BadHttpRequestException>(() => frame.TakeMessageHeaders(socketInput, (FrameRequestHeaders)frame.RequestHeaders));
|
||||||
|
Assert.Equal("Request headers too long.", exception.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ThrowsWhenHeadersExceedCountLimit()
|
||||||
|
{
|
||||||
|
var trace = new KestrelTrace(new TestKestrelTrace());
|
||||||
|
var ltp = new LoggingThreadPool(trace);
|
||||||
|
using (var pool = new MemoryPool())
|
||||||
|
using (var socketInput = new SocketInput(pool, ltp))
|
||||||
|
{
|
||||||
|
const string headerLines = "Header-1: value1\r\nHeader-2: value2\r\n";
|
||||||
|
|
||||||
|
var options = new KestrelServerOptions();
|
||||||
|
options.Limits.MaxRequestHeaderCount = 1;
|
||||||
|
|
||||||
|
var connectionContext = new ConnectionContext()
|
||||||
|
{
|
||||||
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
|
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
||||||
|
ServerOptions = options,
|
||||||
|
Log = trace
|
||||||
|
};
|
||||||
|
|
||||||
|
var frame = new Frame<object>(application: null, context: connectionContext);
|
||||||
|
frame.Reset();
|
||||||
|
frame.InitializeHeaders();
|
||||||
|
|
||||||
|
var headerArray = Encoding.ASCII.GetBytes($"{headerLines}\r\n");
|
||||||
|
socketInput.IncomingData(headerArray, 0, headerArray.Length);
|
||||||
|
|
||||||
|
var exception = Assert.Throws<BadHttpRequestException>(() => frame.TakeMessageHeaders(socketInput, (FrameRequestHeaders)frame.RequestHeaders));
|
||||||
|
Assert.Equal("Request contains too many headers.", exception.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -358,9 +482,11 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
var connectionContext = new ConnectionContext()
|
var connectionContext = new ConnectionContext()
|
||||||
{
|
{
|
||||||
DateHeaderValueManager = new DateHeaderValueManager(),
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
ServerAddress = ServerAddress.FromUrl("http://localhost:5000")
|
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
||||||
|
ServerOptions = new KestrelServerOptions(),
|
||||||
};
|
};
|
||||||
var frame = new Frame<object>(application: null, context: connectionContext);
|
var frame = new Frame<object>(application: null, context: connectionContext);
|
||||||
|
frame.Reset();
|
||||||
frame.InitializeHeaders();
|
frame.InitializeHeaders();
|
||||||
|
|
||||||
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
|
||||||
|
|
@ -384,7 +510,8 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
var connectionContext = new ConnectionContext()
|
var connectionContext = new ConnectionContext()
|
||||||
{
|
{
|
||||||
DateHeaderValueManager = new DateHeaderValueManager(),
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
ServerAddress = ServerAddress.FromUrl("http://localhost:5000")
|
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
||||||
|
ServerOptions = new KestrelServerOptions(),
|
||||||
};
|
};
|
||||||
var frame = new Frame<object>(application: null, context: connectionContext);
|
var frame = new Frame<object>(application: null, context: connectionContext);
|
||||||
frame.Scheme = "https";
|
frame.Scheme = "https";
|
||||||
|
|
@ -396,6 +523,50 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
Assert.Equal("http", ((IFeatureCollection)frame).Get<IHttpRequestFeature>().Scheme);
|
Assert.Equal("http", ((IFeatureCollection)frame).Get<IHttpRequestFeature>().Scheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ResetResetsHeaderLimits()
|
||||||
|
{
|
||||||
|
var trace = new KestrelTrace(new TestKestrelTrace());
|
||||||
|
var ltp = new LoggingThreadPool(trace);
|
||||||
|
using (var pool = new MemoryPool())
|
||||||
|
using (var socketInput = new SocketInput(pool, ltp))
|
||||||
|
{
|
||||||
|
const string headerLine1 = "Header-1: value1\r\n";
|
||||||
|
const string headerLine2 = "Header-2: value2\r\n";
|
||||||
|
|
||||||
|
var options = new KestrelServerOptions();
|
||||||
|
options.Limits.MaxRequestHeadersTotalSize = headerLine1.Length;
|
||||||
|
options.Limits.MaxRequestHeaderCount = 1;
|
||||||
|
|
||||||
|
var connectionContext = new ConnectionContext()
|
||||||
|
{
|
||||||
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
|
ServerAddress = ServerAddress.FromUrl("http://localhost:5000"),
|
||||||
|
ServerOptions = options
|
||||||
|
};
|
||||||
|
|
||||||
|
var frame = new Frame<object>(application: null, context: connectionContext);
|
||||||
|
frame.Reset();
|
||||||
|
frame.InitializeHeaders();
|
||||||
|
|
||||||
|
var headerArray1 = Encoding.ASCII.GetBytes($"{headerLine1}\r\n");
|
||||||
|
socketInput.IncomingData(headerArray1, 0, headerArray1.Length);
|
||||||
|
|
||||||
|
Assert.True(frame.TakeMessageHeaders(socketInput, (FrameRequestHeaders)frame.RequestHeaders));
|
||||||
|
Assert.Equal(1, frame.RequestHeaders.Count);
|
||||||
|
Assert.Equal("value1", frame.RequestHeaders["Header-1"]);
|
||||||
|
|
||||||
|
frame.Reset();
|
||||||
|
|
||||||
|
var headerArray2 = Encoding.ASCII.GetBytes($"{headerLine2}\r\n");
|
||||||
|
socketInput.IncomingData(headerArray2, 0, headerArray1.Length);
|
||||||
|
|
||||||
|
Assert.True(frame.TakeMessageHeaders(socketInput, (FrameRequestHeaders)frame.RequestHeaders));
|
||||||
|
Assert.Equal(1, frame.RequestHeaders.Count);
|
||||||
|
Assert.Equal("value2", frame.RequestHeaders["Header-2"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ThrowsWhenStatusCodeIsSetAfterResponseStarted()
|
public void ThrowsWhenStatusCodeIsSetAfterResponseStarted()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -63,5 +63,61 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
o.MaxRequestLineSize = value;
|
o.MaxRequestLineSize = value;
|
||||||
Assert.Equal(value, o.MaxRequestLineSize);
|
Assert.Equal(value, o.MaxRequestLineSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MaxRequestHeaderTotalSizeDefault()
|
||||||
|
{
|
||||||
|
Assert.Equal(32 * 1024, (new KestrelServerLimits()).MaxRequestHeadersTotalSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(int.MinValue)]
|
||||||
|
[InlineData(-1)]
|
||||||
|
[InlineData(0)]
|
||||||
|
public void MaxRequestHeaderTotalSizeInvalid(int value)
|
||||||
|
{
|
||||||
|
Assert.Throws<ArgumentOutOfRangeException>(() =>
|
||||||
|
{
|
||||||
|
(new KestrelServerLimits()).MaxRequestHeadersTotalSize = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(1)]
|
||||||
|
[InlineData(int.MaxValue)]
|
||||||
|
public void MaxRequestHeaderTotalSizeValid(int value)
|
||||||
|
{
|
||||||
|
var o = new KestrelServerLimits();
|
||||||
|
o.MaxRequestHeadersTotalSize = value;
|
||||||
|
Assert.Equal(value, o.MaxRequestHeadersTotalSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MaxRequestHeadersDefault()
|
||||||
|
{
|
||||||
|
Assert.Equal(100, (new KestrelServerLimits()).MaxRequestHeaderCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(int.MinValue)]
|
||||||
|
[InlineData(-1)]
|
||||||
|
[InlineData(0)]
|
||||||
|
public void MaxRequestHeadersInvalid(int value)
|
||||||
|
{
|
||||||
|
Assert.Throws<ArgumentOutOfRangeException>(() =>
|
||||||
|
{
|
||||||
|
(new KestrelServerLimits()).MaxRequestHeaderCount = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(1)]
|
||||||
|
[InlineData(int.MaxValue)]
|
||||||
|
public void MaxRequestHeadersValid(int value)
|
||||||
|
{
|
||||||
|
var o = new KestrelServerLimits();
|
||||||
|
o.MaxRequestHeaderCount = value;
|
||||||
|
Assert.Equal(value, o.MaxRequestHeaderCount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue