diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/BadHttpRequestException.cs b/src/Microsoft.AspNetCore.Server.Kestrel/BadHttpRequestException.cs index cb37af76c1..128040c1df 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/BadHttpRequestException.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/BadHttpRequestException.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.IO; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Server.Kestrel.Internal.Http; namespace Microsoft.AspNetCore.Server.Kestrel @@ -22,64 +23,64 @@ namespace Microsoft.AspNetCore.Server.Kestrel switch (reason) { case RequestRejectionReason.HeadersCorruptedInvalidHeaderSequence: - ex = new BadHttpRequestException("Headers corrupted, invalid header sequence.", 400); + ex = new BadHttpRequestException("Headers corrupted, invalid header sequence.", StatusCodes.Status400BadRequest); break; case RequestRejectionReason.HeaderLineMustNotStartWithWhitespace: - ex = new BadHttpRequestException("Header line must not start with whitespace.", 400); + ex = new BadHttpRequestException("Header line must not start with whitespace.", StatusCodes.Status400BadRequest); break; case RequestRejectionReason.NoColonCharacterFoundInHeaderLine: - ex = new BadHttpRequestException("No ':' character found in header line.", 400); + 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.", 400); + 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.", 400); + 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.", 400); + ex = new BadHttpRequestException("Header value line folding not supported.", StatusCodes.Status400BadRequest); break; case RequestRejectionReason.MalformedRequestInvalidHeaders: - ex = new BadHttpRequestException("Malformed request: invalid headers.", 400); + ex = new BadHttpRequestException("Malformed request: invalid headers.", StatusCodes.Status400BadRequest); break; case RequestRejectionReason.UnexpectedEndOfRequestContent: - ex = new BadHttpRequestException("Unexpected end of request content.", 400); + ex = new BadHttpRequestException("Unexpected end of request content.", StatusCodes.Status400BadRequest); break; case RequestRejectionReason.BadChunkSuffix: - ex = new BadHttpRequestException("Bad chunk suffix.", 400); + ex = new BadHttpRequestException("Bad chunk suffix.", StatusCodes.Status400BadRequest); break; case RequestRejectionReason.BadChunkSizeData: - ex = new BadHttpRequestException("Bad chunk size data.", 400); + ex = new BadHttpRequestException("Bad chunk size data.", StatusCodes.Status400BadRequest); break; case RequestRejectionReason.ChunkedRequestIncomplete: - ex = new BadHttpRequestException("Chunked request incomplete.", 400); + ex = new BadHttpRequestException("Chunked request incomplete.", StatusCodes.Status400BadRequest); break; case RequestRejectionReason.PathContainsNullCharacters: - ex = new BadHttpRequestException("The path contains null characters.", 400); + ex = new BadHttpRequestException("The path contains null characters.", StatusCodes.Status400BadRequest); break; case RequestRejectionReason.InvalidCharactersInHeaderName: - ex = new BadHttpRequestException("Invalid characters in header name.", 400); + 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.", 400); + 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.", 414); + ex = new BadHttpRequestException("Request line too long.", StatusCodes.Status414UriTooLong); break; case RequestRejectionReason.HeadersExceedMaxTotalSize: - ex = new BadHttpRequestException("Request headers too long.", 431); + ex = new BadHttpRequestException("Request headers too long.", StatusCodes.Status431RequestHeaderFieldsTooLarge); break; case RequestRejectionReason.MissingCRInHeaderLine: - ex = new BadHttpRequestException("No CR character found in header line.", 400); + ex = new BadHttpRequestException("No CR character found in header line.", StatusCodes.Status400BadRequest); break; case RequestRejectionReason.TooManyHeaders: - ex = new BadHttpRequestException("Request contains too many headers.", 431); + ex = new BadHttpRequestException("Request contains too many headers.", StatusCodes.Status431RequestHeaderFieldsTooLarge); break; case RequestRejectionReason.RequestTimeout: - ex = new BadHttpRequestException("Request timed out.", 408); + ex = new BadHttpRequestException("Request timed out.", StatusCodes.Status408RequestTimeout); break; default: - ex = new BadHttpRequestException("Bad request.", 400); + ex = new BadHttpRequestException("Bad request.", StatusCodes.Status400BadRequest); break; } return ex; @@ -91,25 +92,25 @@ namespace Microsoft.AspNetCore.Server.Kestrel switch (reason) { case RequestRejectionReason.InvalidRequestLine: - ex = new BadHttpRequestException($"Invalid request line: {value}", 400); + ex = new BadHttpRequestException($"Invalid request line: {value}", StatusCodes.Status400BadRequest); break; case RequestRejectionReason.InvalidContentLength: - ex = new BadHttpRequestException($"Invalid content length: {value}", 400); + ex = new BadHttpRequestException($"Invalid content length: {value}", StatusCodes.Status400BadRequest); break; case RequestRejectionReason.UnrecognizedHTTPVersion: - ex = new BadHttpRequestException($"Unrecognized HTTP version: {value}", 505); + ex = new BadHttpRequestException($"Unrecognized HTTP version: {value}", StatusCodes.Status505HttpVersionNotsupported); break; case RequestRejectionReason.FinalTransferCodingNotChunked: - ex = new BadHttpRequestException($"Final transfer coding is not \"chunked\": \"{value}\"", 400); + ex = new BadHttpRequestException($"Final transfer coding is not \"chunked\": \"{value}\"", StatusCodes.Status400BadRequest); break; case RequestRejectionReason.LengthRequired: - ex = new BadHttpRequestException($"{value} request contains no Content-Length or Transfer-Encoding header", 411); + ex = new BadHttpRequestException($"{value} request contains no Content-Length or Transfer-Encoding header", StatusCodes.Status411LengthRequired); break; case RequestRejectionReason.LengthRequiredHttp10: - ex = new BadHttpRequestException($"{value} request contains no Content-Length header", 400); + ex = new BadHttpRequestException($"{value} request contains no Content-Length header", StatusCodes.Status400BadRequest); break; default: - ex = new BadHttpRequestException("Bad request.", 400); + ex = new BadHttpRequestException("Bad request.", StatusCodes.Status400BadRequest); break; } return ex; diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.FeatureCollection.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.FeatureCollection.cs index 9480147f95..66be41e7e0 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.FeatureCollection.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.FeatureCollection.cs @@ -323,7 +323,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http async Task IHttpUpgradeFeature.UpgradeAsync() { - StatusCode = 101; + StatusCode = StatusCodes.Status101SwitchingProtocols; ReasonPhrase = "Switching Protocols"; ResponseHeaders["Connection"] = "Upgrade"; if (!ResponseHeaders.ContainsKey("Upgrade")) diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.cs index dfc49447b9..fc4ba2b202 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.cs @@ -141,7 +141,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http set { // GetKnownVersion returns versions which ReferenceEquals interned string - // As most common path, check for this only in fast-path and inline + // As most common path, check for this only in fast-path and inline if (ReferenceEquals(value, "HTTP/1.1")) { _httpVersion = Http.HttpVersion.Http11; @@ -347,7 +347,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http Path = null; QueryString = null; _httpVersion = Http.HttpVersion.Unset; - StatusCode = 200; + StatusCode = StatusCodes.Status200OK; ReasonPhrase = null; RemoteIpAddress = RemoteEndPoint?.Address; @@ -816,7 +816,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http else { // 500 Internal Server Error - SetErrorResponseHeaders(statusCode: 500); + SetErrorResponseHeaders(statusCode: StatusCodes.Status500InternalServerError); } } @@ -909,7 +909,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http { if (!hasTransferEncoding && !responseHeaders.HasContentLength) { - if (appCompleted && StatusCode != 101) + if (appCompleted && StatusCode != StatusCodes.Status101SwitchingProtocols) { // Since the app has completed and we are only now generating // the headers we can safely set the Content-Length to 0. @@ -924,7 +924,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http // // A server MUST NOT send a response containing Transfer-Encoding unless the corresponding // request indicates HTTP/1.1 (or later). - if (_httpVersion == Http.HttpVersion.Http11 && StatusCode != 101) + if (_httpVersion == Http.HttpVersion.Http11 && StatusCode != StatusCodes.Status101SwitchingProtocols) { _autoChunk = true; responseHeaders.SetRawTransferEncoding("chunked", _bytesTransferEncodingChunked); @@ -1410,9 +1410,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http public bool StatusCanHaveBody(int statusCode) { // List of status codes taken from Microsoft.Net.Http.Server.Response - return statusCode != 204 && - statusCode != 205 && - statusCode != 304; + return statusCode != StatusCodes.Status204NoContent && + statusCode != StatusCodes.Status205ResetContent && + statusCode != StatusCodes.Status304NotModified; } private void ThrowResponseAlreadyStartedException(string value) @@ -1434,7 +1434,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http ReportApplicationError(ex); // 500 Internal Server Error - SetErrorResponseHeaders(statusCode: 500); + SetErrorResponseHeaders(statusCode: StatusCodes.Status500InternalServerError); } } diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ReasonPhrases.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ReasonPhrases.cs index c7d52fc91c..d3e916606e 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ReasonPhrases.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ReasonPhrases.cs @@ -1,68 +1,89 @@ // 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.Diagnostics; using System.Globalization; using System.Text; +using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http { public static class ReasonPhrases { - private static readonly byte[] _bytesStatus100 = Encoding.ASCII.GetBytes("100 Continue"); - private static readonly byte[] _bytesStatus101 = Encoding.ASCII.GetBytes("101 Switching Protocols"); - private static readonly byte[] _bytesStatus102 = Encoding.ASCII.GetBytes("102 Processing"); - private static readonly byte[] _bytesStatus200 = Encoding.ASCII.GetBytes("200 OK"); - private static readonly byte[] _bytesStatus201 = Encoding.ASCII.GetBytes("201 Created"); - private static readonly byte[] _bytesStatus202 = Encoding.ASCII.GetBytes("202 Accepted"); - private static readonly byte[] _bytesStatus203 = Encoding.ASCII.GetBytes("203 Non-Authoritative Information"); - private static readonly byte[] _bytesStatus204 = Encoding.ASCII.GetBytes("204 No Content"); - private static readonly byte[] _bytesStatus205 = Encoding.ASCII.GetBytes("205 Reset Content"); - private static readonly byte[] _bytesStatus206 = Encoding.ASCII.GetBytes("206 Partial Content"); - private static readonly byte[] _bytesStatus207 = Encoding.ASCII.GetBytes("207 Multi-Status"); - private static readonly byte[] _bytesStatus226 = Encoding.ASCII.GetBytes("226 IM Used"); - private static readonly byte[] _bytesStatus300 = Encoding.ASCII.GetBytes("300 Multiple Choices"); - private static readonly byte[] _bytesStatus301 = Encoding.ASCII.GetBytes("301 Moved Permanently"); - private static readonly byte[] _bytesStatus302 = Encoding.ASCII.GetBytes("302 Found"); - private static readonly byte[] _bytesStatus303 = Encoding.ASCII.GetBytes("303 See Other"); - private static readonly byte[] _bytesStatus304 = Encoding.ASCII.GetBytes("304 Not Modified"); - private static readonly byte[] _bytesStatus305 = Encoding.ASCII.GetBytes("305 Use Proxy"); - private static readonly byte[] _bytesStatus306 = Encoding.ASCII.GetBytes("306 Reserved"); - private static readonly byte[] _bytesStatus307 = Encoding.ASCII.GetBytes("307 Temporary Redirect"); - private static readonly byte[] _bytesStatus308 = Encoding.ASCII.GetBytes("308 Permanent Redirect"); - private static readonly byte[] _bytesStatus400 = Encoding.ASCII.GetBytes("400 Bad Request"); - private static readonly byte[] _bytesStatus401 = Encoding.ASCII.GetBytes("401 Unauthorized"); - private static readonly byte[] _bytesStatus402 = Encoding.ASCII.GetBytes("402 Payment Required"); - private static readonly byte[] _bytesStatus403 = Encoding.ASCII.GetBytes("403 Forbidden"); - private static readonly byte[] _bytesStatus404 = Encoding.ASCII.GetBytes("404 Not Found"); - private static readonly byte[] _bytesStatus405 = Encoding.ASCII.GetBytes("405 Method Not Allowed"); - private static readonly byte[] _bytesStatus406 = Encoding.ASCII.GetBytes("406 Not Acceptable"); - private static readonly byte[] _bytesStatus407 = Encoding.ASCII.GetBytes("407 Proxy Authentication Required"); - private static readonly byte[] _bytesStatus408 = Encoding.ASCII.GetBytes("408 Request Timeout"); - private static readonly byte[] _bytesStatus409 = Encoding.ASCII.GetBytes("409 Conflict"); - private static readonly byte[] _bytesStatus410 = Encoding.ASCII.GetBytes("410 Gone"); - private static readonly byte[] _bytesStatus411 = Encoding.ASCII.GetBytes("411 Length Required"); - private static readonly byte[] _bytesStatus412 = Encoding.ASCII.GetBytes("412 Precondition Failed"); - private static readonly byte[] _bytesStatus413 = Encoding.ASCII.GetBytes("413 Payload Too Large"); - private static readonly byte[] _bytesStatus414 = Encoding.ASCII.GetBytes("414 URI Too Long"); - private static readonly byte[] _bytesStatus415 = Encoding.ASCII.GetBytes("415 Unsupported Media Type"); - private static readonly byte[] _bytesStatus416 = Encoding.ASCII.GetBytes("416 Range Not Satisfiable"); - private static readonly byte[] _bytesStatus417 = Encoding.ASCII.GetBytes("417 Expectation Failed"); - private static readonly byte[] _bytesStatus418 = Encoding.ASCII.GetBytes("418 I'm a Teapot"); - private static readonly byte[] _bytesStatus422 = Encoding.ASCII.GetBytes("422 Unprocessable Entity"); - private static readonly byte[] _bytesStatus423 = Encoding.ASCII.GetBytes("423 Locked"); - private static readonly byte[] _bytesStatus424 = Encoding.ASCII.GetBytes("424 Failed Dependency"); - private static readonly byte[] _bytesStatus426 = Encoding.ASCII.GetBytes("426 Upgrade Required"); - private static readonly byte[] _bytesStatus431 = Encoding.ASCII.GetBytes("431 Request Header Fields Too Large"); - private static readonly byte[] _bytesStatus451 = Encoding.ASCII.GetBytes("451 Unavailable For Legal Reasons"); - private static readonly byte[] _bytesStatus500 = Encoding.ASCII.GetBytes("500 Internal Server Error"); - private static readonly byte[] _bytesStatus501 = Encoding.ASCII.GetBytes("501 Not Implemented"); - private static readonly byte[] _bytesStatus502 = Encoding.ASCII.GetBytes("502 Bad Gateway"); - private static readonly byte[] _bytesStatus503 = Encoding.ASCII.GetBytes("503 Service Unavailable"); - private static readonly byte[] _bytesStatus504 = Encoding.ASCII.GetBytes("504 Gateway Timeout"); - private static readonly byte[] _bytesStatus505 = Encoding.ASCII.GetBytes("505 HTTP Version Not Supported"); - private static readonly byte[] _bytesStatus506 = Encoding.ASCII.GetBytes("506 Variant Also Negotiates"); - private static readonly byte[] _bytesStatus507 = Encoding.ASCII.GetBytes("507 Insufficient Storage"); - private static readonly byte[] _bytesStatus510 = Encoding.ASCII.GetBytes("510 Not Extended"); + private static readonly byte[] _bytesStatus100 = CreateStatusBytes(StatusCodes.Status100Continue); + private static readonly byte[] _bytesStatus101 = CreateStatusBytes(StatusCodes.Status101SwitchingProtocols); + private static readonly byte[] _bytesStatus102 = CreateStatusBytes(StatusCodes.Status102Processing); + + private static readonly byte[] _bytesStatus200 = CreateStatusBytes(StatusCodes.Status200OK); + private static readonly byte[] _bytesStatus201 = CreateStatusBytes(StatusCodes.Status201Created); + private static readonly byte[] _bytesStatus202 = CreateStatusBytes(StatusCodes.Status202Accepted); + private static readonly byte[] _bytesStatus203 = CreateStatusBytes(StatusCodes.Status203NonAuthoritative); + private static readonly byte[] _bytesStatus204 = CreateStatusBytes(StatusCodes.Status204NoContent); + private static readonly byte[] _bytesStatus205 = CreateStatusBytes(StatusCodes.Status205ResetContent); + private static readonly byte[] _bytesStatus206 = CreateStatusBytes(StatusCodes.Status206PartialContent); + private static readonly byte[] _bytesStatus207 = CreateStatusBytes(StatusCodes.Status207MultiStatus); + private static readonly byte[] _bytesStatus208 = CreateStatusBytes(StatusCodes.Status208AlreadyReported); + private static readonly byte[] _bytesStatus226 = CreateStatusBytes(StatusCodes.Status226IMUsed); + + private static readonly byte[] _bytesStatus300 = CreateStatusBytes(StatusCodes.Status300MultipleChoices); + private static readonly byte[] _bytesStatus301 = CreateStatusBytes(StatusCodes.Status301MovedPermanently); + private static readonly byte[] _bytesStatus302 = CreateStatusBytes(StatusCodes.Status302Found); + private static readonly byte[] _bytesStatus303 = CreateStatusBytes(StatusCodes.Status303SeeOther); + private static readonly byte[] _bytesStatus304 = CreateStatusBytes(StatusCodes.Status304NotModified); + private static readonly byte[] _bytesStatus305 = CreateStatusBytes(StatusCodes.Status305UseProxy); + private static readonly byte[] _bytesStatus306 = CreateStatusBytes(StatusCodes.Status306SwitchProxy); + private static readonly byte[] _bytesStatus307 = CreateStatusBytes(StatusCodes.Status307TemporaryRedirect); + private static readonly byte[] _bytesStatus308 = CreateStatusBytes(StatusCodes.Status308PermanentRedirect); + + private static readonly byte[] _bytesStatus400 = CreateStatusBytes(StatusCodes.Status400BadRequest); + private static readonly byte[] _bytesStatus401 = CreateStatusBytes(StatusCodes.Status401Unauthorized); + private static readonly byte[] _bytesStatus402 = CreateStatusBytes(StatusCodes.Status402PaymentRequired); + private static readonly byte[] _bytesStatus403 = CreateStatusBytes(StatusCodes.Status403Forbidden); + private static readonly byte[] _bytesStatus404 = CreateStatusBytes(StatusCodes.Status404NotFound); + private static readonly byte[] _bytesStatus405 = CreateStatusBytes(StatusCodes.Status405MethodNotAllowed); + private static readonly byte[] _bytesStatus406 = CreateStatusBytes(StatusCodes.Status406NotAcceptable); + private static readonly byte[] _bytesStatus407 = CreateStatusBytes(StatusCodes.Status407ProxyAuthenticationRequired); + private static readonly byte[] _bytesStatus408 = CreateStatusBytes(StatusCodes.Status408RequestTimeout); + private static readonly byte[] _bytesStatus409 = CreateStatusBytes(StatusCodes.Status409Conflict); + private static readonly byte[] _bytesStatus410 = CreateStatusBytes(StatusCodes.Status410Gone); + private static readonly byte[] _bytesStatus411 = CreateStatusBytes(StatusCodes.Status411LengthRequired); + private static readonly byte[] _bytesStatus412 = CreateStatusBytes(StatusCodes.Status412PreconditionFailed); + private static readonly byte[] _bytesStatus413 = CreateStatusBytes(StatusCodes.Status413PayloadTooLarge); + private static readonly byte[] _bytesStatus414 = CreateStatusBytes(StatusCodes.Status414UriTooLong); + private static readonly byte[] _bytesStatus415 = CreateStatusBytes(StatusCodes.Status415UnsupportedMediaType); + private static readonly byte[] _bytesStatus416 = CreateStatusBytes(StatusCodes.Status416RangeNotSatisfiable); + private static readonly byte[] _bytesStatus417 = CreateStatusBytes(StatusCodes.Status417ExpectationFailed); + private static readonly byte[] _bytesStatus418 = CreateStatusBytes(StatusCodes.Status418ImATeapot); + private static readonly byte[] _bytesStatus419 = CreateStatusBytes(StatusCodes.Status419AuthenticationTimeout); + private static readonly byte[] _bytesStatus421 = CreateStatusBytes(StatusCodes.Status421MisdirectedRequest); + private static readonly byte[] _bytesStatus422 = CreateStatusBytes(StatusCodes.Status422UnprocessableEntity); + private static readonly byte[] _bytesStatus423 = CreateStatusBytes(StatusCodes.Status423Locked); + private static readonly byte[] _bytesStatus424 = CreateStatusBytes(StatusCodes.Status424FailedDependency); + private static readonly byte[] _bytesStatus426 = CreateStatusBytes(StatusCodes.Status426UpgradeRequired); + private static readonly byte[] _bytesStatus428 = CreateStatusBytes(StatusCodes.Status428PreconditionRequired); + private static readonly byte[] _bytesStatus429 = CreateStatusBytes(StatusCodes.Status429TooManyRequests); + private static readonly byte[] _bytesStatus431 = CreateStatusBytes(StatusCodes.Status431RequestHeaderFieldsTooLarge); + private static readonly byte[] _bytesStatus451 = CreateStatusBytes(StatusCodes.Status451UnavailableForLegalReasons); + + private static readonly byte[] _bytesStatus500 = CreateStatusBytes(StatusCodes.Status500InternalServerError); + private static readonly byte[] _bytesStatus501 = CreateStatusBytes(StatusCodes.Status501NotImplemented); + private static readonly byte[] _bytesStatus502 = CreateStatusBytes(StatusCodes.Status502BadGateway); + private static readonly byte[] _bytesStatus503 = CreateStatusBytes(StatusCodes.Status503ServiceUnavailable); + private static readonly byte[] _bytesStatus504 = CreateStatusBytes(StatusCodes.Status504GatewayTimeout); + private static readonly byte[] _bytesStatus505 = CreateStatusBytes(StatusCodes.Status505HttpVersionNotsupported); + private static readonly byte[] _bytesStatus506 = CreateStatusBytes(StatusCodes.Status506VariantAlsoNegotiates); + private static readonly byte[] _bytesStatus507 = CreateStatusBytes(StatusCodes.Status507InsufficientStorage); + private static readonly byte[] _bytesStatus508 = CreateStatusBytes(StatusCodes.Status508LoopDetected); + private static readonly byte[] _bytesStatus510 = CreateStatusBytes(StatusCodes.Status510NotExtended); + private static readonly byte[] _bytesStatus511 = CreateStatusBytes(StatusCodes.Status511NetworkAuthenticationRequired); + + private static byte[] CreateStatusBytes(int statusCode) + { + var reasonPhrase = WebUtilities.ReasonPhrases.GetReasonPhrase(statusCode); + Debug.Assert(!string.IsNullOrEmpty(reasonPhrase)); + + return Encoding.ASCII.GetBytes(statusCode.ToString(CultureInfo.InvariantCulture) + " " + reasonPhrase); + } public static byte[] ToStatusBytes(int statusCode, string reasonPhrase = null) { @@ -70,118 +91,141 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http { switch (statusCode) { - case 100: + case StatusCodes.Status100Continue: return _bytesStatus100; - case 101: + case StatusCodes.Status101SwitchingProtocols: return _bytesStatus101; - case 102: + case StatusCodes.Status102Processing: return _bytesStatus102; - case 200: + + case StatusCodes.Status200OK: return _bytesStatus200; - case 201: + case StatusCodes.Status201Created: return _bytesStatus201; - case 202: + case StatusCodes.Status202Accepted: return _bytesStatus202; - case 203: + case StatusCodes.Status203NonAuthoritative: return _bytesStatus203; - case 204: + case StatusCodes.Status204NoContent: return _bytesStatus204; - case 205: + case StatusCodes.Status205ResetContent: return _bytesStatus205; - case 206: + case StatusCodes.Status206PartialContent: return _bytesStatus206; - case 207: + case StatusCodes.Status207MultiStatus: return _bytesStatus207; - case 226: + case StatusCodes.Status208AlreadyReported: + return _bytesStatus208; + case StatusCodes.Status226IMUsed: return _bytesStatus226; - case 300: + + case StatusCodes.Status300MultipleChoices: return _bytesStatus300; - case 301: + case StatusCodes.Status301MovedPermanently: return _bytesStatus301; - case 302: + case StatusCodes.Status302Found: return _bytesStatus302; - case 303: + case StatusCodes.Status303SeeOther: return _bytesStatus303; - case 304: + case StatusCodes.Status304NotModified: return _bytesStatus304; - case 305: + case StatusCodes.Status305UseProxy: return _bytesStatus305; - case 306: + case StatusCodes.Status306SwitchProxy: return _bytesStatus306; - case 307: + case StatusCodes.Status307TemporaryRedirect: return _bytesStatus307; - case 308: + case StatusCodes.Status308PermanentRedirect: return _bytesStatus308; - case 400: + + case StatusCodes.Status400BadRequest: return _bytesStatus400; - case 401: + case StatusCodes.Status401Unauthorized: return _bytesStatus401; - case 402: + case StatusCodes.Status402PaymentRequired: return _bytesStatus402; - case 403: + case StatusCodes.Status403Forbidden: return _bytesStatus403; - case 404: + case StatusCodes.Status404NotFound: return _bytesStatus404; - case 405: + case StatusCodes.Status405MethodNotAllowed: return _bytesStatus405; - case 406: + case StatusCodes.Status406NotAcceptable: return _bytesStatus406; - case 407: + case StatusCodes.Status407ProxyAuthenticationRequired: return _bytesStatus407; - case 408: + case StatusCodes.Status408RequestTimeout: return _bytesStatus408; - case 409: + case StatusCodes.Status409Conflict: return _bytesStatus409; - case 410: + case StatusCodes.Status410Gone: return _bytesStatus410; - case 411: + case StatusCodes.Status411LengthRequired: return _bytesStatus411; - case 412: + case StatusCodes.Status412PreconditionFailed: return _bytesStatus412; - case 413: + case StatusCodes.Status413PayloadTooLarge: return _bytesStatus413; - case 414: + case StatusCodes.Status414UriTooLong: return _bytesStatus414; - case 415: + case StatusCodes.Status415UnsupportedMediaType: return _bytesStatus415; - case 416: + case StatusCodes.Status416RangeNotSatisfiable: return _bytesStatus416; - case 417: + case StatusCodes.Status417ExpectationFailed: return _bytesStatus417; - case 418: + case StatusCodes.Status418ImATeapot: return _bytesStatus418; - case 422: + case StatusCodes.Status419AuthenticationTimeout: + return _bytesStatus419; + case StatusCodes.Status421MisdirectedRequest: + return _bytesStatus421; + case StatusCodes.Status422UnprocessableEntity: return _bytesStatus422; - case 423: + case StatusCodes.Status423Locked: return _bytesStatus423; - case 424: + case StatusCodes.Status424FailedDependency: return _bytesStatus424; - case 426: + case StatusCodes.Status426UpgradeRequired: return _bytesStatus426; - case 431: + case StatusCodes.Status428PreconditionRequired: + return _bytesStatus428; + case StatusCodes.Status429TooManyRequests: + return _bytesStatus429; + case StatusCodes.Status431RequestHeaderFieldsTooLarge: return _bytesStatus431; - case 451: + case StatusCodes.Status451UnavailableForLegalReasons: return _bytesStatus451; - case 500: + + case StatusCodes.Status500InternalServerError: return _bytesStatus500; - case 501: + case StatusCodes.Status501NotImplemented: return _bytesStatus501; - case 502: + case StatusCodes.Status502BadGateway: return _bytesStatus502; - case 503: + case StatusCodes.Status503ServiceUnavailable: return _bytesStatus503; - case 504: + case StatusCodes.Status504GatewayTimeout: return _bytesStatus504; - case 505: + case StatusCodes.Status505HttpVersionNotsupported: return _bytesStatus505; - case 506: + case StatusCodes.Status506VariantAlsoNegotiates: return _bytesStatus506; - case 507: + case StatusCodes.Status507InsufficientStorage: return _bytesStatus507; - case 510: + case StatusCodes.Status508LoopDetected: + return _bytesStatus508; + case StatusCodes.Status510NotExtended: return _bytesStatus510; + case StatusCodes.Status511NetworkAuthenticationRequired: + return _bytesStatus511; + default: - return Encoding.ASCII.GetBytes(statusCode.ToString(CultureInfo.InvariantCulture) + " Unknown"); + var predefinedReasonPhrase = WebUtilities.ReasonPhrases.GetReasonPhrase(statusCode); + return string.IsNullOrEmpty(predefinedReasonPhrase) + ? Encoding.ASCII.GetBytes(statusCode.ToString(CultureInfo.InvariantCulture)) + : Encoding.ASCII.GetBytes(statusCode.ToString(CultureInfo.InvariantCulture) + " " + predefinedReasonPhrase); + } } return Encoding.ASCII.GetBytes(statusCode.ToString(CultureInfo.InvariantCulture) + " " + reasonPhrase); diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/HttpClientSlimTests.cs b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/HttpClientSlimTests.cs index ab8f3a5c02..76cd68c918 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/HttpClientSlimTests.cs +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/HttpClientSlimTests.cs @@ -39,7 +39,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests [Fact] public async Task GetStringAsyncThrowsForErrorResponse() { - using (var host = StartHost(statusCode: 500)) + using (var host = StartHost(statusCode: StatusCodes.Status500InternalServerError)) { await Assert.ThrowsAnyAsync(() => HttpClientSlim.GetStringAsync(host.GetUri())); } @@ -68,14 +68,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests [Fact] public async Task PostAsyncThrowsForErrorResponse() { - using (var host = StartHost(statusCode: 500)) + using (var host = StartHost(statusCode: StatusCodes.Status500InternalServerError)) { await Assert.ThrowsAnyAsync( () => HttpClientSlim.PostAsync(host.GetUri(), new StringContent(""))); } } - private IWebHost StartHost(string protocol = "http", int statusCode = 200, Func handler = null) + private IWebHost StartHost(string protocol = "http", int statusCode = StatusCodes.Status200OK, Func handler = null) { var host = new WebHostBuilder() .UseKestrel(options => diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/MaxRequestBufferSizeTests.cs b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/MaxRequestBufferSizeTests.cs index 0fea1d1ee4..3449b08b51 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/MaxRequestBufferSizeTests.cs +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/MaxRequestBufferSizeTests.cs @@ -118,13 +118,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests // The maximum is harder to determine, since there can be OS-level buffers in both the client // and server, which allow the client to send more than maxRequestBufferSize before getting // paused. We assume the combined buffers are smaller than the difference between - // data.Length and maxRequestBufferSize. + // data.Length and maxRequestBufferSize. var maximumExpectedBytesWritten = data.Length - 1; // Block until the send task has gone a while without writing bytes AND // the bytes written exceeds the minimum expected. This indicates the server buffer // is full. - // + // // If the send task is paused before the expected number of bytes have been // written, keep waiting since the pause may have been caused by something else // like a slow machine. @@ -200,7 +200,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests // Verify client didn't send extra bytes if (context.Request.Body.ReadByte() != -1) { - context.Response.StatusCode = 500; + context.Response.StatusCode = StatusCodes.Status500InternalServerError; await context.Response.WriteAsync("Client sent more bytes than expectedBody.Length"); return; } @@ -210,7 +210,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests { if (buffer[i] != expectedBody[i]) { - context.Response.StatusCode = 500; + context.Response.StatusCode = StatusCodes.Status500InternalServerError; await context.Response.WriteAsync($"Bytes received do not match expectedBody at position {i}"); return; } diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/ResponseTests.cs index 468b6ef9b4..31ffb191ec 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/ResponseTests.cs @@ -395,9 +395,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests } [Theory] - [InlineData(204)] - [InlineData(205)] - [InlineData(304)] + [InlineData(StatusCodes.Status204NoContent)] + [InlineData(StatusCodes.Status205ResetContent)] + [InlineData(StatusCodes.Status304NotModified)] public async Task TransferEncodingChunkedNotSetOnNonBodyResponse(int statusCode) { using (var server = new TestServer(httpContext => @@ -906,7 +906,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests catch (BadHttpRequestException ex) { expectedResponse = ex.Message; - httpContext.Response.StatusCode = 400; + httpContext.Response.StatusCode = StatusCodes.Status400BadRequest; httpContext.Response.ContentLength = ex.Message.Length; await httpContext.Response.WriteAsync(ex.Message); responseWritten.Release(); diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/FrameRequestHeadersTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/FrameRequestHeadersTests.cs index 44e421191d..b19ca07124 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/FrameRequestHeadersTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/FrameRequestHeadersTests.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Text; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Server.Kestrel; using Microsoft.AspNetCore.Server.Kestrel.Internal.Http; using Microsoft.Extensions.Primitives; @@ -248,7 +249,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var encoding = Encoding.GetEncoding("iso-8859-1"); var exception = Assert.Throws( () => headers.Append(encoding.GetBytes(key), 0, encoding.GetByteCount(key), key)); - Assert.Equal(400, exception.StatusCode); + Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode); } } } diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs index 5bf5fabb26..abbed6dfaa 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs @@ -8,6 +8,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.Kestrel; using Microsoft.AspNetCore.Server.Kestrel.Internal; @@ -189,7 +190,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var exception = Assert.Throws(() => _frame.TakeMessageHeaders(_socketInput, (FrameRequestHeaders)_frame.RequestHeaders)); Assert.Equal("Header value line folding not supported.", exception.Message); - Assert.Equal(400, exception.StatusCode); + Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode); } [Fact] @@ -204,7 +205,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var exception = Assert.Throws(() => _frame.TakeMessageHeaders(_socketInput, (FrameRequestHeaders)_frame.RequestHeaders)); Assert.Equal("Header value line folding not supported.", exception.Message); - Assert.Equal(400, exception.StatusCode); + Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode); } [Theory] @@ -221,7 +222,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var exception = Assert.Throws(() => _frame.TakeMessageHeaders(_socketInput, (FrameRequestHeaders)_frame.RequestHeaders)); Assert.Equal("Header value must not contain CR characters.", exception.Message); - Assert.Equal(400, exception.StatusCode); + Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode); } [Theory] @@ -235,7 +236,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var exception = Assert.Throws(() => _frame.TakeMessageHeaders(_socketInput, (FrameRequestHeaders)_frame.RequestHeaders)); Assert.Equal("No ':' character found in header line.", exception.Message); - Assert.Equal(400, exception.StatusCode); + Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode); } [Theory] @@ -250,7 +251,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var exception = Assert.Throws(() => _frame.TakeMessageHeaders(_socketInput, (FrameRequestHeaders)_frame.RequestHeaders)); Assert.Equal("Header line must not start with whitespace.", exception.Message); - Assert.Equal(400, exception.StatusCode); + Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode); } [Theory] @@ -269,7 +270,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var exception = Assert.Throws(() => _frame.TakeMessageHeaders(_socketInput, (FrameRequestHeaders)_frame.RequestHeaders)); Assert.Equal("Whitespace is not allowed in header name.", exception.Message); - Assert.Equal(400, exception.StatusCode); + Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode); } [Theory] @@ -283,7 +284,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var exception = Assert.Throws(() => _frame.TakeMessageHeaders(_socketInput, (FrameRequestHeaders)_frame.RequestHeaders)); Assert.Equal("Headers corrupted, invalid header sequence.", exception.Message); - Assert.Equal(400, exception.StatusCode); + Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode); } [Fact] @@ -298,7 +299,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var exception = Assert.Throws(() => _frame.TakeMessageHeaders(_socketInput, (FrameRequestHeaders)_frame.RequestHeaders)); Assert.Equal("Request headers too long.", exception.Message); - Assert.Equal(431, exception.StatusCode); + Assert.Equal(StatusCodes.Status431RequestHeaderFieldsTooLarge, exception.StatusCode); } [Fact] @@ -312,7 +313,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var exception = Assert.Throws(() => _frame.TakeMessageHeaders(_socketInput, (FrameRequestHeaders)_frame.RequestHeaders)); Assert.Equal("Request contains too many headers.", exception.Message); - Assert.Equal(431, exception.StatusCode); + Assert.Equal(StatusCodes.Status431RequestHeaderFieldsTooLarge, exception.StatusCode); } [Theory] @@ -385,7 +386,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests // Assert Assert.True(_frame.HasResponseStarted); - Assert.Throws(() => ((IHttpResponseFeature)_frame).StatusCode = 404); + Assert.Throws(() => ((IHttpResponseFeature)_frame).StatusCode = StatusCodes.Status404NotFound); } [Fact] @@ -534,7 +535,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var exception = Assert.Throws(() => _frame.TakeStartLine(_socketInput)); Assert.Equal("Request line too long.", exception.Message); - Assert.Equal(414, exception.StatusCode); + Assert.Equal(StatusCodes.Status414UriTooLong, exception.StatusCode); } [Theory] @@ -556,7 +557,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var exception = Assert.Throws(() => _frame.TakeStartLine(_socketInput)); Assert.Equal(expectedExceptionMessage, exception.Message); - Assert.Equal(400, exception.StatusCode); + Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode); } [Fact] @@ -567,7 +568,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var exception = Assert.Throws(() => _frame.TakeStartLine(_socketInput)); Assert.Equal("Unrecognized HTTP version: HTTP/1.2", exception.Message); - Assert.Equal(505, exception.StatusCode); + Assert.Equal(StatusCodes.Status505HttpVersionNotsupported, exception.StatusCode); } [Fact] @@ -578,7 +579,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var exception = Assert.Throws(() => _frame.TakeStartLine(_socketInput)); Assert.Equal("Unrecognized HTTP version: HTTP/1.1a...", exception.Message); - Assert.Equal(505, exception.StatusCode); + Assert.Equal(StatusCodes.Status505HttpVersionNotsupported, exception.StatusCode); } [Fact] @@ -647,7 +648,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests public void WriteThrowsForNonBodyResponse() { // Arrange - ((IHttpResponseFeature)_frame).StatusCode = 304; + ((IHttpResponseFeature)_frame).StatusCode = StatusCodes.Status304NotModified; // Act/Assert Assert.Throws(() => _frame.Write(new ArraySegment(new byte[1]))); @@ -658,7 +659,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests { // Arrange _frame.HttpVersion = "HTTP/1.1"; - ((IHttpResponseFeature)_frame).StatusCode = 304; + ((IHttpResponseFeature)_frame).StatusCode = StatusCodes.Status304NotModified; // Act/Assert await Assert.ThrowsAsync(() => _frame.WriteAsync(new ArraySegment(new byte[1]), default(CancellationToken))); @@ -705,7 +706,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests { // Arrange _frame.HttpVersion = "HTTP/1.1"; - ((IHttpResponseFeature)_frame).StatusCode = 304; + ((IHttpResponseFeature)_frame).StatusCode = StatusCodes.Status304NotModified; // Act _frame.ResponseHeaders.Add("Transfer-Encoding", "chunked"); diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/MessageBodyTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/MessageBodyTests.cs index e0f8dac560..3e11350d40 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/MessageBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/MessageBodyTests.cs @@ -8,13 +8,14 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Server.Kestrel; using Microsoft.AspNetCore.Server.Kestrel.Internal.Http; +using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.Internal; using Moq; using Xunit; using Xunit.Sdk; -using Microsoft.AspNetCore.Testing; namespace Microsoft.AspNetCore.Server.KestrelTests { @@ -198,7 +199,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var ex = Assert.Throws(() => MessageBody.For(HttpVersion.Http11, new FrameRequestHeaders { HeaderTransferEncoding = "chunked, not-chunked" }, input.FrameContext)); - Assert.Equal(400, ex.StatusCode); + Assert.Equal(StatusCodes.Status400BadRequest, ex.StatusCode); Assert.Equal("Final transfer coding is not \"chunked\": \"chunked, not-chunked\"", ex.Message); } } @@ -214,7 +215,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var ex = Assert.Throws(() => MessageBody.For(HttpVersion.Http11, new FrameRequestHeaders(), input.FrameContext)); - Assert.Equal(411, ex.StatusCode); + Assert.Equal(StatusCodes.Status411LengthRequired, ex.StatusCode); Assert.Equal($"{method} request contains no Content-Length or Transfer-Encoding header", ex.Message); } } @@ -230,7 +231,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var ex = Assert.Throws(() => MessageBody.For(HttpVersion.Http10, new FrameRequestHeaders(), input.FrameContext)); - Assert.Equal(400, ex.StatusCode); + Assert.Equal(StatusCodes.Status400BadRequest, ex.StatusCode); Assert.Equal($"{method} request contains no Content-Length header", ex.Message); } } @@ -249,7 +250,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests new object[] { new FrameRequestHeaders { HeaderTransferEncoding = "chunked" }, new[] { "6\r\nHello \r\n", "6\r\nWorld!\r\n0\r\n\r\n" } }, }; - public static IEnumerable CombinedData => + public static IEnumerable CombinedData => from stream in StreamData from request in RequestData select new[] { stream[0], request[0], request[1] };