Unify header rejection messages.

- Log bad headers with escaped non-vchar characters
This commit is contained in:
Cesar Blum Silveira 2017-03-07 17:25:15 -08:00
parent dbcf34388e
commit bb973decb8
7 changed files with 109 additions and 166 deletions

View File

@ -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);

View File

@ -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)]

View File

@ -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,

View File

@ -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)

View File

@ -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()
{ {

View File

@ -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>(() =>

View File

@ -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 }));
}
}
} }
} }