diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/BadHttpRequestException.cs b/src/Microsoft.AspNetCore.Server.Kestrel/BadHttpRequestException.cs index 775fb2344d..2b4aa25f12 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/BadHttpRequestException.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/BadHttpRequestException.cs @@ -99,6 +99,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel case RequestRejectionReason.UnrecognizedHTTPVersion: ex = new BadHttpRequestException($"Unrecognized HTTP version: {value}", 505); break; + case RequestRejectionReason.FinalTransferCodingNotChunked: + ex = new BadHttpRequestException($"Final transfer coding is not \"chunked\": \"{value}\"", 400); + break; default: ex = new BadHttpRequestException("Bad request.", 400); break; diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.cs index c6f90a2858..be3f0f083b 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.cs @@ -811,7 +811,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http { var responseHeaders = FrameResponseHeaders; var hasConnection = responseHeaders.HasConnection; - var connectionOptions = hasConnection ? FrameHeaders.ParseConnection(responseHeaders.HeaderConnection) : ConnectionOptions.None; + var connectionOptions = FrameHeaders.ParseConnection(responseHeaders.HeaderConnection); + var hasTransferEncoding = responseHeaders.HasTransferEncoding; + var transferCoding = FrameHeaders.GetFinalTransferCoding(responseHeaders.HeaderTransferEncoding); var end = SocketOutput.ProducingStart(); @@ -820,6 +822,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http _keepAlive = (connectionOptions & ConnectionOptions.KeepAlive) == ConnectionOptions.KeepAlive; } + // https://tools.ietf.org/html/rfc7230#section-3.3.1 + // If any transfer coding other than + // chunked is applied to a response payload body, the sender MUST either + // apply chunked as the final transfer coding or terminate the message + // by closing the connection. + if (hasTransferEncoding && transferCoding != TransferCoding.Chunked) + { + _keepAlive = false; + } + // Set whether response can have body _canHaveBody = StatusCanHaveBody(StatusCode) && Method != "HEAD"; @@ -827,7 +839,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http // automatically for HEAD requests or 204, 205, 304 responses. if (_canHaveBody) { - if (!responseHeaders.HasTransferEncoding && !responseHeaders.HasContentLength) + if (!hasTransferEncoding && !responseHeaders.HasContentLength) { if (appCompleted && StatusCode != 101) { @@ -856,12 +868,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http } } } - else + else if (hasTransferEncoding) { - if (responseHeaders.HasTransferEncoding) - { - RejectNonBodyTransferEncodingResponse(appCompleted); - } + RejectNonBodyTransferEncodingResponse(appCompleted); } responseHeaders.SetReadOnly(); diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/FrameHeaders.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/FrameHeaders.cs index d0d3114268..e4d42e1eaa 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/FrameHeaders.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/FrameHeaders.cs @@ -308,7 +308,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http ch++; } - if (ch == tokenEnd || *ch == ',') + if (ch == tokenEnd) { connectionOptions |= ConnectionOptions.KeepAlive; } @@ -329,7 +329,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http ch++; } - if (ch == tokenEnd || *ch == ',') + if (ch == tokenEnd) { connectionOptions |= ConnectionOptions.Upgrade; } @@ -348,7 +348,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http ch++; } - if (ch == tokenEnd || *ch == ',') + if (ch == tokenEnd) { connectionOptions |= ConnectionOptions.Close; } @@ -364,6 +364,68 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http return connectionOptions; } + public static unsafe TransferCoding GetFinalTransferCoding(StringValues transferEncoding) + { + var transferEncodingOptions = TransferCoding.None; + + foreach (var value in transferEncoding) + { + fixed (char* ptr = value) + { + var ch = ptr; + var tokenEnd = ch; + var end = ch + value.Length; + + while (ch < end) + { + while (tokenEnd < end && *tokenEnd != ',') + { + tokenEnd++; + } + + while (ch < tokenEnd && *ch == ' ') + { + ch++; + } + + var tokenLength = tokenEnd - ch; + + if (tokenLength >= 7 && (*ch | 0x20) == 'c') + { + if ((*++ch | 0x20) == 'h' && + (*++ch | 0x20) == 'u' && + (*++ch | 0x20) == 'n' && + (*++ch | 0x20) == 'k' && + (*++ch | 0x20) == 'e' && + (*++ch | 0x20) == 'd') + { + ch++; + while (ch < tokenEnd && *ch == ' ') + { + ch++; + } + + if (ch == tokenEnd) + { + transferEncodingOptions = TransferCoding.Chunked; + } + } + } + + if (tokenLength > 0 && ch != tokenEnd) + { + transferEncodingOptions = TransferCoding.Other; + } + + tokenEnd++; + ch = tokenEnd; + } + } + } + + return transferEncodingOptions; + } + private static void ThrowInvalidContentLengthException(string value) { throw new InvalidOperationException($"Invalid Content-Length: \"{value}\". Value must be a positive integral number."); diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/MessageBody.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/MessageBody.cs index a3e0093089..c2843a2d00 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/MessageBody.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/MessageBody.cs @@ -247,9 +247,22 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http keepAlive = (connectionOptions & ConnectionOptions.KeepAlive) == ConnectionOptions.KeepAlive; } - var transferEncoding = headers.HeaderTransferEncoding.ToString(); - if (transferEncoding.Length > 0) + var transferEncoding = headers.HeaderTransferEncoding; + if (transferEncoding.Count > 0) { + var transferCoding = FrameHeaders.GetFinalTransferCoding(headers.HeaderTransferEncoding); + + // https://tools.ietf.org/html/rfc7230#section-3.3.3 + // If a Transfer-Encoding header field + // is present in a request and the chunked transfer coding is not + // the final encoding, the message body length cannot be determined + // reliably; the server MUST respond with the 400 (Bad Request) + // status code and then close the connection. + if (transferCoding != TransferCoding.Chunked) + { + context.RejectRequest(RequestRejectionReason.FinalTransferCodingNotChunked, transferEncoding.ToString()); + } + return new ForChunkedEncoding(keepAlive, headers, context); } diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/RequestRejectionReason.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/RequestRejectionReason.cs index 07ed7444e4..68693304e0 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/RequestRejectionReason.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/RequestRejectionReason.cs @@ -27,5 +27,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http MissingCRInHeaderLine, TooManyHeaders, RequestTimeout, + FinalTransferCodingNotChunked } } diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/TransferCoding.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/TransferCoding.cs new file mode 100644 index 0000000000..3bfa8cc74b --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/TransferCoding.cs @@ -0,0 +1,15 @@ +// 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; + +namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http +{ + [Flags] + public enum TransferCoding + { + None, + Chunked, + Other + } +} diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/ResponseTests.cs b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/ResponseTests.cs index f62dfc8e17..d25b55e06f 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/ResponseTests.cs +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/ResponseTests.cs @@ -848,6 +848,140 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests } } + [Theory] + [InlineData("gzip")] + [InlineData("chunked, gzip")] + [InlineData("gzip")] + [InlineData("chunked, gzip")] + public async Task ConnectionClosedWhenChunkedIsNotFinalTransferCoding(string responseTransferEncoding) + { + using (var server = new TestServer(async httpContext => + { + httpContext.Response.Headers["Transfer-Encoding"] = responseTransferEncoding; + await httpContext.Response.WriteAsync("hello, world"); + }, new TestServiceContext())) + { + using (var connection = server.CreateConnection()) + { + await connection.Send( + "GET / HTTP/1.1", + "", + ""); + await connection.ReceiveEnd( + "HTTP/1.1 200 OK", + "Connection: close", + $"Date: {server.Context.DateHeaderValue}", + $"Transfer-Encoding: {responseTransferEncoding}", + "", + "hello, world"); + } + + using (var connection = server.CreateConnection()) + { + await connection.Send( + "GET / HTTP/1.0", + "Connection: keep-alive", + "", + ""); + await connection.ReceiveEnd( + "HTTP/1.1 200 OK", + "Connection: close", + $"Date: {server.Context.DateHeaderValue}", + $"Transfer-Encoding: {responseTransferEncoding}", + "", + "hello, world"); + } + } + } + + [Theory] + [InlineData("gzip")] + [InlineData("chunked, gzip")] + [InlineData("gzip")] + [InlineData("chunked, gzip")] + public async Task ConnectionClosedWhenChunkedIsNotFinalTransferCodingEvenIfConnectionKeepAliveSetInResponse(string responseTransferEncoding) + { + using (var server = new TestServer(async httpContext => + { + httpContext.Response.Headers["Connection"] = "keep-alive"; + httpContext.Response.Headers["Transfer-Encoding"] = responseTransferEncoding; + await httpContext.Response.WriteAsync("hello, world"); + }, new TestServiceContext())) + { + using (var connection = server.CreateConnection()) + { + await connection.Send( + "GET / HTTP/1.1", + "", + ""); + await connection.ReceiveEnd( + "HTTP/1.1 200 OK", + "Connection: keep-alive", + $"Date: {server.Context.DateHeaderValue}", + $"Transfer-Encoding: {responseTransferEncoding}", + "", + "hello, world"); + } + + using (var connection = server.CreateConnection()) + { + await connection.Send( + "GET / HTTP/1.0", + "Connection: keep-alive", + "", + ""); + await connection.ReceiveEnd( + "HTTP/1.1 200 OK", + "Connection: keep-alive", + $"Date: {server.Context.DateHeaderValue}", + $"Transfer-Encoding: {responseTransferEncoding}", + "", + "hello, world"); + } + } + } + + [Theory] + [InlineData("chunked")] + [InlineData("gzip, chunked")] + public async Task ConnectionKeptAliveWhenChunkedIsFinalTransferCoding(string responseTransferEncoding) + { + using (var server = new TestServer(async httpContext => + { + httpContext.Response.Headers["Transfer-Encoding"] = responseTransferEncoding; + + // App would have to chunk manually, but here we don't care + await httpContext.Response.WriteAsync("hello, world"); + }, new TestServiceContext())) + { + using (var connection = server.CreateConnection()) + { + await connection.Send( + "GET / HTTP/1.1", + "", + ""); + await connection.Receive( + "HTTP/1.1 200 OK", + $"Date: {server.Context.DateHeaderValue}", + $"Transfer-Encoding: {responseTransferEncoding}", + "", + "hello, world"); + + // Make sure connection was kept open + await connection.SendEnd( + "GET / HTTP/1.1", + "", + ""); + await connection.ReceiveEnd( + "HTTP/1.1 200 OK", + $"Date: {server.Context.DateHeaderValue}", + $"Transfer-Encoding: {responseTransferEncoding}", + "", + "hello, world"); + } + } + } + public static TheoryData NullHeaderData { get diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/ChunkedRequestTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/ChunkedRequestTests.cs index 221922a050..30f4ecd9d6 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/ChunkedRequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/ChunkedRequestTests.cs @@ -8,6 +8,7 @@ using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Testing; +using Microsoft.Extensions.Internal; using Xunit; namespace Microsoft.AspNetCore.Server.KestrelTests @@ -512,6 +513,106 @@ namespace Microsoft.AspNetCore.Server.KestrelTests } } } + + + [Theory] + [MemberData(nameof(ConnectionFilterData))] + public async Task ChunkedNotFinalTransferCodingResultsIn400(TestServiceContext testContext) + { + using (var server = new TestServer(httpContext => + { + return TaskCache.CompletedTask; + }, testContext)) + { + using (var connection = server.CreateConnection()) + { + await connection.SendAll( + "POST / HTTP/1.1", + "Transfer-Encoding: not-chunked", + "", + "C", + "hello, world", + "0", + "", + ""); + + await connection.ReceiveForcedEnd( + "HTTP/1.1 400 Bad Request", + "Connection: close", + $"Date: {testContext.DateHeaderValue}", + "Content-Length: 0", + "", + ""); + } + + // Content-Length should not affect this + using (var connection = server.CreateConnection()) + { + await connection.SendAll( + "POST / HTTP/1.1", + "Transfer-Encoding: not-chunked", + "Content-Length: 22", + "", + "C", + "hello, world", + "0", + "", + ""); + + await connection.ReceiveForcedEnd( + "HTTP/1.1 400 Bad Request", + "Connection: close", + $"Date: {testContext.DateHeaderValue}", + "Content-Length: 0", + "", + ""); + } + + using (var connection = server.CreateConnection()) + { + await connection.SendAll( + "POST / HTTP/1.1", + "Transfer-Encoding: chunked, not-chunked", + "", + "C", + "hello, world", + "0", + "", + ""); + + await connection.ReceiveForcedEnd( + "HTTP/1.1 400 Bad Request", + "Connection: close", + $"Date: {testContext.DateHeaderValue}", + "Content-Length: 0", + "", + ""); + } + + // Content-Length should not affect this + using (var connection = server.CreateConnection()) + { + await connection.SendAll( + "POST / HTTP/1.1", + "Transfer-Encoding: chunked, not-chunked", + "Content-Length: 22", + "", + "C", + "hello, world", + "0", + "", + ""); + + await connection.ReceiveForcedEnd( + "HTTP/1.1 400 Bad Request", + "Connection: close", + $"Date: {testContext.DateHeaderValue}", + "Content-Length: 0", + "", + ""); + } + } + } } } diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/FrameHeadersTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/FrameHeadersTests.cs index c8cc648376..6e41b778e2 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/FrameHeadersTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/FrameHeadersTests.cs @@ -10,6 +10,16 @@ namespace Microsoft.AspNetCore.Server.KestrelTests public class FrameHeadersTests { [Theory] + [InlineData("", ConnectionOptions.None)] + [InlineData(",", ConnectionOptions.None)] + [InlineData(" ,", ConnectionOptions.None)] + [InlineData(" , ", ConnectionOptions.None)] + [InlineData(",,", ConnectionOptions.None)] + [InlineData(" ,,", ConnectionOptions.None)] + [InlineData(",, ", ConnectionOptions.None)] + [InlineData(" , ,", ConnectionOptions.None)] + [InlineData(" , ,", ConnectionOptions.None)] + [InlineData(" , , ", ConnectionOptions.None)] [InlineData("keep-alive", ConnectionOptions.KeepAlive)] [InlineData("keep-alive, upgrade", ConnectionOptions.KeepAlive | ConnectionOptions.Upgrade)] [InlineData("keep-alive,upgrade", ConnectionOptions.KeepAlive | ConnectionOptions.Upgrade)] @@ -123,10 +133,10 @@ namespace Microsoft.AspNetCore.Server.KestrelTests [InlineData("up2rade ,", ConnectionOptions.None)] [InlineData("c2ose ,", ConnectionOptions.None)] [InlineData("cl2se ,", ConnectionOptions.None)] - public void TestParseConnection(string connection, ConnectionOptions expectedConnectionOptionss) + public void TestParseConnection(string connection, ConnectionOptions expectedConnectionOptions) { var connectionOptions = FrameHeaders.ParseConnection(connection); - Assert.Equal(expectedConnectionOptionss, connectionOptions); + Assert.Equal(expectedConnectionOptions, connectionOptions); } [Theory] @@ -145,11 +155,73 @@ namespace Microsoft.AspNetCore.Server.KestrelTests [InlineData("", "close", ConnectionOptions.Close)] [InlineData("close", "upgrade", ConnectionOptions.Close | ConnectionOptions.Upgrade)] [InlineData("upgrade", "close", ConnectionOptions.Close | ConnectionOptions.Upgrade)] - public void TestParseConnectionMultipleValues(string value1, string value2, ConnectionOptions expectedConnectionOptionss) + public void TestParseConnectionMultipleValues(string value1, string value2, ConnectionOptions expectedConnectionOptions) { var connection = new StringValues(new[] { value1, value2 }); var connectionOptions = FrameHeaders.ParseConnection(connection); - Assert.Equal(expectedConnectionOptionss, connectionOptions); + Assert.Equal(expectedConnectionOptions, connectionOptions); + } + + [Theory] + [InlineData("", TransferCoding.None)] + [InlineData(",,", TransferCoding.None)] + [InlineData(" ,,", TransferCoding.None)] + [InlineData(",, ", TransferCoding.None)] + [InlineData(" , ,", TransferCoding.None)] + [InlineData(" , ,", TransferCoding.None)] + [InlineData(" , , ", TransferCoding.None)] + [InlineData("chunked,", TransferCoding.Chunked)] + [InlineData("chunked,,", TransferCoding.Chunked)] + [InlineData(",chunked", TransferCoding.Chunked)] + [InlineData(",,chunked", TransferCoding.Chunked)] + [InlineData("chunked, ", TransferCoding.Chunked)] + [InlineData("chunked, ,", TransferCoding.Chunked)] + [InlineData("chunked, , ", TransferCoding.Chunked)] + [InlineData("chunked ,", TransferCoding.Chunked)] + [InlineData(",chunked", TransferCoding.Chunked)] + [InlineData(", chunked", TransferCoding.Chunked)] + [InlineData(",,chunked", TransferCoding.Chunked)] + [InlineData(", ,chunked", TransferCoding.Chunked)] + [InlineData(",, chunked", TransferCoding.Chunked)] + [InlineData(", , chunked", TransferCoding.Chunked)] + [InlineData("chunked, gzip", TransferCoding.Other)] + [InlineData("chunked,compress", TransferCoding.Other)] + [InlineData("deflate, chunked", TransferCoding.Chunked)] + [InlineData("gzip,chunked", TransferCoding.Chunked)] + [InlineData("compress,,chunked", TransferCoding.Chunked)] + [InlineData("chunkedchunked", TransferCoding.Other)] + [InlineData("chunked2", TransferCoding.Other)] + [InlineData("chunked 2", TransferCoding.Other)] + [InlineData("2chunked", TransferCoding.Other)] + [InlineData("c2unked", TransferCoding.Other)] + [InlineData("ch2nked", TransferCoding.Other)] + [InlineData("chunked 2, gzip", TransferCoding.Other)] + [InlineData("chunked2, gzip", TransferCoding.Other)] + [InlineData("gzip, chunked 2", TransferCoding.Other)] + [InlineData("gzip, chunked2", TransferCoding.Other)] + public void TestParseTransferEncoding(string transferEncoding, TransferCoding expectedTransferEncodingOptions) + { + var transferEncodingOptions = FrameHeaders.GetFinalTransferCoding(transferEncoding); + Assert.Equal(expectedTransferEncodingOptions, transferEncodingOptions); + } + + [Theory] + [InlineData("chunked", "gzip", TransferCoding.Other)] + [InlineData("compress", "chunked", TransferCoding.Chunked)] + [InlineData("chunked", "", TransferCoding.Chunked)] + [InlineData("", "chunked", TransferCoding.Chunked)] + [InlineData("chunked, deflate", "", TransferCoding.Other)] + [InlineData("gzip, chunked", "", TransferCoding.Chunked)] + [InlineData("", "chunked, compress", TransferCoding.Other)] + [InlineData("", "compress, chunked", TransferCoding.Chunked)] + [InlineData("", "", TransferCoding.None)] + [InlineData("deflate", "", TransferCoding.Other)] + [InlineData("", "gzip", TransferCoding.Other)] + public void TestParseTransferEncodingMultipleValues(string value1, string value2, TransferCoding expectedTransferEncodingOptions) + { + var transferEncoding = new StringValues(new[] { value1, value2 }); + var transferEncodingOptions = FrameHeaders.GetFinalTransferCoding(transferEncoding); + Assert.Equal(expectedTransferEncodingOptions, transferEncodingOptions); } } } diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/MessageBodyTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/MessageBodyTests.cs index 427189fd1b..4ada15b2c5 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/MessageBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/MessageBodyTests.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Server.Kestrel; using Microsoft.AspNetCore.Server.Kestrel.Internal.Http; using Microsoft.AspNetCore.Server.KestrelTests.TestHelpers; using Microsoft.Extensions.Internal; @@ -189,6 +190,19 @@ namespace Microsoft.AspNetCore.Server.KestrelTests } } + [Fact] + public void ForThrowsWhenFinalTransferCodingIsNotChunked() + { + using (var input = new TestInput()) + { + var ex = Assert.Throws(() => + MessageBody.For(HttpVersion.Http10, new FrameRequestHeaders { HeaderTransferEncoding = "chunked, not-chunked" }, input.FrameContext)); + + Assert.Equal(400, ex.StatusCode); + Assert.Equal("Final transfer coding is not \"chunked\": \"chunked, not-chunked\"", ex.Message); + } + } + public static IEnumerable StreamData => new[] { new object[] { new ThrowOnWriteSynchronousStream() }, diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/TestInput.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/TestInput.cs index 3de1e92e07..872e4512f4 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/TestInput.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/TestInput.cs @@ -38,6 +38,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var context = new Frame(null, connectionContext); FrameContext = context; FrameContext.FrameControl = this; + FrameContext.ConnectionContext.ListenerContext.ServiceContext.Log = trace; _memoryPool = new MemoryPool(); FrameContext.SocketInput = new SocketInput(_memoryPool, ltp); diff --git a/test/shared/TestConnection.cs b/test/shared/TestConnection.cs index 3b00841109..56e6c53ce2 100644 --- a/test/shared/TestConnection.cs +++ b/test/shared/TestConnection.cs @@ -115,7 +115,7 @@ namespace Microsoft.AspNetCore.Testing { await Receive(lines); var ch = new char[128]; - var count = await _reader.ReadAsync(ch, 0, 128); + var count = await _reader.ReadAsync(ch, 0, 128).TimeoutAfter(TimeSpan.FromMinutes(1)); var text = new string(ch, 0, count); Assert.Equal("", text); } @@ -127,7 +127,7 @@ namespace Microsoft.AspNetCore.Testing try { var ch = new char[128]; - var count = await _reader.ReadAsync(ch, 0, 128); + var count = await _reader.ReadAsync(ch, 0, 128).TimeoutAfter(TimeSpan.FromMinutes(1)); var text = new string(ch, 0, count); Assert.Equal("", text); }