From c60d1e1a14691a624f46b350f6561dc752e3964c Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Mon, 7 Jan 2019 15:04:28 -0800 Subject: [PATCH] Handle EOF HResult from async callback (#6453) --- .../managedexports.cpp | 12 ------ .../IIS/IIS/src/Core/IO/AsyncIOEngine.Read.cs | 2 + .../IIS/IIS/src/Core/IO/AsyncIOOperation.cs | 4 +- .../Core/IO/WebSocketsAsyncIOEngine.Read.cs | 2 + src/Servers/IIS/IIS/src/NativeMethods.cs | 2 +- .../Inprocess/SynchronousReadAndWriteTests.cs | 39 +++++++++++++++++++ .../testassets/InProcessWebSite/Startup.cs | 7 ++++ src/Servers/IIS/IISIntegration.NoV1.sln | 35 +++++++++++------ 8 files changed, 77 insertions(+), 26 deletions(-) diff --git a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp index 78b61f4446..6f52892b6f 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp @@ -246,12 +246,6 @@ http_read_request_bytes( fAsync, pdwBytesReceived, pfCompletionPending); - - if (hr == HRESULT_FROM_WIN32(ERROR_HANDLE_EOF)) - { - // We reached the end of the data - hr = S_OK; - } } else { @@ -333,12 +327,6 @@ http_websockets_read_bytes( pDwBytesReceived, pfCompletionPending); - if (hr == HRESULT_FROM_WIN32(ERROR_HANDLE_EOF)) - { - // We reached the end of the data - hr = S_OK; - } - return hr; } diff --git a/src/Servers/IIS/IIS/src/Core/IO/AsyncIOEngine.Read.cs b/src/Servers/IIS/IIS/src/Core/IO/AsyncIOEngine.Read.cs index 00c6709453..abe60ccea6 100644 --- a/src/Servers/IIS/IIS/src/Core/IO/AsyncIOEngine.Read.cs +++ b/src/Servers/IIS/IIS/src/Core/IO/AsyncIOEngine.Read.cs @@ -58,6 +58,8 @@ namespace Microsoft.AspNetCore.Server.IIS.Core.IO { _inputHandle.Dispose(); } + + protected override bool IsSuccessfulResult(int hr) => hr == NativeMethods.ERROR_HANDLE_EOF; } } } diff --git a/src/Servers/IIS/IIS/src/Core/IO/AsyncIOOperation.cs b/src/Servers/IIS/IIS/src/Core/IO/AsyncIOOperation.cs index 0f8b533071..32e137f598 100644 --- a/src/Servers/IIS/IIS/src/Core/IO/AsyncIOOperation.cs +++ b/src/Servers/IIS/IIS/src/Core/IO/AsyncIOOperation.cs @@ -102,7 +102,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core.IO if (hr != NativeMethods.ERROR_OPERATION_ABORTED) { _result = bytes; - if (hr != NativeMethods.HR_OK) + if (hr != NativeMethods.HR_OK && !IsSuccessfulResult(hr)) { // Treat all errors as the client disconnect _exception = new ConnectionResetException("The client has disconnected", Marshal.GetExceptionForHR(hr)); @@ -126,6 +126,8 @@ namespace Microsoft.AspNetCore.Server.IIS.Core.IO return asyncContinuation; } + protected virtual bool IsSuccessfulResult(int hr) => false; + public virtual void FreeOperationResources(int hr, int bytes) { } protected virtual void ResetOperation() diff --git a/src/Servers/IIS/IIS/src/Core/IO/WebSocketsAsyncIOEngine.Read.cs b/src/Servers/IIS/IIS/src/Core/IO/WebSocketsAsyncIOEngine.Read.cs index 413fa77703..2dac1a234e 100644 --- a/src/Servers/IIS/IIS/src/Core/IO/WebSocketsAsyncIOEngine.Read.cs +++ b/src/Servers/IIS/IIS/src/Core/IO/WebSocketsAsyncIOEngine.Read.cs @@ -74,6 +74,8 @@ namespace Microsoft.AspNetCore.Server.IIS.Core.IO _engine.ReturnOperation(this); } + + protected override bool IsSuccessfulResult(int hr) => hr == NativeMethods.ERROR_HANDLE_EOF; } } } diff --git a/src/Servers/IIS/IIS/src/NativeMethods.cs b/src/Servers/IIS/IIS/src/NativeMethods.cs index 8e5e484edd..4702d29a57 100644 --- a/src/Servers/IIS/IIS/src/NativeMethods.cs +++ b/src/Servers/IIS/IIS/src/NativeMethods.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Server.IIS internal const int ERROR_NOT_FOUND = unchecked((int)0x80070490); internal const int ERROR_OPERATION_ABORTED = unchecked((int)0x800703E3); internal const int ERROR_INVALID_PARAMETER = unchecked((int)0x80070057); - internal const int COR_E_IO = unchecked((int)0x80131620); + internal const int ERROR_HANDLE_EOF = unchecked((int)0x80070026); private const string KERNEL32 = "kernel32.dll"; diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/SynchronousReadAndWriteTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/SynchronousReadAndWriteTests.cs index 03aa0e16e6..ae8bf44217 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/SynchronousReadAndWriteTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/SynchronousReadAndWriteTests.cs @@ -193,5 +193,44 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests await connection.WaitForConnectionClose(); } } + + [ConditionalFact] + [RequiresNewHandler] + public async Task AsyncChunkedPostIsAccepted() + { + // This test sends a lot of request because we are trying to force + // different async completion modes from IIS + for (int i = 0; i < 100; i++) + { + using (var connection = _fixture.CreateTestConnection()) + { + await connection.Send( + "POST /ReadFullBody HTTP/1.1", + $"Transfer-Encoding: chunked", + "Host: localhost", + "Connection: close", + "", + ""); + + await connection.Send("5", + "Hello", + ""); + + await connection.Send( + "0", + "", + ""); + + await connection.Receive( + "HTTP/1.1 200 OK", + ""); + + await connection.ReceiveHeaders(); + await connection.Receive("Completed"); + + await connection.WaitForConnectionClose(); + } + } + } } } diff --git a/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.cs b/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.cs index b156efa966..fb505a14ec 100644 --- a/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.cs +++ b/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.cs @@ -283,6 +283,13 @@ namespace TestSite } } + private async Task ReadFullBody(HttpContext ctx) + { + await ReadRequestBody(ctx); + ctx.Response.ContentLength = 9; + await ctx.Response.WriteAsync("Completed"); + } + private async Task WriteManyTimesToResponseBody(HttpContext ctx) { for (var i = 0; i < 10000; i++) diff --git a/src/Servers/IIS/IISIntegration.NoV1.sln b/src/Servers/IIS/IISIntegration.NoV1.sln index b1384237d4..39acf0c539 100644 --- a/src/Servers/IIS/IISIntegration.NoV1.sln +++ b/src/Servers/IIS/IISIntegration.NoV1.sln @@ -118,6 +118,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonLibTests", "AspNetCor EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IISSample", "IISIntegration\samples\IISSample\IISSample.csproj", "{2C720685-FBE2-4450-9A01-CAA327D3485A}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest", "AspNetCoreModuleV2\gtest\gtest.vcxproj", "{CAC1267B-8778-4257-AAC6-CAF481723B01}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -260,18 +262,16 @@ Global {D182103F-8405-4647-B158-C36F598657EF}.Release|x64.Build.0 = Release|Any CPU {D182103F-8405-4647-B158-C36F598657EF}.Release|x86.ActiveCfg = Release|Any CPU {D182103F-8405-4647-B158-C36F598657EF}.Release|x86.Build.0 = Release|Any CPU - {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Debug|x64.ActiveCfg = Debug|Any CPU - {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Debug|x64.Build.0 = Debug|Any CPU - {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Debug|x86.ActiveCfg = Debug|Any CPU - {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Debug|x86.Build.0 = Debug|Any CPU - {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Release|Any CPU.Build.0 = Release|Any CPU - {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Release|x64.ActiveCfg = Release|Any CPU - {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Release|x64.Build.0 = Release|Any CPU - {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Release|x86.ActiveCfg = Release|Any CPU - {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Release|x86.Build.0 = Release|Any CPU + {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Debug|Any CPU.ActiveCfg = Debug|x86 + {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Debug|x64.ActiveCfg = Debug|x64 + {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Debug|x64.Build.0 = Debug|x64 + {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Debug|x86.ActiveCfg = Debug|x86 + {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Debug|x86.Build.0 = Debug|x86 + {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Release|Any CPU.ActiveCfg = Release|x86 + {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Release|x64.ActiveCfg = Release|x64 + {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Release|x64.Build.0 = Release|x64 + {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Release|x86.ActiveCfg = Release|x86 + {C0310D84-BC2F-4B2E-870E-D35044DB3E3E}.Release|x86.Build.0 = Release|x86 {D17B7B35-5361-4A50-B499-E03E5C3CC095}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D17B7B35-5361-4A50-B499-E03E5C3CC095}.Debug|Any CPU.Build.0 = Debug|Any CPU {D17B7B35-5361-4A50-B499-E03E5C3CC095}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -396,6 +396,16 @@ Global {2C720685-FBE2-4450-9A01-CAA327D3485A}.Release|x64.Build.0 = Release|Any CPU {2C720685-FBE2-4450-9A01-CAA327D3485A}.Release|x86.ActiveCfg = Release|Any CPU {2C720685-FBE2-4450-9A01-CAA327D3485A}.Release|x86.Build.0 = Release|Any CPU + {CAC1267B-8778-4257-AAC6-CAF481723B01}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {CAC1267B-8778-4257-AAC6-CAF481723B01}.Debug|x64.ActiveCfg = Debug|x64 + {CAC1267B-8778-4257-AAC6-CAF481723B01}.Debug|x64.Build.0 = Debug|x64 + {CAC1267B-8778-4257-AAC6-CAF481723B01}.Debug|x86.ActiveCfg = Debug|Win32 + {CAC1267B-8778-4257-AAC6-CAF481723B01}.Debug|x86.Build.0 = Debug|Win32 + {CAC1267B-8778-4257-AAC6-CAF481723B01}.Release|Any CPU.ActiveCfg = Release|Win32 + {CAC1267B-8778-4257-AAC6-CAF481723B01}.Release|x64.ActiveCfg = Release|x64 + {CAC1267B-8778-4257-AAC6-CAF481723B01}.Release|x64.Build.0 = Release|x64 + {CAC1267B-8778-4257-AAC6-CAF481723B01}.Release|x86.ActiveCfg = Release|Win32 + {CAC1267B-8778-4257-AAC6-CAF481723B01}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -434,6 +444,7 @@ Global {01452FA1-65C9-4A38-A544-E55E63B93357} = {98DA3CDD-571F-412F-9CAB-6543CE81EC30} {1EAC8125-1765-4E2D-8CBE-56DC98A1C8C1} = {06CA2C2B-83B0-4D83-905A-E0C74790009E} {2C720685-FBE2-4450-9A01-CAA327D3485A} = {F10CFC80-ED34-4B58-9A29-0E915A2FFFF3} + {CAC1267B-8778-4257-AAC6-CAF481723B01} = {06CA2C2B-83B0-4D83-905A-E0C74790009E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DB4F868D-E1AE-4FD7-9333-69FA15B268C5}