Unify header rejection messages.
- Log bad headers with escaped non-vchar characters
This commit is contained in:
parent
dbcf34388e
commit
bb973decb8
|
|
@ -22,20 +22,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
||||||
BadHttpRequestException ex;
|
BadHttpRequestException ex;
|
||||||
switch (reason)
|
switch (reason)
|
||||||
{
|
{
|
||||||
case RequestRejectionReason.HeadersCorruptedInvalidHeaderSequence:
|
case RequestRejectionReason.InvalidRequestHeadersNoCRLF:
|
||||||
ex = new BadHttpRequestException("Headers corrupted, invalid header sequence.", StatusCodes.Status400BadRequest);
|
ex = new BadHttpRequestException("Invalid request headers: missing final CRLF in header fields.", StatusCodes.Status400BadRequest);
|
||||||
break;
|
|
||||||
case RequestRejectionReason.NoColonCharacterFoundInHeaderLine:
|
|
||||||
ex = new BadHttpRequestException("No ':' character found in header line.", StatusCodes.Status400BadRequest);
|
|
||||||
break;
|
|
||||||
case RequestRejectionReason.WhitespaceIsNotAllowedInHeaderName:
|
|
||||||
ex = new BadHttpRequestException("Whitespace is not allowed in header name.", StatusCodes.Status400BadRequest);
|
|
||||||
break;
|
|
||||||
case RequestRejectionReason.HeaderValueMustNotContainCR:
|
|
||||||
ex = new BadHttpRequestException("Header value must not contain CR characters.", StatusCodes.Status400BadRequest);
|
|
||||||
break;
|
|
||||||
case RequestRejectionReason.HeaderValueLineFoldingNotSupported:
|
|
||||||
ex = new BadHttpRequestException("Header value line folding not supported.", StatusCodes.Status400BadRequest);
|
|
||||||
break;
|
break;
|
||||||
case RequestRejectionReason.InvalidRequestLine:
|
case RequestRejectionReason.InvalidRequestLine:
|
||||||
ex = new BadHttpRequestException("Invalid request line.", StatusCodes.Status400BadRequest);
|
ex = new BadHttpRequestException("Invalid request line.", StatusCodes.Status400BadRequest);
|
||||||
|
|
@ -58,24 +46,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
||||||
case RequestRejectionReason.ChunkedRequestIncomplete:
|
case RequestRejectionReason.ChunkedRequestIncomplete:
|
||||||
ex = new BadHttpRequestException("Chunked request incomplete.", StatusCodes.Status400BadRequest);
|
ex = new BadHttpRequestException("Chunked request incomplete.", StatusCodes.Status400BadRequest);
|
||||||
break;
|
break;
|
||||||
case RequestRejectionReason.PathContainsNullCharacters:
|
|
||||||
ex = new BadHttpRequestException("The path contains null characters.", StatusCodes.Status400BadRequest);
|
|
||||||
break;
|
|
||||||
case RequestRejectionReason.InvalidCharactersInHeaderName:
|
case RequestRejectionReason.InvalidCharactersInHeaderName:
|
||||||
ex = new BadHttpRequestException("Invalid characters in header name.", StatusCodes.Status400BadRequest);
|
ex = new BadHttpRequestException("Invalid characters in header name.", StatusCodes.Status400BadRequest);
|
||||||
break;
|
break;
|
||||||
case RequestRejectionReason.NonAsciiOrNullCharactersInInputString:
|
|
||||||
ex = new BadHttpRequestException("The input string contains non-ASCII or null characters.", StatusCodes.Status400BadRequest);
|
|
||||||
break;
|
|
||||||
case RequestRejectionReason.RequestLineTooLong:
|
case RequestRejectionReason.RequestLineTooLong:
|
||||||
ex = new BadHttpRequestException("Request line too long.", StatusCodes.Status414UriTooLong);
|
ex = new BadHttpRequestException("Request line too long.", StatusCodes.Status414UriTooLong);
|
||||||
break;
|
break;
|
||||||
case RequestRejectionReason.HeadersExceedMaxTotalSize:
|
case RequestRejectionReason.HeadersExceedMaxTotalSize:
|
||||||
ex = new BadHttpRequestException("Request headers too long.", StatusCodes.Status431RequestHeaderFieldsTooLarge);
|
ex = new BadHttpRequestException("Request headers too long.", StatusCodes.Status431RequestHeaderFieldsTooLarge);
|
||||||
break;
|
break;
|
||||||
case RequestRejectionReason.MissingCRInHeaderLine:
|
|
||||||
ex = new BadHttpRequestException("No CR character found in header line.", StatusCodes.Status400BadRequest);
|
|
||||||
break;
|
|
||||||
case RequestRejectionReason.TooManyHeaders:
|
case RequestRejectionReason.TooManyHeaders:
|
||||||
ex = new BadHttpRequestException("Request contains too many headers.", StatusCodes.Status431RequestHeaderFieldsTooLarge);
|
ex = new BadHttpRequestException("Request contains too many headers.", StatusCodes.Status431RequestHeaderFieldsTooLarge);
|
||||||
break;
|
break;
|
||||||
|
|
@ -95,7 +74,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel
|
||||||
switch (reason)
|
switch (reason)
|
||||||
{
|
{
|
||||||
case RequestRejectionReason.InvalidRequestLine:
|
case RequestRejectionReason.InvalidRequestLine:
|
||||||
ex = new BadHttpRequestException($"Invalid request line: {value}", StatusCodes.Status400BadRequest);
|
ex = new BadHttpRequestException($"Invalid request line: '{value}'", StatusCodes.Status400BadRequest);
|
||||||
|
break;
|
||||||
|
case RequestRejectionReason.InvalidRequestHeader:
|
||||||
|
ex = new BadHttpRequestException($"Invalid request header: '{value}'", StatusCodes.Status400BadRequest);
|
||||||
break;
|
break;
|
||||||
case RequestRejectionReason.InvalidContentLength:
|
case RequestRejectionReason.InvalidContentLength:
|
||||||
ex = new BadHttpRequestException($"Invalid content length: {value}", StatusCodes.Status400BadRequest);
|
ex = new BadHttpRequestException($"Invalid content length: {value}", StatusCodes.Status400BadRequest);
|
||||||
|
|
|
||||||
|
|
@ -316,11 +316,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
}
|
}
|
||||||
|
|
||||||
// Headers don't end in CRLF line.
|
// Headers don't end in CRLF line.
|
||||||
RejectRequest(RequestRejectionReason.HeadersCorruptedInvalidHeaderSequence);
|
RejectRequest(RequestRejectionReason.InvalidRequestHeadersNoCRLF);
|
||||||
}
|
|
||||||
else if(ch1 == ByteSpace || ch1 == ByteTab)
|
|
||||||
{
|
|
||||||
RejectRequest(RequestRejectionReason.WhitespaceIsNotAllowedInHeaderName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We moved the reader so look ahead 2 bytes so reset both the reader
|
// We moved the reader so look ahead 2 bytes so reset both the reader
|
||||||
|
|
@ -390,7 +386,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static unsafe int FindEndOfName(byte* headerLine, int length)
|
private unsafe int FindEndOfName(byte* headerLine, int length)
|
||||||
{
|
{
|
||||||
var index = 0;
|
var index = 0;
|
||||||
var sawWhitespace = false;
|
var sawWhitespace = false;
|
||||||
|
|
@ -407,14 +403,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index == length)
|
if (index == length || sawWhitespace)
|
||||||
{
|
{
|
||||||
RejectRequest(RequestRejectionReason.NoColonCharacterFoundInHeaderLine);
|
RejectRequestHeader(headerLine, length);
|
||||||
}
|
|
||||||
if (sawWhitespace)
|
|
||||||
{
|
|
||||||
RejectRequest(RequestRejectionReason.WhitespaceIsNotAllowedInHeaderName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -427,11 +420,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
|
|
||||||
if (headerLine[valueEnd + 2] != ByteLF)
|
if (headerLine[valueEnd + 2] != ByteLF)
|
||||||
{
|
{
|
||||||
RejectRequest(RequestRejectionReason.HeaderValueMustNotContainCR);
|
RejectRequestHeader(headerLine, length);
|
||||||
}
|
}
|
||||||
if (headerLine[valueEnd + 1] != ByteCR)
|
if (headerLine[valueEnd + 1] != ByteCR)
|
||||||
{
|
{
|
||||||
RejectRequest(RequestRejectionReason.MissingCRInHeaderLine);
|
RejectRequestHeader(headerLine, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip colon from value start
|
// Skip colon from value start
|
||||||
|
|
@ -446,16 +439,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
}
|
}
|
||||||
else if (ch == ByteCR)
|
else if (ch == ByteCR)
|
||||||
{
|
{
|
||||||
RejectRequest(RequestRejectionReason.HeaderValueMustNotContainCR);
|
RejectRequestHeader(headerLine, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Check for CR in value
|
// Check for CR in value
|
||||||
var i = valueStart + 1;
|
var i = valueStart + 1;
|
||||||
if (Contains(headerLine + i, valueEnd - i, ByteCR))
|
if (Contains(headerLine + i, valueEnd - i, ByteCR))
|
||||||
{
|
{
|
||||||
RejectRequest(RequestRejectionReason.HeaderValueMustNotContainCR);
|
RejectRequestHeader(headerLine, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore end whitespace
|
// Ignore end whitespace
|
||||||
|
|
@ -557,9 +549,25 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
Log.IsEnabled(LogLevel.Information) ? span.GetAsciiStringEscaped(MaxRequestLineError) : string.Empty);
|
Log.IsEnabled(LogLevel.Information) ? span.GetAsciiStringEscaped(MaxRequestLineError) : string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private unsafe void RejectRequestHeader(byte* headerLine, int length)
|
||||||
|
{
|
||||||
|
RejectRequestHeader(new Span<byte>(headerLine, length));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RejectRequestHeader(Span<byte> span)
|
||||||
|
{
|
||||||
|
throw GetRejectRequestHeaderException(span);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BadHttpRequestException GetRejectRequestHeaderException(Span<byte> span)
|
||||||
|
{
|
||||||
|
const int MaxRequestHeaderError = 128;
|
||||||
|
return BadHttpRequestException.GetException(RequestRejectionReason.InvalidRequestHeader,
|
||||||
|
Log.IsEnabled(LogLevel.Information) ? span.GetAsciiStringEscaped(MaxRequestHeaderError) : string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
public enum RequestRejectionReason
|
public enum RequestRejectionReason
|
||||||
{
|
{
|
||||||
UnrecognizedHTTPVersion,
|
UnrecognizedHTTPVersion,
|
||||||
HeadersCorruptedInvalidHeaderSequence,
|
|
||||||
NoColonCharacterFoundInHeaderLine,
|
|
||||||
WhitespaceIsNotAllowedInHeaderName,
|
|
||||||
HeaderValueMustNotContainCR,
|
|
||||||
HeaderValueLineFoldingNotSupported,
|
|
||||||
InvalidRequestLine,
|
InvalidRequestLine,
|
||||||
|
InvalidRequestHeader,
|
||||||
|
InvalidRequestHeadersNoCRLF,
|
||||||
MalformedRequestInvalidHeaders,
|
MalformedRequestInvalidHeaders,
|
||||||
InvalidContentLength,
|
InvalidContentLength,
|
||||||
MultipleContentLengths,
|
MultipleContentLengths,
|
||||||
|
|
@ -19,12 +16,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
BadChunkSuffix,
|
BadChunkSuffix,
|
||||||
BadChunkSizeData,
|
BadChunkSizeData,
|
||||||
ChunkedRequestIncomplete,
|
ChunkedRequestIncomplete,
|
||||||
PathContainsNullCharacters,
|
|
||||||
InvalidCharactersInHeaderName,
|
InvalidCharactersInHeaderName,
|
||||||
NonAsciiOrNullCharactersInInputString,
|
|
||||||
RequestLineTooLong,
|
RequestLineTooLong,
|
||||||
HeadersExceedMaxTotalSize,
|
HeadersExceedMaxTotalSize,
|
||||||
MissingCRInHeaderLine,
|
|
||||||
TooManyHeaders,
|
TooManyHeaders,
|
||||||
RequestTimeout,
|
RequestTimeout,
|
||||||
FinalTransferCodingNotChunked,
|
FinalTransferCodingNotChunked,
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
|
|
||||||
foreach (var requestLine in HttpParsingData.RequestLineInvalidData)
|
foreach (var requestLine in HttpParsingData.RequestLineInvalidData)
|
||||||
{
|
{
|
||||||
data.Add(requestLine, $"Invalid request line: {requestLine.Replace("\r", "\\x0D").Replace("\n", "\\x0A")}");
|
data.Add(requestLine, $"Invalid request line: '{requestLine.Replace("\r", "\\x0D").Replace("\n", "\\x0A")}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var requestLine in HttpParsingData.RequestLineWithEncodedNullCharInTargetData)
|
foreach (var requestLine in HttpParsingData.RequestLineWithEncodedNullCharInTargetData)
|
||||||
|
|
|
||||||
|
|
@ -81,25 +81,6 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
_pipelineFactory.Dispose();
|
_pipelineFactory.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task TakeMessageHeadersThrowsOnHeaderValueWithLineFolding_CharacterNotAvailableOnFirstAttempt()
|
|
||||||
{
|
|
||||||
await _input.Writer.WriteAsync(Encoding.ASCII.GetBytes("Header-1: value1\r\n"));
|
|
||||||
|
|
||||||
var readableBuffer = (await _input.Reader.ReadAsync()).Buffer;
|
|
||||||
Assert.False(_frame.TakeMessageHeaders(readableBuffer, out _consumed, out _examined));
|
|
||||||
_input.Reader.Advance(_consumed, _examined);
|
|
||||||
|
|
||||||
await _input.Writer.WriteAsync(Encoding.ASCII.GetBytes(" "));
|
|
||||||
|
|
||||||
readableBuffer = (await _input.Reader.ReadAsync()).Buffer;
|
|
||||||
var exception = Assert.Throws<BadHttpRequestException>(() => _frame.TakeMessageHeaders(readableBuffer, out _consumed, out _examined));
|
|
||||||
_input.Reader.Advance(_consumed, _examined);
|
|
||||||
|
|
||||||
Assert.Equal("Whitespace is not allowed in header name.", exception.Message);
|
|
||||||
Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task TakeMessageHeadersThrowsWhenHeadersExceedTotalSizeLimit()
|
public async Task TakeMessageHeadersThrowsWhenHeadersExceedTotalSizeLimit()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
||||||
parser.ParseRequestLine(Mock.Of<IHttpRequestLineHandler>(), buffer, out var consumed, out var examined));
|
parser.ParseRequestLine(Mock.Of<IHttpRequestLineHandler>(), buffer, out var consumed, out var examined));
|
||||||
|
|
||||||
Assert.Equal($"Invalid request line: {requestLine.Replace("\r", "\\x0D").Replace("\n", "\\x0A")}", exception.Message);
|
Assert.Equal($"Invalid request line: '{requestLine.Replace("\r", "\\x0D").Replace("\n", "\\x0A")}'", exception.Message);
|
||||||
Assert.Equal(StatusCodes.Status400BadRequest, (exception as BadHttpRequestException).StatusCode);
|
Assert.Equal(StatusCodes.Status400BadRequest, (exception as BadHttpRequestException).StatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -306,7 +306,12 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
[MemberData(nameof(RequestHeaderInvalidData))]
|
[MemberData(nameof(RequestHeaderInvalidData))]
|
||||||
public void ParseHeadersThrowsOnInvalidRequestHeaders(string rawHeaders, string expectedExceptionMessage)
|
public void ParseHeadersThrowsOnInvalidRequestHeaders(string rawHeaders, string expectedExceptionMessage)
|
||||||
{
|
{
|
||||||
var parser = CreateParser(Mock.Of<IKestrelTrace>());
|
var mockTrace = new Mock<IKestrelTrace>();
|
||||||
|
mockTrace
|
||||||
|
.Setup(trace => trace.IsEnabled(LogLevel.Information))
|
||||||
|
.Returns(true);
|
||||||
|
|
||||||
|
var parser = CreateParser(mockTrace.Object);
|
||||||
var buffer = ReadableBuffer.Create(Encoding.ASCII.GetBytes(rawHeaders));
|
var buffer = ReadableBuffer.Create(Encoding.ASCII.GetBytes(rawHeaders));
|
||||||
|
|
||||||
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
var exception = Assert.Throws<BadHttpRequestException>(() =>
|
||||||
|
|
|
||||||
|
|
@ -203,106 +203,79 @@ namespace Microsoft.AspNetCore.Testing
|
||||||
"8charact",
|
"8charact",
|
||||||
};
|
};
|
||||||
|
|
||||||
public static IEnumerable<object[]> RequestHeaderInvalidData
|
public static IEnumerable<object[]> RequestHeaderInvalidData => new[]
|
||||||
{
|
{
|
||||||
get
|
// Missing CR
|
||||||
{
|
new[] { "Header: value\n\r\n", @"Invalid request header: 'Header: value\x0A'" },
|
||||||
// Line folding
|
new[] { "Header-1: value1\nHeader-2: value2\r\n\r\n", @"Invalid request header: 'Header-1: value1\x0A'" },
|
||||||
var headersWithLineFolding = new[]
|
new[] { "Header-1: value1\r\nHeader-2: value2\n\r\n", @"Invalid request header: 'Header-2: value2\x0A'" },
|
||||||
{
|
|
||||||
"Header: line1\r\n line2\r\n\r\n",
|
|
||||||
"Header: line1\r\n\tline2\r\n\r\n",
|
|
||||||
"Header: line1\r\n line2\r\n\r\n",
|
|
||||||
"Header: line1\r\n \tline2\r\n\r\n",
|
|
||||||
"Header: line1\r\n\t line2\r\n\r\n",
|
|
||||||
"Header: line1\r\n\t\tline2\r\n\r\n",
|
|
||||||
"Header: line1\r\n \t\t line2\r\n\r\n",
|
|
||||||
"Header: line1\r\n \t \t line2\r\n\r\n",
|
|
||||||
"Header-1: multi\r\n line\r\nHeader-2: value2\r\n\r\n",
|
|
||||||
"Header-1: value1\r\nHeader-2: multi\r\n line\r\n\r\n",
|
|
||||||
"Header-1: value1\r\n Header-2: value2\r\n\r\n",
|
|
||||||
"Header-1: value1\r\n\tHeader-2: value2\r\n\r\n",
|
|
||||||
};
|
|
||||||
|
|
||||||
// CR in value
|
// Line folding
|
||||||
var headersWithCRInValue = new[]
|
new[] { "Header: line1\r\n line2\r\n\r\n", @"Invalid request header: ' line2\x0D\x0A'" },
|
||||||
{
|
new[] { "Header: line1\r\n\tline2\r\n\r\n", @"Invalid request header: '\x09line2\x0D\x0A'" },
|
||||||
"Header-1: value1\r\r\n",
|
new[] { "Header: line1\r\n line2\r\n\r\n", @"Invalid request header: ' line2\x0D\x0A'" },
|
||||||
"Header-1: val\rue1\r\n",
|
new[] { "Header: line1\r\n \tline2\r\n\r\n", @"Invalid request header: ' \x09line2\x0D\x0A'" },
|
||||||
"Header-1: value1\rHeader-2: value2\r\n\r\n",
|
new[] { "Header: line1\r\n\t line2\r\n\r\n", @"Invalid request header: '\x09 line2\x0D\x0A'" },
|
||||||
"Header-1: value1\r\nHeader-2: value2\r\r\n",
|
new[] { "Header: line1\r\n\t\tline2\r\n\r\n", @"Invalid request header: '\x09\x09line2\x0D\x0A'" },
|
||||||
"Header-1: value1\r\nHeader-2: v\ralue2\r\n",
|
new[] { "Header: line1\r\n \t\t line2\r\n\r\n", @"Invalid request header: ' \x09\x09 line2\x0D\x0A'" },
|
||||||
"Header-1: Value__\rVector16________Vector32\r\n",
|
new[] { "Header: line1\r\n \t \t line2\r\n\r\n", @"Invalid request header: ' \x09 \x09 line2\x0D\x0A'" },
|
||||||
"Header-1: Value___Vector16\r________Vector32\r\n",
|
new[] { "Header-1: multi\r\n line\r\nHeader-2: value2\r\n\r\n", @"Invalid request header: ' line\x0D\x0A'" },
|
||||||
"Header-1: Value___Vector16_______\rVector32\r\n",
|
new[] { "Header-1: value1\r\nHeader-2: multi\r\n line\r\n\r\n", @"Invalid request header: ' line\x0D\x0A'" },
|
||||||
"Header-1: Value___Vector16________Vector32\r\r\n",
|
new[] { "Header-1: value1\r\n Header-2: value2\r\n\r\n", @"Invalid request header: ' Header-2: value2\x0D\x0A'" },
|
||||||
"Header-1: Value___Vector16________Vector32_\r\r\n",
|
new[] { "Header-1: value1\r\n\tHeader-2: value2\r\n\r\n", @"Invalid request header: '\x09Header-2: value2\x0D\x0A'" },
|
||||||
"Header-1: Value___Vector16________Vector32Value___Vector16_______\rVector32\r\n",
|
|
||||||
"Header-1: Value___Vector16________Vector32Value___Vector16________Vector32\r\r\n",
|
|
||||||
"Header-1: Value___Vector16________Vector32Value___Vector16________Vector32_\r\r\n",
|
|
||||||
};
|
|
||||||
|
|
||||||
// Missing colon
|
// CR in value
|
||||||
var headersWithMissingColon = new[]
|
new[] { "Header-1: value1\r\r\n", @"Invalid request header: 'Header-1: value1\x0D\x0D\x0A'" },
|
||||||
{
|
new[] { "Header-1: val\rue1\r\n", @"Invalid request header: 'Header-1: val\x0Due1\x0D\x0A'" },
|
||||||
"Header-1 value1\r\n\r\n",
|
new[] { "Header-1: value1\rHeader-2: value2\r\n\r\n", @"Invalid request header: 'Header-1: value1\x0DHeader-2: value2\x0D\x0A'" },
|
||||||
"Header-1 value1\r\nHeader-2: value2\r\n\r\n",
|
new[] { "Header-1: value1\r\nHeader-2: value2\r\r\n", @"Invalid request header: 'Header-2: value2\x0D\x0D\x0A'" },
|
||||||
"Header-1: value1\r\nHeader-2 value2\r\n\r\n",
|
new[] { "Header-1: value1\r\nHeader-2: v\ralue2\r\n", @"Invalid request header: 'Header-2: v\x0Dalue2\x0D\x0A'" },
|
||||||
"\n"
|
new[] { "Header-1: Value__\rVector16________Vector32\r\n", @"Invalid request header: 'Header-1: Value__\x0DVector16________Vector32\x0D\x0A'" },
|
||||||
};
|
new[] { "Header-1: Value___Vector16\r________Vector32\r\n", @"Invalid request header: 'Header-1: Value___Vector16\x0D________Vector32\x0D\x0A'" },
|
||||||
|
new[] { "Header-1: Value___Vector16_______\rVector32\r\n", @"Invalid request header: 'Header-1: Value___Vector16_______\x0DVector32\x0D\x0A'" },
|
||||||
|
new[] { "Header-1: Value___Vector16________Vector32\r\r\n", @"Invalid request header: 'Header-1: Value___Vector16________Vector32\x0D\x0D\x0A'" },
|
||||||
|
new[] { "Header-1: Value___Vector16________Vector32_\r\r\n", @"Invalid request header: 'Header-1: Value___Vector16________Vector32_\x0D\x0D\x0A'" },
|
||||||
|
new[] { "Header-1: Value___Vector16________Vector32Value___Vector16_______\rVector32\r\n", @"Invalid request header: 'Header-1: Value___Vector16________Vector32Value___Vector16_______\x0DVector32\x0D\x0A'" },
|
||||||
|
new[] { "Header-1: Value___Vector16________Vector32Value___Vector16________Vector32\r\r\n", @"Invalid request header: 'Header-1: Value___Vector16________Vector32Value___Vector16________Vector32\x0D\x0D\x0A'" },
|
||||||
|
new[] { "Header-1: Value___Vector16________Vector32Value___Vector16________Vector32_\r\r\n", @"Invalid request header: 'Header-1: Value___Vector16________Vector32Value___Vector16________Vector32_\x0D\x0D\x0A'" },
|
||||||
|
|
||||||
// Starting with whitespace
|
// Missing colon
|
||||||
var headersStartingWithWhitespace = new[]
|
new[] { "Header-1 value1\r\n\r\n", @"Invalid request header: 'Header-1 value1\x0D\x0A'" },
|
||||||
{
|
new[] { "Header-1 value1\r\nHeader-2: value2\r\n\r\n", @"Invalid request header: 'Header-1 value1\x0D\x0A'" },
|
||||||
" Header: value\r\n\r\n",
|
new[] { "Header-1: value1\r\nHeader-2 value2\r\n\r\n", @"Invalid request header: 'Header-2 value2\x0D\x0A'" },
|
||||||
"\tHeader: value\r\n\r\n",
|
new[] { "\n", @"Invalid request header: '\x0A'" },
|
||||||
" Header-1: value1\r\nHeader-2: value2\r\n\r\n",
|
|
||||||
"\tHeader-1: value1\r\nHeader-2: value2\r\n\r\n",
|
|
||||||
};
|
|
||||||
|
|
||||||
// Whitespace in header name
|
// Starting with whitespace
|
||||||
var headersWithWithspaceInName = new[]
|
new[] { " Header: value\r\n\r\n", @"Invalid request header: ' Header: value\x0D\x0A'" },
|
||||||
{
|
new[] { "\tHeader: value\r\n\r\n", @"Invalid request header: '\x09Header: value\x0D\x0A'" },
|
||||||
"Header : value\r\n\r\n",
|
new[] { " Header-1: value1\r\nHeader-2: value2\r\n\r\n", @"Invalid request header: ' Header-1: value1\x0D\x0A'" },
|
||||||
"Header\t: value\r\n\r\n",
|
new[] { "\tHeader-1: value1\r\nHeader-2: value2\r\n\r\n", @"Invalid request header: '\x09Header-1: value1\x0D\x0A'" },
|
||||||
"Header\r: value\r\n\r\n",
|
|
||||||
"Header_\rVector16: value\r\n\r\n",
|
|
||||||
"Header__Vector16\r: value\r\n\r\n",
|
|
||||||
"Header__Vector16_\r: value\r\n\r\n",
|
|
||||||
"Header_\rVector16________Vector32: value\r\n\r\n",
|
|
||||||
"Header__Vector16________Vector32\r: value\r\n\r\n",
|
|
||||||
"Header__Vector16________Vector32_\r: value\r\n\r\n",
|
|
||||||
"Header__Vector16________Vector32Header_\rVector16________Vector32: value\r\n\r\n",
|
|
||||||
"Header__Vector16________Vector32Header__Vector16________Vector32\r: value\r\n\r\n",
|
|
||||||
"Header__Vector16________Vector32Header__Vector16________Vector32_\r: value\r\n\r\n",
|
|
||||||
"Header 1: value1\r\nHeader-2: value2\r\n\r\n",
|
|
||||||
"Header 1 : value1\r\nHeader-2: value2\r\n\r\n",
|
|
||||||
"Header 1\t: value1\r\nHeader-2: value2\r\n\r\n",
|
|
||||||
"Header 1\r: value1\r\nHeader-2: value2\r\n\r\n",
|
|
||||||
"Header-1: value1\r\nHeader 2: value2\r\n\r\n",
|
|
||||||
"Header-1: value1\r\nHeader-2 : value2\r\n\r\n",
|
|
||||||
"Header-1: value1\r\nHeader-2\t: value2\r\n\r\n",
|
|
||||||
};
|
|
||||||
|
|
||||||
// Headers not ending in CRLF line
|
// Whitespace in header name
|
||||||
var headersNotEndingInCrLfLine = new[]
|
new[] { "Header : value\r\n\r\n", @"Invalid request header: 'Header : value\x0D\x0A'" },
|
||||||
{
|
new[] { "Header\t: value\r\n\r\n", @"Invalid request header: 'Header\x09: value\x0D\x0A'" },
|
||||||
"Header-1: value1\r\nHeader-2: value2\r\n\r\r",
|
new[] { "Header\r: value\r\n\r\n", @"Invalid request header: 'Header\x0D: value\x0D\x0A'" },
|
||||||
"Header-1: value1\r\nHeader-2: value2\r\n\r ",
|
new[] { "Header_\rVector16: value\r\n\r\n", @"Invalid request header: 'Header_\x0DVector16: value\x0D\x0A'" },
|
||||||
"Header-1: value1\r\nHeader-2: value2\r\n\r \n",
|
new[] { "Header__Vector16\r: value\r\n\r\n", @"Invalid request header: 'Header__Vector16\x0D: value\x0D\x0A'" },
|
||||||
};
|
new[] { "Header__Vector16_\r: value\r\n\r\n", @"Invalid request header: 'Header__Vector16_\x0D: value\x0D\x0A'" },
|
||||||
|
new[] { "Header_\rVector16________Vector32: value\r\n\r\n", @"Invalid request header: 'Header_\x0DVector16________Vector32: value\x0D\x0A'" },
|
||||||
|
new[] { "Header__Vector16________Vector32\r: value\r\n\r\n", @"Invalid request header: 'Header__Vector16________Vector32\x0D: value\x0D\x0A'" },
|
||||||
|
new[] { "Header__Vector16________Vector32_\r: value\r\n\r\n", @"Invalid request header: 'Header__Vector16________Vector32_\x0D: value\x0D\x0A'" },
|
||||||
|
new[] { "Header__Vector16________Vector32Header_\rVector16________Vector32: value\r\n\r\n", @"Invalid request header: 'Header__Vector16________Vector32Header_\x0DVector16________Vector32: value\x0D\x0A'" },
|
||||||
|
new[] { "Header__Vector16________Vector32Header__Vector16________Vector32\r: value\r\n\r\n", @"Invalid request header: 'Header__Vector16________Vector32Header__Vector16________Vector32\x0D: value\x0D\x0A'" },
|
||||||
|
new[] { "Header__Vector16________Vector32Header__Vector16________Vector32_\r: value\r\n\r\n", @"Invalid request header: 'Header__Vector16________Vector32Header__Vector16________Vector32_\x0D: value\x0D\x0A'" },
|
||||||
|
new[] { "Header 1: value1\r\nHeader-2: value2\r\n\r\n", @"Invalid request header: 'Header 1: value1\x0D\x0A'" },
|
||||||
|
new[] { "Header 1 : value1\r\nHeader-2: value2\r\n\r\n", @"Invalid request header: 'Header 1 : value1\x0D\x0A'" },
|
||||||
|
new[] { "Header 1\t: value1\r\nHeader-2: value2\r\n\r\n", @"Invalid request header: 'Header 1\x09: value1\x0D\x0A'" },
|
||||||
|
new[] { "Header 1\r: value1\r\nHeader-2: value2\r\n\r\n", @"Invalid request header: 'Header 1\x0D: value1\x0D\x0A'" },
|
||||||
|
new[] { "Header-1: value1\r\nHeader 2: value2\r\n\r\n", @"Invalid request header: 'Header 2: value2\x0D\x0A'" },
|
||||||
|
new[] { "Header-1: value1\r\nHeader-2 : value2\r\n\r\n", @"Invalid request header: 'Header-2 : value2\x0D\x0A'" },
|
||||||
|
new[] { "Header-1: value1\r\nHeader-2\t: value2\r\n\r\n", @"Invalid request header: 'Header-2\x09: value2\x0D\x0A'" },
|
||||||
|
|
||||||
return new[]
|
// Headers not ending in CRLF line
|
||||||
{
|
new[] { "Header-1: value1\r\nHeader-2: value2\r\n\r\r", @"Invalid request headers: missing final CRLF in header fields." },
|
||||||
Tuple.Create(headersWithLineFolding, "Whitespace is not allowed in header name."),
|
new[] { "Header-1: value1\r\nHeader-2: value2\r\n\r ", @"Invalid request headers: missing final CRLF in header fields." },
|
||||||
Tuple.Create(headersWithCRInValue, "Header value must not contain CR characters."),
|
new[] { "Header-1: value1\r\nHeader-2: value2\r\n\r \n", @"Invalid request headers: missing final CRLF in header fields." },
|
||||||
Tuple.Create(headersWithMissingColon, "No ':' character found in header line."),
|
};
|
||||||
Tuple.Create(headersStartingWithWhitespace, "Whitespace is not allowed in header name."),
|
|
||||||
Tuple.Create(headersWithWithspaceInName, "Whitespace is not allowed in header name."),
|
|
||||||
Tuple.Create(headersNotEndingInCrLfLine, "Headers corrupted, invalid header sequence.")
|
|
||||||
}
|
|
||||||
.SelectMany(t => t.Item1.Select(headers => new[] { headers, t.Item2 }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue