From b0deed05be7710d80e28a1ce95ff4e760939644b Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Mon, 15 Oct 2018 10:33:14 -0700 Subject: [PATCH] Add server abort tests (#1510) --- build/launchSettings.json | 11 ++-- build/testsite.props | 2 - .../Properties/launchSettings.json | 7 +- .../AspNetCore/HandlerResolver.cpp | 14 +++- test/Common.FunctionalTests/BasicAuthTests.cs | 1 - .../Inprocess/FixtureLoggedTest.cs | 2 +- .../ServerAbortTests.cs | 65 +++++++++++++++++++ .../Utilities/IISTestSiteCollection.cs | 13 ++++ .../Utilities/IISTestSiteFixture.cs | 28 +++++++- .../OutOfProcess/GlobalVersionTests.cs | 30 +++++++++ .../Properties/launchSettings.json | 11 ++-- .../Properties/launchSettings.json | 11 ++-- .../Properties/launchSettings.json | 11 ++-- .../shared/SharedStartup/Startup.shared.cs | 8 ++- 14 files changed, 182 insertions(+), 32 deletions(-) create mode 100644 test/Common.FunctionalTests/ServerAbortTests.cs diff --git a/build/launchSettings.json b/build/launchSettings.json index 9c963c0100..246b7a0b47 100644 --- a/build/launchSettings.json +++ b/build/launchSettings.json @@ -12,11 +12,11 @@ "commandName": "Executable", "executablePath": "$(IISExpressPath)", "commandLineArgs": "$(IISExpressArguments)", - "nativeDebugging": true, "environmentVariables": { "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", - "ANCM_PATH": "$(TargetDir)\\$(AncmPath)", - "ANCMV2_PATH": "$(TargetDir)\\$(AncmV2Path)", + "ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)", + "ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)", + "ANCM_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", @@ -29,8 +29,9 @@ "commandLineArgs": "$(IISArguments)", "environmentVariables": { "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", - "ANCM_PATH": "$(AncmPath)", - "ANCMV2_PATH": "$(AncmV2Path)", + "ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)", + "ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)", + "ASPNETCORE_MODULE_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", diff --git a/build/testsite.props b/build/testsite.props index 861d44a563..1ef6bf81cc 100644 --- a/build/testsite.props +++ b/build/testsite.props @@ -36,8 +36,6 @@ /config:"$(IISExpressAppHostConfig)" /systray:false -h "$(IISAppHostConfig)" - $(AspNetCoreModuleV1ShimDll) - $(AspNetCoreModuleV2ShimDll) aspnetcorev2_inprocess.dll $(userprofile)\.dotnet\$(NativePlatform)\dotnet.exe diff --git a/samples/NativeIISSample/Properties/launchSettings.json b/samples/NativeIISSample/Properties/launchSettings.json index 9c963c0100..f62697de39 100644 --- a/samples/NativeIISSample/Properties/launchSettings.json +++ b/samples/NativeIISSample/Properties/launchSettings.json @@ -12,11 +12,11 @@ "commandName": "Executable", "executablePath": "$(IISExpressPath)", "commandLineArgs": "$(IISExpressArguments)", - "nativeDebugging": true, "environmentVariables": { "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", - "ANCM_PATH": "$(TargetDir)\\$(AncmPath)", - "ANCMV2_PATH": "$(TargetDir)\\$(AncmV2Path)", + "ANCM_PATH": "$(AncmPath)", + "ANCMV2_PATH": "$(AncmV2Path)", + "ANCM_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", @@ -31,6 +31,7 @@ "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", "ANCM_PATH": "$(AncmPath)", "ANCMV2_PATH": "$(AncmV2Path)", + "ANCM_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", diff --git a/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp index 726229cc9e..44210d8b68 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp +++ b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp @@ -16,6 +16,7 @@ #include "WebConfigConfigurationSource.h" #include "ModuleHelpers.h" #include "BaseOutputManager.h" +#include "Environment.h" const PCWSTR HandlerResolver::s_pwzAspnetcoreInProcessRequestHandlerName = L"aspnetcorev2_inprocess.dll"; const PCWSTR HandlerResolver::s_pwzAspnetcoreOutOfProcessRequestHandlerName = L"aspnetcorev2_outofprocess.dll"; @@ -103,12 +104,12 @@ HandlerResolver::LoadRequestHandlerAssembly(const IHttpApplication &pApplication LOG_INFOF(L"Loading request handler: '%ls'", handlerDllPath.c_str()); hRequestHandlerDll = LoadLibrary(handlerDllPath.c_str()); + RETURN_LAST_ERROR_IF_NULL(hRequestHandlerDll); if (preventUnload) { // Pin module in memory - GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN, pstrHandlerDllName, &hRequestHandlerDll); + GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN, handlerDllPath.c_str(), &hRequestHandlerDll); } - RETURN_LAST_ERROR_IF_NULL(hRequestHandlerDll); } auto pfnAspNetCoreCreateApplication = ModuleHelpers::GetKnownProcAddress(hRequestHandlerDll, "CreateApplication"); @@ -150,7 +151,7 @@ HandlerResolver::GetApplicationFactory(const IHttpApplication &pApplication, std m_loadedApplicationHostingModel = options.QueryHostingModel(); m_loadedApplicationId = pApplication.GetApplicationId(); RETURN_IF_FAILED(LoadRequestHandlerAssembly(pApplication, options, pApplicationFactory)); - + return S_OK; } @@ -171,6 +172,13 @@ HandlerResolver::FindNativeAssemblyFromGlobalLocation( { try { + auto handlerPath = Environment::GetEnvironmentVariableValue(L"ASPNETCORE_MODULE_OUTOFPROCESS_HANDLER"); + if (handlerPath.has_value() && std::filesystem::is_regular_file(handlerPath.value())) + { + handlerDllPath = handlerPath.value(); + return S_OK; + } + std::wstring modulePath = GlobalVersionUtility::GetModuleName(m_hModule); modulePath = GlobalVersionUtility::RemoveFileNameFromFolderPath(modulePath); diff --git a/test/Common.FunctionalTests/BasicAuthTests.cs b/test/Common.FunctionalTests/BasicAuthTests.cs index 1c7faf00b4..d8607db21e 100644 --- a/test/Common.FunctionalTests/BasicAuthTests.cs +++ b/test/Common.FunctionalTests/BasicAuthTests.cs @@ -6,7 +6,6 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities; using Microsoft.AspNetCore.Server.IntegrationTesting; using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; diff --git a/test/Common.FunctionalTests/Inprocess/FixtureLoggedTest.cs b/test/Common.FunctionalTests/Inprocess/FixtureLoggedTest.cs index 4604687991..705af2b213 100644 --- a/test/Common.FunctionalTests/Inprocess/FixtureLoggedTest.cs +++ b/test/Common.FunctionalTests/Inprocess/FixtureLoggedTest.cs @@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { _fixture = fixture; } - + public override void Initialize(MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper) { base.Initialize(methodInfo, testMethodArguments, testOutputHelper); diff --git a/test/Common.FunctionalTests/ServerAbortTests.cs b/test/Common.FunctionalTests/ServerAbortTests.cs new file mode 100644 index 0000000000..8ebd70db12 --- /dev/null +++ b/test/Common.FunctionalTests/ServerAbortTests.cs @@ -0,0 +1,65 @@ +// 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.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Server.IntegrationTesting; +using Microsoft.AspNetCore.Testing.xunit; +using Xunit; + +namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests +{ + public abstract class ServerAbortTests: FixtureLoggedTest + { + private readonly IISTestSiteFixture _fixture; + + [Collection(IISTestSiteCollection.Name)] + public class InProc: ServerAbortTests + { + public InProc(IISTestSiteFixture fixture) : base(fixture) { } + } + + [Collection(OutOfProcessTestSiteCollection.Name)] + public class OutOfProcess: ServerAbortTests + { + public OutOfProcess(OutOfProcessTestSiteFixture fixture) : base(fixture) { } + } + + [Collection(OutOfProcessV1TestSiteCollection.Name)] + public class OutOfProcessV1: ServerAbortTests + { + public OutOfProcessV1(OutOfProcessV1TestSiteFixture fixture) : base(fixture) { } + } + + protected ServerAbortTests(IISTestSiteFixture fixture) : base(fixture) + { + _fixture = fixture; + } + + [ConditionalFact] + public async Task ClosesConnectionOnServerAbort() + { + try + { + var response = await _fixture.Client.GetAsync("/Abort").DefaultTimeout(); + + // 502 is expected for outofproc but not for inproc + if (_fixture.DeploymentResult.DeploymentParameters.HostingModel == HostingModel.OutOfProcess) + { + Assert.Equal(HttpStatusCode.BadGateway, response.StatusCode); + // 0x80072f78 ERROR_HTTP_INVALID_SERVER_RESPONSE The server returned an invalid or unrecognized response + Assert.Contains("0x80072f78", await response.Content.ReadAsStringAsync()); + } + else + { + Assert.True(false, "Should not reach here"); + } + } + catch (HttpRequestException) + { + // Connection reset is expected both for outofproc and inproc + } + } + } +} diff --git a/test/Common.FunctionalTests/Utilities/IISTestSiteCollection.cs b/test/Common.FunctionalTests/Utilities/IISTestSiteCollection.cs index 8d53affc98..562d63adbe 100644 --- a/test/Common.FunctionalTests/Utilities/IISTestSiteCollection.cs +++ b/test/Common.FunctionalTests/Utilities/IISTestSiteCollection.cs @@ -13,4 +13,17 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { public const string Name = nameof(IISTestSiteCollection); } + + [CollectionDefinition(Name)] + public class OutOfProcessTestSiteCollection : ICollectionFixture + { + public const string Name = nameof(OutOfProcessTestSiteCollection); + } + + [CollectionDefinition(Name)] + public class OutOfProcessV1TestSiteCollection : ICollectionFixture + { + public const string Name = nameof(OutOfProcessV1TestSiteCollection); + } + } diff --git a/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs b/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs index 5628a1acfb..e8cfd8f641 100644 --- a/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs +++ b/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Net.Http; -using System.Threading; using Microsoft.AspNetCore.Server.IntegrationTesting; using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.Extensions.Logging; @@ -12,6 +11,33 @@ using Microsoft.Extensions.Logging.Testing; namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { + public class OutOfProcessTestSiteFixture : IISTestSiteFixture + { + public OutOfProcessTestSiteFixture() : base(Configure) + { + } + + private static void Configure(IISDeploymentParameters deploymentParameters) + { + deploymentParameters.ApplicationPath = Helpers.GetOutOfProcessTestSitesPath(); + deploymentParameters.HostingModel = HostingModel.OutOfProcess; + } + } + + public class OutOfProcessV1TestSiteFixture : IISTestSiteFixture + { + public OutOfProcessV1TestSiteFixture() : base(Configure) + { + } + + private static void Configure(IISDeploymentParameters deploymentParameters) + { + deploymentParameters.ApplicationPath = Helpers.GetOutOfProcessTestSitesPath(); + deploymentParameters.HostingModel = HostingModel.OutOfProcess; + deploymentParameters.AncmVersion = AncmVersion.AspNetCoreModule; + } + } + public class IISTestSiteFixture : IDisposable { private ApplicationDeployer _deployer; diff --git a/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs b/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs index c92349ae3a..4757c1d59b 100644 --- a/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs +++ b/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs @@ -1,6 +1,7 @@ // 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; using System.IO; using System.Linq; using System.Net; @@ -52,6 +53,35 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests Assert.Equal(_helloWorldResponse, responseText); } + [ConditionalFact] + [RequiresIIS(IISCapability.PoolEnvironmentVariables)] + public async Task GlobalVersion_EnvironmentVariableWorks() + { + var temporaryFile = Path.GetTempFileName(); + try + { + var deploymentParameters = GetGlobalVersionBaseDeploymentParameters(); + CopyShimToOutput(deploymentParameters); + deploymentParameters.PublishApplicationBeforeDeployment = true; + deploymentParameters.EnvironmentVariables["ASPNETCORE_MODULE_OUTOFPROCESS_HANDLER"] = temporaryFile; + + var deploymentResult = await DeployAsync(deploymentParameters); + var requestHandlerPath = Path.Combine(GetANCMRequestHandlerPath(deploymentResult, _handlerVersion20), "aspnetcorev2_outofprocess.dll"); + + File.Delete(temporaryFile); + File.Move(requestHandlerPath, temporaryFile); + + var response = await deploymentResult.HttpClient.GetAsync(_helloWorldRequest); + var responseText = await response.Content.ReadAsStringAsync(); + Assert.Equal(_helloWorldResponse, responseText); + StopServer(); + } + finally + { + File.Delete(temporaryFile); + } + } + [ConditionalTheory] [InlineData("2.1.0")] [InlineData("2.1.0-preview")] diff --git a/test/WebSites/InProcessWebSite/Properties/launchSettings.json b/test/WebSites/InProcessWebSite/Properties/launchSettings.json index 9c963c0100..246b7a0b47 100644 --- a/test/WebSites/InProcessWebSite/Properties/launchSettings.json +++ b/test/WebSites/InProcessWebSite/Properties/launchSettings.json @@ -12,11 +12,11 @@ "commandName": "Executable", "executablePath": "$(IISExpressPath)", "commandLineArgs": "$(IISExpressArguments)", - "nativeDebugging": true, "environmentVariables": { "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", - "ANCM_PATH": "$(TargetDir)\\$(AncmPath)", - "ANCMV2_PATH": "$(TargetDir)\\$(AncmV2Path)", + "ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)", + "ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)", + "ANCM_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", @@ -29,8 +29,9 @@ "commandLineArgs": "$(IISArguments)", "environmentVariables": { "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", - "ANCM_PATH": "$(AncmPath)", - "ANCMV2_PATH": "$(AncmV2Path)", + "ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)", + "ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)", + "ASPNETCORE_MODULE_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", diff --git a/test/WebSites/OutOfProcessWebSite/Properties/launchSettings.json b/test/WebSites/OutOfProcessWebSite/Properties/launchSettings.json index 9c963c0100..246b7a0b47 100644 --- a/test/WebSites/OutOfProcessWebSite/Properties/launchSettings.json +++ b/test/WebSites/OutOfProcessWebSite/Properties/launchSettings.json @@ -12,11 +12,11 @@ "commandName": "Executable", "executablePath": "$(IISExpressPath)", "commandLineArgs": "$(IISExpressArguments)", - "nativeDebugging": true, "environmentVariables": { "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", - "ANCM_PATH": "$(TargetDir)\\$(AncmPath)", - "ANCMV2_PATH": "$(TargetDir)\\$(AncmV2Path)", + "ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)", + "ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)", + "ANCM_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", @@ -29,8 +29,9 @@ "commandLineArgs": "$(IISArguments)", "environmentVariables": { "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", - "ANCM_PATH": "$(AncmPath)", - "ANCMV2_PATH": "$(AncmV2Path)", + "ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)", + "ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)", + "ASPNETCORE_MODULE_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", diff --git a/test/WebSites/StressTestWebSite/Properties/launchSettings.json b/test/WebSites/StressTestWebSite/Properties/launchSettings.json index 9c963c0100..246b7a0b47 100644 --- a/test/WebSites/StressTestWebSite/Properties/launchSettings.json +++ b/test/WebSites/StressTestWebSite/Properties/launchSettings.json @@ -12,11 +12,11 @@ "commandName": "Executable", "executablePath": "$(IISExpressPath)", "commandLineArgs": "$(IISExpressArguments)", - "nativeDebugging": true, "environmentVariables": { "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", - "ANCM_PATH": "$(TargetDir)\\$(AncmPath)", - "ANCMV2_PATH": "$(TargetDir)\\$(AncmV2Path)", + "ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)", + "ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)", + "ANCM_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", @@ -29,8 +29,9 @@ "commandLineArgs": "$(IISArguments)", "environmentVariables": { "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", - "ANCM_PATH": "$(AncmPath)", - "ANCMV2_PATH": "$(AncmV2Path)", + "ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)", + "ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)", + "ASPNETCORE_MODULE_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", diff --git a/test/WebSites/shared/SharedStartup/Startup.shared.cs b/test/WebSites/shared/SharedStartup/Startup.shared.cs index 2c08c93fa6..4035decb02 100644 --- a/test/WebSites/shared/SharedStartup/Startup.shared.cs +++ b/test/WebSites/shared/SharedStartup/Startup.shared.cs @@ -68,10 +68,16 @@ namespace TestSite } finally { - Interlocked.Decrement(ref _waitingRequestCount); + Interlocked.Decrement(ref _waitingRequestCount); } } + public Task Abort(HttpContext context) + { + context.Abort(); + return Task.CompletedTask; + } + public async Task WaitingRequestCount(HttpContext context) { await context.Response.WriteAsync(_waitingRequestCount.ToString());