From fbc5b64cd8fee5e966b51ce0dbb9f32fd524fce4 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Fri, 16 Mar 2018 10:56:36 -0700 Subject: [PATCH] React to new SocketHttpHandler (#434) --- build/dependencies.props | 18 +- .../RequestProcessing/RequestStream.cs | 227 +++++++++--------- .../Listener/RequestBodyTests.cs | 3 +- .../Listener/ResponseBodyTests.cs | 8 +- .../Listener/ResponseSendFileTests.cs | 4 +- .../Listener/ServerTests.cs | 4 +- .../RequestBodyLimitTests.cs | 1 + .../RequestBodyTests.cs | 3 +- 8 files changed, 131 insertions(+), 137 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index f2976b08b8..5aaa28edec 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,17 +4,17 @@ 2.1.0-preview2-15728 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 - 2.1.0-preview2-30272 + 2.1.0-preview2-30301 + 2.1.0-preview2-30301 + 2.1.0-preview2-30301 + 2.1.0-preview2-30301 2.0.0 - 2.1.0-preview2-26225-03 - 2.1.0-preview2-30272 + 2.1.0-preview2-26308-01 + 2.1.0-preview2-30301 15.6.0 - 4.5.0-preview2-26224-02 - 4.5.0-preview2-26224-02 - 4.5.0-preview2-26224-02 + 4.5.0-preview2-26308-02 + 4.5.0-preview2-26308-02 + 4.5.0-preview2-26308-02 2.3.1 2.4.0-beta.1.build3945 diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs index 284a3d856e..6e0cb2ace5 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs @@ -133,12 +133,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys dataRead = _requestContext.Request.GetChunks(ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); } - if (_dataChunkIndex == -1 && dataRead < size) + if (_dataChunkIndex == -1 && dataRead == 0) { uint statusCode = 0; uint extraDataRead = 0; - offset += (int)dataRead; - size -= (int)dataRead; // the http.sys team recommends that we limit the size to 128kb if (size > MaxReadSize) @@ -209,72 +207,68 @@ namespace Microsoft.AspNetCore.Server.HttpSys { dataRead = _requestContext.Request.GetChunks(ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); - if (_dataChunkIndex != -1 && dataRead == size) + if (dataRead > 0) { asyncResult = new RequestStreamAsyncResult(this, state, callback, buffer, offset, 0); asyncResult.Complete((int)dataRead); + return asyncResult; } } - if (_dataChunkIndex == -1 && dataRead < size) + uint statusCode = 0; + + // the http.sys team recommends that we limit the size to 128kb + if (size > MaxReadSize) { - uint statusCode = 0; - offset += (int)dataRead; - size -= (int)dataRead; + size = MaxReadSize; + } - // the http.sys team recommends that we limit the size to 128kb - if (size > MaxReadSize) - { - size = MaxReadSize; - } + asyncResult = new RequestStreamAsyncResult(this, state, callback, buffer, offset, dataRead); + uint bytesReturned; - asyncResult = new RequestStreamAsyncResult(this, state, callback, buffer, offset, dataRead); - uint bytesReturned; + try + { + uint flags = 0; - try - { - uint flags = 0; + statusCode = + HttpApi.HttpReceiveRequestEntityBody( + RequestQueueHandle, + RequestId, + flags, + asyncResult.PinnedBuffer, + (uint)size, + out bytesReturned, + asyncResult.NativeOverlapped); + } + catch (Exception e) + { + LogHelper.LogException(Logger, "BeginRead", e); + asyncResult.Dispose(); + throw; + } - statusCode = - HttpApi.HttpReceiveRequestEntityBody( - RequestQueueHandle, - RequestId, - flags, - asyncResult.PinnedBuffer, - (uint)size, - out bytesReturned, - asyncResult.NativeOverlapped); - } - catch (Exception e) + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) + { + asyncResult.Dispose(); + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) { - LogHelper.LogException(Logger, "BeginRead", e); - asyncResult.Dispose(); - throw; + asyncResult = new RequestStreamAsyncResult(this, state, callback, dataRead); + asyncResult.Complete((int)bytesReturned); } - - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) + else { - asyncResult.Dispose(); - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) - { - asyncResult = new RequestStreamAsyncResult(this, state, callback, dataRead); - asyncResult.Complete((int)bytesReturned); - } - else - { - Exception exception = new IOException(string.Empty, new HttpSysException((int)statusCode)); - LogHelper.LogException(Logger, "BeginRead", exception); - Abort(); - throw exception; - } - } - else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && - HttpSysListener.SkipIOCPCallbackOnSuccess) - { - // IO operation completed synchronously - callback won't be called to signal completion. - asyncResult.IOCompleted(statusCode, bytesReturned); + Exception exception = new IOException(string.Empty, new HttpSysException((int)statusCode)); + LogHelper.LogException(Logger, "BeginRead", exception); + Abort(); + throw exception; } } + else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && + HttpSysListener.SkipIOCPCallbackOnSuccess) + { + // IO operation completed synchronously - callback won't be called to signal completion. + asyncResult.IOCompleted(statusCode, bytesReturned); + } return asyncResult; } @@ -322,7 +316,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys if (_dataChunkIndex != -1) { dataRead = _requestContext.Request.GetChunks(ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size); - if (_dataChunkIndex != -1 && dataRead == size) + if (dataRead > 0) { UpdateAfterRead(UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS, dataRead); if (TryCheckSizeLimit((int)dataRead, out var exception)) @@ -334,85 +328,82 @@ namespace Microsoft.AspNetCore.Server.HttpSys } } - if (_dataChunkIndex == -1 && dataRead < size) + uint statusCode = 0; + offset += (int)dataRead; + size -= (int)dataRead; + + // the http.sys team recommends that we limit the size to 128kb + if (size > MaxReadSize) { - uint statusCode = 0; - offset += (int)dataRead; - size -= (int)dataRead; + size = MaxReadSize; + } - // the http.sys team recommends that we limit the size to 128kb - if (size > MaxReadSize) - { - size = MaxReadSize; - } + var cancellationRegistration = default(CancellationTokenRegistration); + if (cancellationToken.CanBeCanceled) + { + cancellationRegistration = RequestContext.RegisterForCancellation(cancellationToken); + } - var cancellationRegistration = default(CancellationTokenRegistration); - if (cancellationToken.CanBeCanceled) - { - cancellationRegistration = RequestContext.RegisterForCancellation(cancellationToken); - } + asyncResult = new RequestStreamAsyncResult(this, null, null, buffer, offset, dataRead, cancellationRegistration); + uint bytesReturned; - asyncResult = new RequestStreamAsyncResult(this, null, null, buffer, offset, dataRead, cancellationRegistration); - uint bytesReturned; + try + { + uint flags = 0; - try - { - uint flags = 0; + statusCode = + HttpApi.HttpReceiveRequestEntityBody( + RequestQueueHandle, + RequestId, + flags, + asyncResult.PinnedBuffer, + (uint)size, + out bytesReturned, + asyncResult.NativeOverlapped); + } + catch (Exception e) + { + asyncResult.Dispose(); + Abort(); + LogHelper.LogException(Logger, "ReadAsync", e); + throw; + } - statusCode = - HttpApi.HttpReceiveRequestEntityBody( - RequestQueueHandle, - RequestId, - flags, - asyncResult.PinnedBuffer, - (uint)size, - out bytesReturned, - asyncResult.NativeOverlapped); - } - catch (Exception e) + if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) + { + asyncResult.Dispose(); + if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) { - asyncResult.Dispose(); - Abort(); - LogHelper.LogException(Logger, "ReadAsync", e); - throw; - } - - if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) - { - asyncResult.Dispose(); - if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) - { - uint totalRead = dataRead + bytesReturned; - UpdateAfterRead(statusCode, totalRead); - if (TryCheckSizeLimit((int)totalRead, out var exception)) - { - return Task.FromException(exception); - } - // TODO: Verbose log totalRead - return Task.FromResult((int)totalRead); - } - else - { - Exception exception = new IOException(string.Empty, new HttpSysException((int)statusCode)); - LogHelper.LogException(Logger, "ReadAsync", exception); - Abort(); - throw exception; - } - } - else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && - HttpSysListener.SkipIOCPCallbackOnSuccess) - { - // IO operation completed synchronously - callback won't be called to signal completion. - asyncResult.Dispose(); uint totalRead = dataRead + bytesReturned; UpdateAfterRead(statusCode, totalRead); if (TryCheckSizeLimit((int)totalRead, out var exception)) { return Task.FromException(exception); } - // TODO: Verbose log + // TODO: Verbose log totalRead return Task.FromResult((int)totalRead); } + else + { + Exception exception = new IOException(string.Empty, new HttpSysException((int)statusCode)); + LogHelper.LogException(Logger, "ReadAsync", exception); + Abort(); + throw exception; + } + } + else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && + HttpSysListener.SkipIOCPCallbackOnSuccess) + { + // IO operation completed synchronously - callback won't be called to signal completion. + asyncResult.Dispose(); + uint totalRead = dataRead + bytesReturned; + UpdateAfterRead(statusCode, totalRead); + if (TryCheckSizeLimit((int)totalRead, out var exception)) + { + return Task.FromException(exception); + } + // TODO: Verbose log + return Task.FromResult((int)totalRead); } return asyncResult.Task; } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs index 9ea7f4805f..baec5a8204 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/RequestBodyTests.cs @@ -344,7 +344,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener content.Block.Release(); context.Dispose(); - await Assert.ThrowsAsync(async () => await responseTask); + await Assert.ThrowsAnyAsync(async () => await responseTask); } } @@ -421,6 +421,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener protected async override Task SerializeToStreamAsync(Stream stream, TransportContext context) { await stream.WriteAsync(new byte[5], 0, 5); + await stream.FlushAsync(); await Block.WaitAsync(); await stream.WriteAsync(new byte[5], 0, 5); } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs index ef56e997cb..0c91833773 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseBodyTests.cs @@ -427,7 +427,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers cts.Cancel(); - await Assert.ThrowsAsync(() => responseTask); + await Assert.ThrowsAnyAsync(() => responseTask); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); Assert.Throws(() => { @@ -458,7 +458,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener // First write sends headers cts.Cancel(); - await Assert.ThrowsAsync(() => responseTask); + await Assert.ThrowsAnyAsync(() => responseTask); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); await Assert.ThrowsAsync(async () => @@ -489,7 +489,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers cts.Cancel(); - await Assert.ThrowsAsync(() => responseTask); + await Assert.ThrowsAnyAsync(() => responseTask); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); // It can take several tries before Write notices the disconnect. for (int i = 0; i < Utilities.WriteRetryLimit; i++) @@ -512,7 +512,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers cts.Cancel(); - await Assert.ThrowsAsync(() => responseTask); + await Assert.ThrowsAnyAsync(() => responseTask); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); // It can take several tries before Write notices the disconnect. for (int i = 0; i < Utilities.WriteRetryLimit; i++) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs index 2a962c69f2..990af071e7 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ResponseSendFileTests.cs @@ -468,7 +468,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener // First write sends headers cts.Cancel(); - await Assert.ThrowsAsync(() => responseTask); + await Assert.ThrowsAnyAsync(() => responseTask); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); await Assert.ThrowsAsync(async () => @@ -499,7 +499,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var context = await server.AcceptAsync(Utilities.DefaultTimeout); // First write sends headers cts.Cancel(); - await Assert.ThrowsAsync(() => responseTask); + await Assert.ThrowsAnyAsync(() => responseTask); Assert.True(context.DisconnectToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5))); // It can take several tries before Send notices the disconnect. for (int i = 0; i < Utilities.WriteRetryLimit; i++) diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs index 60c95a94f1..c15d47fd15 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Listener/ServerTests.cs @@ -96,7 +96,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener Assert.True(canceled.WaitOne(interval), "canceled"); Assert.True(ct.IsCancellationRequested, "IsCancellationRequested"); - await Assert.ThrowsAsync(() => responseTask); + await Assert.ThrowsAnyAsync(() => responseTask); context.Dispose(); } @@ -119,7 +119,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.Listener var context = await server.AcceptAsync(Utilities.DefaultTimeout); client.CancelPendingRequests(); - await Assert.ThrowsAsync(() => responseTask); + await Assert.ThrowsAnyAsync(() => responseTask); var ct = context.DisconnectToken; Assert.True(ct.CanBeCanceled, "CanBeCanceled"); diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs index ebc0fa9f98..ae203ceab1 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyLimitTests.cs @@ -413,6 +413,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys protected async override Task SerializeToStreamAsync(Stream stream, TransportContext context) { await stream.WriteAsync(new byte[10], 0, 10); + await stream.FlushAsync(); Assert.True(await Block.WaitAsync(TimeSpan.FromSeconds(10))); await stream.WriteAsync(new byte[10], 0, 10); } diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs index 1b87920103..b7a18867d9 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestBodyTests.cs @@ -232,7 +232,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys protected async override Task SerializeToStreamAsync(Stream stream, TransportContext context) { await stream.WriteAsync(new byte[5], 0, 5); - await Block.WaitAsync(); + await stream.FlushAsync(); + Assert.True(await Block.WaitAsync(TimeSpan.FromSeconds(10))); await stream.WriteAsync(new byte[5], 0, 5); }