From b08163d3b7bbc5e599bb895e49ad9d2abd67b848 Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Tue, 29 May 2018 16:07:41 -0700 Subject: [PATCH 1/7] [2.1.1] Use TaskCreationOptions.RunContinuationsAsynchronously a lot (#2618) --- .../ConnectionLimitTests.cs | 12 ++-- .../HttpConnectionManagerTests.cs | 2 +- test/Kestrel.FunctionalTests/HttpsTests.cs | 6 +- .../MaxRequestBufferSizeTests.cs | 8 +-- test/Kestrel.FunctionalTests/RequestTests.cs | 32 +++++----- test/Kestrel.FunctionalTests/ResponseTests.cs | 62 +++++++++---------- .../HostNameIsReachableAttribute.cs | 2 +- test/Kestrel.FunctionalTests/UpgradeTests.cs | 10 +-- .../ListenerPrimaryTests.cs | 2 +- test/shared/TestConnection.cs | 2 +- 10 files changed, 66 insertions(+), 72 deletions(-) diff --git a/test/Kestrel.FunctionalTests/ConnectionLimitTests.cs b/test/Kestrel.FunctionalTests/ConnectionLimitTests.cs index 8462050e36..3aa1ad90f5 100644 --- a/test/Kestrel.FunctionalTests/ConnectionLimitTests.cs +++ b/test/Kestrel.FunctionalTests/ConnectionLimitTests.cs @@ -22,9 +22,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests [Fact] public async Task ResetsCountWhenConnectionClosed() { - var requestTcs = new TaskCompletionSource(); - var releasedTcs = new TaskCompletionSource(); - var lockedTcs = new TaskCompletionSource(); + var requestTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var releasedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var lockedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var counter = new EventRaisingResourceCounter(ResourceCounter.Quota(1)); counter.OnLock += (s, e) => lockedTcs.TrySetResult(e); counter.OnRelease += (s, e) => releasedTcs.TrySetResult(null); @@ -95,7 +95,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests public async Task RejectsConnectionsWhenLimitReached() { const int max = 10; - var requestTcs = new TaskCompletionSource(); + var requestTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); using (var server = CreateServerWithMaxConnections(async context => { @@ -140,8 +140,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests const int count = 100; var opened = 0; var closed = 0; - var openedTcs = new TaskCompletionSource(); - var closedTcs = new TaskCompletionSource(); + var openedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var closedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var counter = new EventRaisingResourceCounter(ResourceCounter.Quota(uint.MaxValue)); diff --git a/test/Kestrel.FunctionalTests/HttpConnectionManagerTests.cs b/test/Kestrel.FunctionalTests/HttpConnectionManagerTests.cs index 7f5296763c..ef8ac428b1 100644 --- a/test/Kestrel.FunctionalTests/HttpConnectionManagerTests.cs +++ b/test/Kestrel.FunctionalTests/HttpConnectionManagerTests.cs @@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests using (var server = new TestServer(context => { appStartedWh.Release(); - var tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); return tcs.Task; }, new TestServiceContext(new LoggerFactory(), mockTrace.Object))) diff --git a/test/Kestrel.FunctionalTests/HttpsTests.cs b/test/Kestrel.FunctionalTests/HttpsTests.cs index b20b3c5874..30ae3470ed 100644 --- a/test/Kestrel.FunctionalTests/HttpsTests.cs +++ b/test/Kestrel.FunctionalTests/HttpsTests.cs @@ -253,7 +253,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests [Fact] public async Task DoesNotThrowObjectDisposedExceptionFromWriteAsyncAfterConnectionIsAborted() { - var tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var loggerProvider = new HandshakeErrorLoggerProvider(); LoggerFactory.AddProvider(loggerProvider); var hostBuilder = TransportSelector.GetWebHostBuilder() @@ -441,13 +441,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests { public LogLevel LastLogLevel { get; set; } public EventId LastEventId { get; set; } - public TaskCompletionSource LogTcs { get; } = new TaskCompletionSource(); + public TaskCompletionSource LogTcs { get; } = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) { LastLogLevel = logLevel; LastEventId = eventId; - Task.Run(() => LogTcs.SetResult(null)); + LogTcs.SetResult(null); } public bool IsEnabled(LogLevel logLevel) diff --git a/test/Kestrel.FunctionalTests/MaxRequestBufferSizeTests.cs b/test/Kestrel.FunctionalTests/MaxRequestBufferSizeTests.cs index 93919845ea..64522f2202 100644 --- a/test/Kestrel.FunctionalTests/MaxRequestBufferSizeTests.cs +++ b/test/Kestrel.FunctionalTests/MaxRequestBufferSizeTests.cs @@ -89,8 +89,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests // Initialize data with random bytes (new Random()).NextBytes(data); - var startReadingRequestBody = new TaskCompletionSource(); - var clientFinishedSendingRequestBody = new TaskCompletionSource(); + var startReadingRequestBody = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var clientFinishedSendingRequestBody = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var lastBytesWritten = DateTime.MaxValue; using (var host = StartWebHost(maxRequestBufferSize, data, connectionAdapter, startReadingRequestBody, clientFinishedSendingRequestBody)) @@ -181,8 +181,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests var bytesWrittenPollingInterval = TimeSpan.FromMilliseconds(bytesWrittenTimeout.TotalMilliseconds / 10); var maxSendSize = 4096; - var startReadingRequestBody = new TaskCompletionSource(); - var clientFinishedSendingRequestBody = new TaskCompletionSource(); + var startReadingRequestBody = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var clientFinishedSendingRequestBody = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var lastBytesWritten = DateTime.MaxValue; using (var host = StartWebHost(16 * 1024, data, false, startReadingRequestBody, clientFinishedSendingRequestBody)) diff --git a/test/Kestrel.FunctionalTests/RequestTests.cs b/test/Kestrel.FunctionalTests/RequestTests.cs index 3f82426e5f..7d01075fc4 100644 --- a/test/Kestrel.FunctionalTests/RequestTests.cs +++ b/test/Kestrel.FunctionalTests/RequestTests.cs @@ -578,8 +578,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests public async Task ConnectionClosedTokenFiresOnClientFIN(ListenOptions listenOptions) { var testContext = new TestServiceContext(LoggerFactory); - var appStartedTcs = new TaskCompletionSource(); - var connectionClosedTcs = new TaskCompletionSource(); + var appStartedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var connectionClosedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); using (var server = new TestServer(context => { @@ -613,7 +613,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests public async Task ConnectionClosedTokenFiresOnServerFIN(ListenOptions listenOptions) { var testContext = new TestServiceContext(LoggerFactory); - var connectionClosedTcs = new TaskCompletionSource(); + var connectionClosedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); using (var server = new TestServer(context => { @@ -649,7 +649,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests public async Task ConnectionClosedTokenFiresOnServerAbort(ListenOptions listenOptions) { var testContext = new TestServiceContext(LoggerFactory); - var connectionClosedTcs = new TaskCompletionSource(); + var connectionClosedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); using (var server = new TestServer(context => { @@ -694,9 +694,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests [InlineData("http://localhost/path%20with%20space?q=abc%20123", "/path with space", "abc 123")] public async Task CanHandleRequestsWithUrlInAbsoluteForm(string requestUrl, string expectedPath, string queryValue) { - var pathTcs = new TaskCompletionSource(); - var rawTargetTcs = new TaskCompletionSource(); - var queryTcs = new TaskCompletionSource(); + var pathTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var rawTargetTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var queryTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); using (var server = new TestServer(async context => { @@ -1135,8 +1135,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests { var testContext = new TestServiceContext(LoggerFactory); - var readTcs = new TaskCompletionSource(); - var registrationTcs = new TaskCompletionSource(); + var readTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var registrationTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var requestId = 0; using (var server = new TestServer(async httpContext => @@ -1217,10 +1217,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests const int connectionFinSentEventId = 7; const int maxRequestBufferSize = 4096; - var readCallbackUnwired = new TaskCompletionSource(TaskContinuationOptions.RunContinuationsAsynchronously); - var clientClosedConnection = new TaskCompletionSource(TaskContinuationOptions.RunContinuationsAsynchronously); - var serverClosedConnection = new TaskCompletionSource(TaskContinuationOptions.RunContinuationsAsynchronously); - var appFuncCompleted = new TaskCompletionSource(TaskContinuationOptions.RunContinuationsAsynchronously); + var readCallbackUnwired = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var clientClosedConnection = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var serverClosedConnection = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var appFuncCompleted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var mockLogger = new Mock(); mockLogger @@ -1276,9 +1276,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests await serverClosedConnection.Task; - // TaskContinuationOptions.RunContinuationsAsynchronously sometimes runs inline anyway in - // situations such as this where the awaiter starts awaiting right when SetResult is called. - _ = Task.Run(() => appFuncCompleted.SetResult(null)); + appFuncCompleted.SetResult(null); }, testContext, listenOptions)) { using (var connection = server.CreateConnection()) @@ -1308,7 +1306,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests [MemberData(nameof(ConnectionAdapterData))] public async Task AppCanHandleClientAbortingConnectionMidRequest(ListenOptions listenOptions) { - var readTcs = new TaskCompletionSource(TaskContinuationOptions.RunContinuationsAsynchronously); + var readTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var mockKestrelTrace = new Mock(Logger) { CallBase = true }; var testContext = new TestServiceContext() diff --git a/test/Kestrel.FunctionalTests/ResponseTests.cs b/test/Kestrel.FunctionalTests/ResponseTests.cs index 3e7f4b7d58..d652b8aff4 100644 --- a/test/Kestrel.FunctionalTests/ResponseTests.cs +++ b/test/Kestrel.FunctionalTests/ResponseTests.cs @@ -145,7 +145,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests public async Task OnCompleteCalledEvenWhenOnStartingNotCalled() { var onStartingCalled = false; - var onCompletedTcs = new TaskCompletionSource(); + var onCompletedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var hostBuilder = TransportSelector.GetWebHostBuilder() .UseKestrel() @@ -341,7 +341,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests [Fact] public async Task OnCompletedShouldNotBlockAResponse() { - var delayTcs = new TaskCompletionSource(); + var delayTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var hostBuilder = TransportSelector.GetWebHostBuilder() .UseKestrel() .UseUrls("http://127.0.0.1:0/") @@ -375,7 +375,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests [Fact] public async Task InvalidChunkedEncodingInRequestShouldNotBlockOnCompleted() { - var onCompletedTcs = new TaskCompletionSource(); + var onCompletedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); using (var server = new TestServer(httpContext => { @@ -418,7 +418,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests mockHttpContextFactory.Setup(f => f.Create(It.IsAny())) .Returns(fc => new DefaultHttpContext(fc)); - var disposedTcs = new TaskCompletionSource(); + var disposedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); mockHttpContextFactory.Setup(f => f.Dispose(It.IsAny())) .Callback(c => { @@ -619,7 +619,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests { const string response = "hello, world"; - var logTcs = new TaskCompletionSource(); + var logTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var mockKestrelTrace = new Mock(); mockKestrelTrace .Setup(trace => trace.ConnectionHeadResponseBodyWrite(It.IsAny(), response.Length)) @@ -808,7 +808,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests [Fact] public async Task WhenAppWritesLessThanContentLengthErrorLogged() { - var logTcs = new TaskCompletionSource(); + var logTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var mockTrace = new Mock(); mockTrace .Setup(trace => trace.ApplicationError(It.IsAny(), It.IsAny(), It.IsAny())) @@ -1182,7 +1182,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests { var connectionClosed = new ManualResetEventSlim(); var requestStarted = new ManualResetEventSlim(); - var tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); using (var server = new TestServer(async httpContext => { @@ -2279,7 +2279,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests // Ensure string is long enough to disable write-behind buffering var largeString = new string('a', maxBytesPreCompleted + 1); - var writeTcs = new TaskCompletionSource(); + var writeTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var requestAbortedWh = new ManualResetEventSlim(); var requestStartWh = new ManualResetEventSlim(); @@ -2336,9 +2336,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests const int maxRequestBufferSize = 2048; var requestAborted = false; - var readCallbackUnwired = new TaskCompletionSource(TaskContinuationOptions.RunContinuationsAsynchronously); - var clientClosedConnection = new TaskCompletionSource(TaskContinuationOptions.RunContinuationsAsynchronously); - var writeTcs = new TaskCompletionSource(TaskContinuationOptions.RunContinuationsAsynchronously); + var readCallbackUnwired = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var clientClosedConnection = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var writeTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var mockKestrelTrace = new Mock(Logger) { CallBase = true }; var mockLogger = new Mock(); @@ -2401,9 +2401,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests } catch (Exception ex) { - // TaskContinuationOptions.RunContinuationsAsynchronously sometimes runs inline anyway in - // situations such as this where the awaiter starts awaiting right when SetResult is called. - _ = Task.Run(() => writeTcs.SetException(ex)); + writeTcs.SetException(ex); throw; } @@ -2443,7 +2441,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests const int responseBodySize = responseBodySegmentSize * responseBodySegmentCount; var requestAborted = false; - var appCompletedTcs = new TaskCompletionSource(TaskContinuationOptions.RunContinuationsAsynchronously); + var appCompletedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var mockKestrelTrace = new Mock(Logger) { CallBase = true }; var testContext = new TestServiceContext() @@ -2474,9 +2472,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests { // WriteAsync shouldn't throw without a CancellationToken passed in. Unfortunately a ECONNRESET UvException sometimes gets thrown. // This will be fixed by https://github.com/aspnet/KestrelHttpServer/pull/2547 - // TaskContinuationOptions.RunContinuationsAsynchronously sometimes runs inline anyway in - // situations such as this where the awaiter starts awaiting right when SetResult is called. - _ = Task.Run(() => appCompletedTcs.SetResult(null)); + appCompletedTcs.SetResult(null); } }, testContext, listenOptions)) { @@ -2623,7 +2619,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests var testContext= new TestServiceContext(LoggerFactory); var callOrder = new Stack(); - var onStartingTcs = new TaskCompletionSource(); + var onStartingTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); using (var server = new TestServer(async context => { @@ -2675,7 +2671,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests var testContext= new TestServiceContext(LoggerFactory); var callOrder = new Stack(); - var onCompletedTcs = new TaskCompletionSource(); + var onCompletedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); using (var server = new TestServer(async context => { @@ -2819,10 +2815,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests var responseSize = chunks * chunkSize; var chunkData = new byte[chunkSize]; - var responseRateTimeoutMessageLogged = new TaskCompletionSource(); - var connectionStopMessageLogged = new TaskCompletionSource(); - var requestAborted = new TaskCompletionSource(); - var appFuncCompleted = new TaskCompletionSource(); + var responseRateTimeoutMessageLogged = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var connectionStopMessageLogged = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var requestAborted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var appFuncCompleted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var mockKestrelTrace = new Mock(); mockKestrelTrace @@ -2910,10 +2906,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests var certificate = new X509Certificate2(TestResources.TestCertificatePath, "testPassword"); - var responseRateTimeoutMessageLogged = new TaskCompletionSource(); - var connectionStopMessageLogged = new TaskCompletionSource(); - var aborted = new TaskCompletionSource(); - var appFuncCompleted = new TaskCompletionSource(); + var responseRateTimeoutMessageLogged = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var connectionStopMessageLogged = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var aborted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var appFuncCompleted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var mockKestrelTrace = new Mock(); mockKestrelTrace @@ -3002,10 +2998,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests var responseSize = bufferCount * bufferSize; var buffer = new byte[bufferSize]; - var responseRateTimeoutMessageLogged = new TaskCompletionSource(); - var connectionStopMessageLogged = new TaskCompletionSource(); - var requestAborted = new TaskCompletionSource(); - var appFuncCompleted = new TaskCompletionSource(); + var responseRateTimeoutMessageLogged = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var connectionStopMessageLogged = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var requestAborted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var appFuncCompleted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var mockKestrelTrace = new Mock(); mockKestrelTrace @@ -3089,7 +3085,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests var chunkData = new byte[chunkSize]; var requestAborted = false; - var appFuncCompleted = new TaskCompletionSource(); + var appFuncCompleted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var mockKestrelTrace = new Mock(); var testContext = new TestServiceContext diff --git a/test/Kestrel.FunctionalTests/TestHelpers/HostNameIsReachableAttribute.cs b/test/Kestrel.FunctionalTests/TestHelpers/HostNameIsReachableAttribute.cs index bd120b6356..5a83bd7c3f 100644 --- a/test/Kestrel.FunctionalTests/TestHelpers/HostNameIsReachableAttribute.cs +++ b/test/Kestrel.FunctionalTests/TestHelpers/HostNameIsReachableAttribute.cs @@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests public static async Task ConnectToHost(string hostName, int port) { - var tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var socketArgs = new SocketAsyncEventArgs(); socketArgs.RemoteEndPoint = new DnsEndPoint(hostName, port); diff --git a/test/Kestrel.FunctionalTests/UpgradeTests.cs b/test/Kestrel.FunctionalTests/UpgradeTests.cs index 6a839aaad3..d7a0f5073f 100644 --- a/test/Kestrel.FunctionalTests/UpgradeTests.cs +++ b/test/Kestrel.FunctionalTests/UpgradeTests.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests [Fact] public async Task ResponseThrowsAfterUpgrade() { - var upgrade = new TaskCompletionSource(); + var upgrade = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); using (var server = new TestServer(async context => { var feature = context.Features.Get(); @@ -58,7 +58,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests const string send = "Custom protocol send"; const string recv = "Custom protocol recv"; - var upgrade = new TaskCompletionSource(); + var upgrade = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); using (var server = new TestServer(async context => { try @@ -109,7 +109,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests [Fact] public async Task UpgradeCannotBeCalledMultipleTimes() { - var upgradeTcs = new TaskCompletionSource(); + var upgradeTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); using (var server = new TestServer(async context => { var feature = context.Features.Get(); @@ -217,7 +217,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests [Fact] public async Task ThrowsWhenUpgradingNonUpgradableRequest() { - var upgradeTcs = new TaskCompletionSource(); + var upgradeTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); using (var server = new TestServer(async context => { var feature = context.Features.Get(); @@ -251,7 +251,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests public async Task RejectsUpgradeWhenLimitReached() { const int limit = 10; - var upgradeTcs = new TaskCompletionSource(); + var upgradeTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var serviceContext = new TestServiceContext(LoggerFactory); serviceContext.ConnectionManager = new HttpConnectionManager(serviceContext.Log, ResourceCounter.Quota(limit)); diff --git a/test/Kestrel.Transport.Libuv.Tests/ListenerPrimaryTests.cs b/test/Kestrel.Transport.Libuv.Tests/ListenerPrimaryTests.cs index fa4198ccb4..2d906fc2cf 100644 --- a/test/Kestrel.Transport.Libuv.Tests/ListenerPrimaryTests.cs +++ b/test/Kestrel.Transport.Libuv.Tests/ListenerPrimaryTests.cs @@ -140,7 +140,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests Assert.Equal("Primary", await HttpClientSlim.GetStringAsync(address)); // Create a pipe connection and keep it open without sending any data - var connectTcs = new TaskCompletionSource(); + var connectTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var connectionTrace = new LibuvTrace(new TestApplicationErrorLogger()); var pipe = new UvPipeHandle(connectionTrace); diff --git a/test/shared/TestConnection.cs b/test/shared/TestConnection.cs index 4f65da6bcf..85e82590c0 100644 --- a/test/shared/TestConnection.cs +++ b/test/shared/TestConnection.cs @@ -217,7 +217,7 @@ namespace Microsoft.AspNetCore.Testing public Task WaitForConnectionClose() { - var tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var eventArgs = new SocketAsyncEventArgs(); eventArgs.SetBuffer(new byte[128], 0, 128); eventArgs.Completed += ReceiveAsyncCompleted; From 5ec7bacdfea4e44217d2fc29d6b31ebfa83e8e07 Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Tue, 29 May 2018 16:27:16 -0700 Subject: [PATCH 2/7] Lower severity of AuthenticationException logs from SslStream handshake (#2614) --- .../Internal/HttpsConnectionAdapter.cs | 3 +- test/Kestrel.FunctionalTests/HttpsTests.cs | 58 +++++++++++++------ test/Kestrel.FunctionalTests/RequestTests.cs | 2 +- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/src/Kestrel.Core/Internal/HttpsConnectionAdapter.cs b/src/Kestrel.Core/Internal/HttpsConnectionAdapter.cs index 301c9c7a23..95ee435b43 100644 --- a/src/Kestrel.Core/Internal/HttpsConnectionAdapter.cs +++ b/src/Kestrel.Core/Internal/HttpsConnectionAdapter.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Net.Security; +using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; @@ -186,7 +187,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https.Internal sslStream.Dispose(); return _closedAdaptedConnection; } - catch (IOException ex) + catch (Exception ex) when (ex is IOException || ex is AuthenticationException) { _logger?.LogDebug(1, ex, CoreStrings.AuthenticationFailed); sslStream.Dispose(); diff --git a/test/Kestrel.FunctionalTests/HttpsTests.cs b/test/Kestrel.FunctionalTests/HttpsTests.cs index 30ae3470ed..be9e9fe623 100644 --- a/test/Kestrel.FunctionalTests/HttpsTests.cs +++ b/test/Kestrel.FunctionalTests/HttpsTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Net; using System.Net.Security; using System.Net.Sockets; @@ -235,15 +236,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests var request = Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\nHost:\r\n\r\n"); await sslStream.WriteAsync(request, 0, request.Length); - // Temporary workaround for a deadlock when reading from an aborted client SslStream on Mac and Linux. - if (TestPlatformHelper.IsWindows) - { - await sslStream.ReadAsync(new byte[32], 0, 32); - } - else - { - await stream.ReadAsync(new byte[32], 0, 32); - } + await sslStream.ReadAsync(new byte[32], 0, 32); } } @@ -295,15 +288,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests var request = Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\nHost:\r\n\r\n"); await sslStream.WriteAsync(request, 0, request.Length); - // Temporary workaround for a deadlock when reading from an aborted client SslStream on Mac and Linux. - if (TestPlatformHelper.IsWindows) - { - await sslStream.ReadAsync(new byte[32], 0, 32); - } - else - { - await stream.ReadAsync(new byte[32], 0, 32); - } + await sslStream.ReadAsync(new byte[32], 0, 32); } } @@ -415,6 +400,43 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests Assert.Equal(LogLevel.Debug, loggerProvider.FilterLogger.LastLogLevel); } + [Fact] + public async Task ClientAttemptingToUseUnsupportedProtocolIsLoggedAsDebug() + { + var loggerProvider = new HandshakeErrorLoggerProvider(); + LoggerFactory.AddProvider(loggerProvider); + var hostBuilder = TransportSelector.GetWebHostBuilder() + .UseKestrel(options => + { + options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions => + { + listenOptions.UseHttps(TestResources.TestCertificatePath, "testPassword"); + }); + }) + .ConfigureServices(AddTestLogging) + .Configure(app => app.Run(httpContext => Task.CompletedTask)); + + using (var host = hostBuilder.Build()) + { + host.Start(); + + using (var socket = await HttpClientSlim.GetSocket(new Uri($"https://127.0.0.1:{host.GetPort()}/"))) + using (var stream = new NetworkStream(socket, ownsSocket: false)) + using (var sslStream = new SslStream(stream, true, (sender, certificate, chain, errors) => true)) + { + // SslProtocols.Tls is TLS 1.0 which isn't supported by Kestrel by default. + await Assert.ThrowsAsync(() => + sslStream.AuthenticateAsClientAsync("127.0.0.1", clientCertificates: null, + enabledSslProtocols: SslProtocols.Tls, + checkCertificateRevocation: false)); + } + } + + await loggerProvider.FilterLogger.LogTcs.Task.TimeoutAfter(TestConstants.DefaultTimeout); + Assert.Equal(1, loggerProvider.FilterLogger.LastEventId); + Assert.Equal(LogLevel.Debug, loggerProvider.FilterLogger.LastLogLevel); + } + private class HandshakeErrorLoggerProvider : ILoggerProvider { public HttpsConnectionFilterLogger FilterLogger { get; } = new HttpsConnectionFilterLogger(); diff --git a/test/Kestrel.FunctionalTests/RequestTests.cs b/test/Kestrel.FunctionalTests/RequestTests.cs index 7d01075fc4..d8d78fd6d8 100644 --- a/test/Kestrel.FunctionalTests/RequestTests.cs +++ b/test/Kestrel.FunctionalTests/RequestTests.cs @@ -1266,7 +1266,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests } }; - var scratchBuffer = new byte[maxRequestBufferSize * 2 + 1]; + var scratchBuffer = new byte[maxRequestBufferSize * 8]; using (var server = new TestServer(async context => { From af177c5adcb467ad8cf7e6793a1020b7c830b03e Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Thu, 31 May 2018 15:44:39 -0700 Subject: [PATCH 3/7] Add Memory overloads to HttpUpgradeStream (#2622) --- .../Internal/Http/HttpUpgradeStream.cs | 14 ++++++++++++++ .../Internal/Infrastructure/WrappingStream.cs | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/Kestrel.Core/Internal/Http/HttpUpgradeStream.cs b/src/Kestrel.Core/Internal/Http/HttpUpgradeStream.cs index e7163b7ece..d6fedc0518 100644 --- a/src/Kestrel.Core/Internal/Http/HttpUpgradeStream.cs +++ b/src/Kestrel.Core/Internal/Http/HttpUpgradeStream.cs @@ -145,6 +145,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return _requestStream.ReadAsync(buffer, offset, count, cancellationToken); } +#if NETCOREAPP2_1 + public override ValueTask ReadAsync(Memory destination, CancellationToken cancellationToken = default) + { + return _requestStream.ReadAsync(destination, cancellationToken); + } +#endif + public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken) { return _requestStream.CopyToAsync(destination, bufferSize, cancellationToken); @@ -155,6 +162,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return _responseStream.WriteAsync(buffer, offset, count, cancellationToken); } +#if NETCOREAPP2_1 + public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default) + { + return _responseStream.WriteAsync(source, cancellationToken); + } +#endif + public override long Seek(long offset, SeekOrigin origin) { return _requestStream.Seek(offset, origin); diff --git a/src/Kestrel.Core/Internal/Infrastructure/WrappingStream.cs b/src/Kestrel.Core/Internal/Infrastructure/WrappingStream.cs index a1c87ad8c8..9485392825 100644 --- a/src/Kestrel.Core/Internal/Infrastructure/WrappingStream.cs +++ b/src/Kestrel.Core/Internal/Infrastructure/WrappingStream.cs @@ -68,6 +68,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => _inner.ReadAsync(buffer, offset, count, cancellationToken); +#if NETCOREAPP2_1 + public override ValueTask ReadAsync(Memory destination, CancellationToken cancellationToken = default) + => _inner.ReadAsync(destination, cancellationToken); +#endif + public override int ReadByte() => _inner.ReadByte(); @@ -83,6 +88,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => _inner.WriteAsync(buffer, offset, count, cancellationToken); +#if NETCOREAPP2_1 + public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default) + => _inner.WriteAsync(source, cancellationToken); +#endif + public override void WriteByte(byte value) => _inner.WriteByte(value); From d1416e679bcc6604fd86d7a34015fddcf2ef5480 Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Thu, 31 May 2018 15:45:26 -0700 Subject: [PATCH 4/7] [2.1.1] Provide clearer exception message for breaking change (#2623) - In 2.1, the default transport (Sockets) can no longer bind to certain endpoint types (Unix domain sockets and open socket handles). - The new message recommends manually selecting the libuv transport to work around this issue. --- .../Properties/SocketsStrings.Designer.cs | 4 ++-- src/Kestrel.Transport.Sockets/SocketsStrings.resx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Kestrel.Transport.Sockets/Properties/SocketsStrings.Designer.cs b/src/Kestrel.Transport.Sockets/Properties/SocketsStrings.Designer.cs index 9d2e7e0182..2d26f8f398 100644 --- a/src/Kestrel.Transport.Sockets/Properties/SocketsStrings.Designer.cs +++ b/src/Kestrel.Transport.Sockets/Properties/SocketsStrings.Designer.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets = new ResourceManager("Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketsStrings", typeof(SocketsStrings).GetTypeInfo().Assembly); /// - /// Only ListenType.IPEndPoint is supported. + /// Only ListenType.IPEndPoint is supported by the Socket Transport. https://go.microsoft.com/fwlink/?linkid=874850 /// internal static string OnlyIPEndPointsSupported { @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets } /// - /// Only ListenType.IPEndPoint is supported. + /// Only ListenType.IPEndPoint is supported by the Socket Transport. https://go.microsoft.com/fwlink/?linkid=874850 /// internal static string FormatOnlyIPEndPointsSupported() => GetString("OnlyIPEndPointsSupported"); diff --git a/src/Kestrel.Transport.Sockets/SocketsStrings.resx b/src/Kestrel.Transport.Sockets/SocketsStrings.resx index 79cd2d7303..52b26c66bc 100644 --- a/src/Kestrel.Transport.Sockets/SocketsStrings.resx +++ b/src/Kestrel.Transport.Sockets/SocketsStrings.resx @@ -118,7 +118,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Only ListenType.IPEndPoint is supported. + Only ListenType.IPEndPoint is supported by the Socket Transport. https://go.microsoft.com/fwlink/?linkid=874850 Transport is already bound. From e4d290b601ef646c5e02b5819012b49ad54f5a4e Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Thu, 31 May 2018 16:28:25 -0700 Subject: [PATCH 5/7] Fix Json regression in Socket Transport (#2578) --- .../Internal/SocketConnection.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Kestrel.Transport.Sockets/Internal/SocketConnection.cs b/src/Kestrel.Transport.Sockets/Internal/SocketConnection.cs index e1f323abba..47a0dad85c 100644 --- a/src/Kestrel.Transport.Sockets/Internal/SocketConnection.cs +++ b/src/Kestrel.Transport.Sockets/Internal/SocketConnection.cs @@ -20,6 +20,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal internal sealed class SocketConnection : TransportConnection { private static readonly int MinAllocBufferSize = KestrelMemoryPool.MinimumSegmentSize / 2; + private static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); private readonly Socket _socket; private readonly PipeScheduler _scheduler; @@ -54,8 +55,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal ConnectionClosed = _connectionClosedTokenSource.Token; - _receiver = new SocketReceiver(_socket, _scheduler); - _sender = new SocketSender(_socket, _scheduler); + // On *nix platforms, Sockets already dispatches to the ThreadPool. + // Yes, the IOQueues are still used for the PipeSchedulers. This is intentional. + // https://github.com/aspnet/KestrelHttpServer/issues/2573 + var awaiterScheduler = IsWindows ? _scheduler : PipeScheduler.Inline; + + _receiver = new SocketReceiver(_socket, awaiterScheduler); + _sender = new SocketSender(_socket, awaiterScheduler); } public override MemoryPool MemoryPool { get; } From ab5fb559e54244d0fa36b86ff18a0363530f4a46 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Tue, 12 Jun 2018 19:26:02 +0000 Subject: [PATCH 6/7] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 54 ++++++++++++++++++++-------------------- korebuild-lock.txt | 4 +-- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 3f6b4b6da1..a53bc20e1f 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -5,44 +5,44 @@ 0.10.13 - 2.1.1-rtm-15790 + 2.1.1-rtm-15793 1.10.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 - 2.1.0 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 2.0.0 - 2.1.0 - 2.1.0 + 2.1.1 + 2.1.1 15.6.1 4.7.49 2.0.3 11.0.2 4.5.0 4.5.0 - 4.5.0 + 4.5.1 4.5.0 - 4.5.0 + 4.5.1 4.5.0 - 4.5.0 + 4.5.1 1.3.7 0.8.0 2.3.1 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index cd5b409a1e..bc84e0cd53 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.1-rtm-15790 -commithash:274c65868e735f29f4078c1884c61c4371ee1fc0 +version:2.1.1-rtm-15793 +commithash:988313f4b064d6c69fc6f7b845b6384a6af3447a From 11ddd9174c7c2af231ad70cf3efad85012e2fd73 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Tue, 12 Jun 2018 14:13:52 -0700 Subject: [PATCH 7/7] Bumping version from 2.1.1 to 2.1.2 --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 669c874829..478dfd16ed 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@  - 2.1.1 + 2.1.2 rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final