diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/BadHttpRequestException.cs b/src/Microsoft.AspNetCore.Server.Kestrel/BadHttpRequestException.cs index 54533f05e1..09aaf94a45 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/BadHttpRequestException.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/BadHttpRequestException.cs @@ -22,20 +22,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel BadHttpRequestException ex; switch (reason) { - case RequestRejectionReason.HeadersCorruptedInvalidHeaderSequence: - ex = new BadHttpRequestException("Headers corrupted, invalid header sequence.", 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); + case RequestRejectionReason.InvalidRequestHeadersNoCRLF: + ex = new BadHttpRequestException("Invalid request headers: missing final CRLF in header fields.", StatusCodes.Status400BadRequest); break; case RequestRejectionReason.InvalidRequestLine: ex = new BadHttpRequestException("Invalid request line.", StatusCodes.Status400BadRequest); @@ -58,24 +46,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel case RequestRejectionReason.ChunkedRequestIncomplete: ex = new BadHttpRequestException("Chunked request incomplete.", StatusCodes.Status400BadRequest); break; - case RequestRejectionReason.PathContainsNullCharacters: - ex = new BadHttpRequestException("The path contains null characters.", StatusCodes.Status400BadRequest); - break; case RequestRejectionReason.InvalidCharactersInHeaderName: ex = new BadHttpRequestException("Invalid characters in header name.", StatusCodes.Status400BadRequest); break; - case RequestRejectionReason.NonAsciiOrNullCharactersInInputString: - ex = new BadHttpRequestException("The input string contains non-ASCII or null characters.", StatusCodes.Status400BadRequest); - break; case RequestRejectionReason.RequestLineTooLong: ex = new BadHttpRequestException("Request line too long.", StatusCodes.Status414UriTooLong); break; case RequestRejectionReason.HeadersExceedMaxTotalSize: ex = new BadHttpRequestException("Request headers too long.", StatusCodes.Status431RequestHeaderFieldsTooLarge); break; - case RequestRejectionReason.MissingCRInHeaderLine: - ex = new BadHttpRequestException("No CR character found in header line.", StatusCodes.Status400BadRequest); - break; case RequestRejectionReason.TooManyHeaders: ex = new BadHttpRequestException("Request contains too many headers.", StatusCodes.Status431RequestHeaderFieldsTooLarge); break; @@ -95,7 +74,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel switch (reason) { 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; case RequestRejectionReason.InvalidContentLength: ex = new BadHttpRequestException($"Invalid content length: {value}", StatusCodes.Status400BadRequest); diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/KestrelHttpParser.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/KestrelHttpParser.cs index a5ce732aec..79ecd4b9f0 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/KestrelHttpParser.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/KestrelHttpParser.cs @@ -316,11 +316,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http } // Headers don't end in CRLF line. - RejectRequest(RequestRejectionReason.HeadersCorruptedInvalidHeaderSequence); - } - else if(ch1 == ByteSpace || ch1 == ByteTab) - { - RejectRequest(RequestRejectionReason.WhitespaceIsNotAllowedInHeaderName); + RejectRequest(RequestRejectionReason.InvalidRequestHeadersNoCRLF); } // 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)] - private static unsafe int FindEndOfName(byte* headerLine, int length) + private unsafe int FindEndOfName(byte* headerLine, int length) { var index = 0; var sawWhitespace = false; @@ -407,14 +403,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http } } - if (index == length) + if (index == length || sawWhitespace) { - RejectRequest(RequestRejectionReason.NoColonCharacterFoundInHeaderLine); - } - if (sawWhitespace) - { - RejectRequest(RequestRejectionReason.WhitespaceIsNotAllowedInHeaderName); + RejectRequestHeader(headerLine, length); } + return index; } @@ -427,11 +420,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http if (headerLine[valueEnd + 2] != ByteLF) { - RejectRequest(RequestRejectionReason.HeaderValueMustNotContainCR); + RejectRequestHeader(headerLine, length); } if (headerLine[valueEnd + 1] != ByteCR) { - RejectRequest(RequestRejectionReason.MissingCRInHeaderLine); + RejectRequestHeader(headerLine, length); } // Skip colon from value start @@ -446,16 +439,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http } else if (ch == ByteCR) { - RejectRequest(RequestRejectionReason.HeaderValueMustNotContainCR); + RejectRequestHeader(headerLine, length); } } - // Check for CR in value var i = valueStart + 1; if (Contains(headerLine + i, valueEnd - i, ByteCR)) { - RejectRequest(RequestRejectionReason.HeaderValueMustNotContainCR); + RejectRequestHeader(headerLine, length); } // Ignore end whitespace @@ -557,9 +549,25 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http Log.IsEnabled(LogLevel.Information) ? span.GetAsciiStringEscaped(MaxRequestLineError) : string.Empty); } + private unsafe void RejectRequestHeader(byte* headerLine, int length) + { + RejectRequestHeader(new Span(headerLine, length)); + } + + private void RejectRequestHeader(Span span) + { + throw GetRejectRequestHeaderException(span); + } + + private BadHttpRequestException GetRejectRequestHeaderException(Span span) + { + const int MaxRequestHeaderError = 128; + return BadHttpRequestException.GetException(RequestRejectionReason.InvalidRequestHeader, + Log.IsEnabled(LogLevel.Information) ? span.GetAsciiStringEscaped(MaxRequestHeaderError) : string.Empty); + } + public void Reset() { - } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/RequestRejectionReason.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/RequestRejectionReason.cs index b0aa5a1372..92faea1965 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/RequestRejectionReason.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/RequestRejectionReason.cs @@ -6,12 +6,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http public enum RequestRejectionReason { UnrecognizedHTTPVersion, - HeadersCorruptedInvalidHeaderSequence, - NoColonCharacterFoundInHeaderLine, - WhitespaceIsNotAllowedInHeaderName, - HeaderValueMustNotContainCR, - HeaderValueLineFoldingNotSupported, InvalidRequestLine, + InvalidRequestHeader, + InvalidRequestHeadersNoCRLF, MalformedRequestInvalidHeaders, InvalidContentLength, MultipleContentLengths, @@ -19,12 +16,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http BadChunkSuffix, BadChunkSizeData, ChunkedRequestIncomplete, - PathContainsNullCharacters, InvalidCharactersInHeaderName, - NonAsciiOrNullCharactersInInputString, RequestLineTooLong, HeadersExceedMaxTotalSize, - MissingCRInHeaderLine, TooManyHeaders, RequestTimeout, FinalTransferCodingNotChunked, diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/BadHttpRequestTests.cs b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/BadHttpRequestTests.cs index 65402a019b..380a51188e 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/BadHttpRequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/BadHttpRequestTests.cs @@ -133,7 +133,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests 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) diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs index 8aeb066862..bbac629985 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs @@ -81,25 +81,6 @@ namespace Microsoft.AspNetCore.Server.KestrelTests _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(() => _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] public async Task TakeMessageHeadersThrowsWhenHeadersExceedTotalSizeLimit() { diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/HttpParserTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/HttpParserTests.cs index b63ecc5d83..6ad29a68cb 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/HttpParserTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/HttpParserTests.cs @@ -108,7 +108,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var exception = Assert.Throws(() => parser.ParseRequestLine(Mock.Of(), 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); } @@ -306,7 +306,12 @@ namespace Microsoft.AspNetCore.Server.KestrelTests [MemberData(nameof(RequestHeaderInvalidData))] public void ParseHeadersThrowsOnInvalidRequestHeaders(string rawHeaders, string expectedExceptionMessage) { - var parser = CreateParser(Mock.Of()); + var mockTrace = new Mock(); + mockTrace + .Setup(trace => trace.IsEnabled(LogLevel.Information)) + .Returns(true); + + var parser = CreateParser(mockTrace.Object); var buffer = ReadableBuffer.Create(Encoding.ASCII.GetBytes(rawHeaders)); var exception = Assert.Throws(() => diff --git a/test/shared/HttpParsingData.cs b/test/shared/HttpParsingData.cs index 7d84ba37b3..e999fb3170 100644 --- a/test/shared/HttpParsingData.cs +++ b/test/shared/HttpParsingData.cs @@ -203,106 +203,79 @@ namespace Microsoft.AspNetCore.Testing "8charact", }; - public static IEnumerable RequestHeaderInvalidData + public static IEnumerable RequestHeaderInvalidData => new[] { - get - { - // Line folding - var headersWithLineFolding = new[] - { - "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", - }; + // Missing CR + new[] { "Header: value\n\r\n", @"Invalid request header: 'Header: value\x0A'" }, + new[] { "Header-1: value1\nHeader-2: value2\r\n\r\n", @"Invalid request header: 'Header-1: value1\x0A'" }, + new[] { "Header-1: value1\r\nHeader-2: value2\n\r\n", @"Invalid request header: 'Header-2: value2\x0A'" }, - // CR in value - var headersWithCRInValue = new[] - { - "Header-1: value1\r\r\n", - "Header-1: val\rue1\r\n", - "Header-1: value1\rHeader-2: value2\r\n\r\n", - "Header-1: value1\r\nHeader-2: value2\r\r\n", - "Header-1: value1\r\nHeader-2: v\ralue2\r\n", - "Header-1: Value__\rVector16________Vector32\r\n", - "Header-1: Value___Vector16\r________Vector32\r\n", - "Header-1: Value___Vector16_______\rVector32\r\n", - "Header-1: Value___Vector16________Vector32\r\r\n", - "Header-1: Value___Vector16________Vector32_\r\r\n", - "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", - }; + // Line folding + 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'" }, + 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'" }, + new[] { "Header: line1\r\n\t line2\r\n\r\n", @"Invalid request header: '\x09 line2\x0D\x0A'" }, + new[] { "Header: line1\r\n\t\tline2\r\n\r\n", @"Invalid request header: '\x09\x09line2\x0D\x0A'" }, + new[] { "Header: line1\r\n \t\t line2\r\n\r\n", @"Invalid request header: ' \x09\x09 line2\x0D\x0A'" }, + new[] { "Header: line1\r\n \t \t line2\r\n\r\n", @"Invalid request header: ' \x09 \x09 line2\x0D\x0A'" }, + new[] { "Header-1: multi\r\n line\r\nHeader-2: value2\r\n\r\n", @"Invalid request header: ' line\x0D\x0A'" }, + new[] { "Header-1: value1\r\nHeader-2: multi\r\n line\r\n\r\n", @"Invalid request header: ' line\x0D\x0A'" }, + new[] { "Header-1: value1\r\n Header-2: value2\r\n\r\n", @"Invalid request header: ' Header-2: value2\x0D\x0A'" }, + new[] { "Header-1: value1\r\n\tHeader-2: value2\r\n\r\n", @"Invalid request header: '\x09Header-2: value2\x0D\x0A'" }, - // Missing colon - var headersWithMissingColon = new[] - { - "Header-1 value1\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", - "\n" - }; + // CR in value + 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'" }, + new[] { "Header-1: value1\rHeader-2: value2\r\n\r\n", @"Invalid request header: 'Header-1: value1\x0DHeader-2: value2\x0D\x0A'" }, + new[] { "Header-1: value1\r\nHeader-2: value2\r\r\n", @"Invalid request header: 'Header-2: value2\x0D\x0D\x0A'" }, + new[] { "Header-1: value1\r\nHeader-2: v\ralue2\r\n", @"Invalid request header: 'Header-2: v\x0Dalue2\x0D\x0A'" }, + 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 - var headersStartingWithWhitespace = new[] - { - " Header: value\r\n\r\n", - "\tHeader: value\r\n\r\n", - " Header-1: value1\r\nHeader-2: value2\r\n\r\n", - "\tHeader-1: value1\r\nHeader-2: value2\r\n\r\n", - }; + // Missing colon + 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'" }, + new[] { "Header-1: value1\r\nHeader-2 value2\r\n\r\n", @"Invalid request header: 'Header-2 value2\x0D\x0A'" }, + new[] { "\n", @"Invalid request header: '\x0A'" }, - // Whitespace in header name - var headersWithWithspaceInName = new[] - { - "Header : value\r\n\r\n", - "Header\t: value\r\n\r\n", - "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", - }; + // Starting with whitespace + 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'" }, + new[] { " Header-1: value1\r\nHeader-2: value2\r\n\r\n", @"Invalid request header: ' Header-1: value1\x0D\x0A'" }, + new[] { "\tHeader-1: value1\r\nHeader-2: value2\r\n\r\n", @"Invalid request header: '\x09Header-1: value1\x0D\x0A'" }, - // Headers not ending in CRLF line - var headersNotEndingInCrLfLine = new[] - { - "Header-1: value1\r\nHeader-2: value2\r\n\r\r", - "Header-1: value1\r\nHeader-2: value2\r\n\r ", - "Header-1: value1\r\nHeader-2: value2\r\n\r \n", - }; + // Whitespace in header name + 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'" }, + new[] { "Header\r: value\r\n\r\n", @"Invalid request header: 'Header\x0D: value\x0D\x0A'" }, + new[] { "Header_\rVector16: value\r\n\r\n", @"Invalid request header: 'Header_\x0DVector16: value\x0D\x0A'" }, + 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[] - { - Tuple.Create(headersWithLineFolding, "Whitespace is not allowed in header name."), - Tuple.Create(headersWithCRInValue, "Header value must not contain CR characters."), - 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 })); - } - } + // 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." }, + new[] { "Header-1: value1\r\nHeader-2: value2\r\n\r ", @"Invalid request headers: missing final CRLF in header fields." }, + new[] { "Header-1: value1\r\nHeader-2: value2\r\n\r \n", @"Invalid request headers: missing final CRLF in header fields." }, + }; } }