From 1e143c71c66ce7148d04b8d59e9bd2b0f6e2850a Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Thu, 24 May 2018 08:11:40 -0700 Subject: [PATCH] Add Hostable Web Core based inprocess test server (#853) --- .../IIS.Performance/IIS.Performance.csproj | 12 +- .../IIS.Performance/PlaintextBenchmark.cs | 73 +++ .../IIS.Performance/StartupTimeBenchmark.cs | 1 - .../AspNetCore/AspNetCore.vcxproj | 522 +++++++++--------- .../AspNetCore/Inc/applicationinfo.h | 10 +- .../AspNetCore/Inc/aspnetcore_shim_config.h | 57 +- .../AspNetCore/src/applicationinfo.cpp | 119 ++-- .../AspNetCore/src/aspnetcore_shim_config.cpp | 36 +- .../AspNetCore/src/precomp.hxx | 2 +- .../AspNetCore/src/proxymodule.cxx | 6 +- .../CommonLib/CommonLib.vcxproj | 456 +++++++-------- .../CommonLib/environmentvariablehelpers.h | 10 +- .../CommonLib/hostfxroptions.cpp | 102 ++++ .../CommonLib/hostfxroptions.h | 58 ++ .../CommonLib/requesthandler_config.cpp | 58 -- .../CommonLib/requesthandler_config.h | 38 +- src/AspNetCoreModuleV2/CommonLib/stdafx.h | 2 +- .../InProcessRequestHandler/dllmain.cxx | 4 +- .../inprocess/inprocessapplication.cpp | 77 ++- .../inprocess/inprocessapplication.h | 16 +- .../managedexports.cxx | 7 + .../OutOfProcessRequestHandler/dllmain.cxx | 4 +- .../Core/IISHttpServer.cs | 2 + .../NativeMethods.cs | 2 +- .../AppHostConfig/TestServer.config | 201 +++++++ .../IISIntegration.FunctionalTests.csproj | 22 + .../Inprocess/TestServerTest.cs | 41 ++ ...pIfHostableWebCoreNotAvailibleAttribute.cs | 17 + .../Utilities/TestServer.cs | 144 +++++ 29 files changed, 1329 insertions(+), 770 deletions(-) create mode 100644 benchmarks/IIS.Performance/PlaintextBenchmark.cs create mode 100644 src/AspNetCoreModuleV2/CommonLib/hostfxroptions.cpp create mode 100644 src/AspNetCoreModuleV2/CommonLib/hostfxroptions.h create mode 100644 test/IISIntegration.FunctionalTests/AppHostConfig/TestServer.config create mode 100644 test/IISIntegration.FunctionalTests/Inprocess/TestServerTest.cs create mode 100644 test/IISIntegration.FunctionalTests/Utilities/SkipIfHostableWebCoreNotAvailibleAttribute.cs create mode 100644 test/IISIntegration.FunctionalTests/Utilities/TestServer.cs diff --git a/benchmarks/IIS.Performance/IIS.Performance.csproj b/benchmarks/IIS.Performance/IIS.Performance.csproj index 6fb9ab2c05..179e042514 100644 --- a/benchmarks/IIS.Performance/IIS.Performance.csproj +++ b/benchmarks/IIS.Performance/IIS.Performance.csproj @@ -1,4 +1,4 @@ - + @@ -15,13 +15,21 @@ + + + + + + + + False - + diff --git a/benchmarks/IIS.Performance/PlaintextBenchmark.cs b/benchmarks/IIS.Performance/PlaintextBenchmark.cs new file mode 100644 index 0000000000..ff79705756 --- /dev/null +++ b/benchmarks/IIS.Performance/PlaintextBenchmark.cs @@ -0,0 +1,73 @@ +// 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.Net.Http; +using System.Text; +using System.Threading.Tasks; +using BenchmarkDotNet.Attributes; +using IISIntegration.FunctionalTests.Utilities; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; + +namespace Microsoft.AspNetCore.Server.IIS.Performance +{ + [AspNetCoreBenchmark] + public class PlaintextBenchmark + { + private TestServer _server; + + private HttpClient _client; + + [GlobalSetup] + public void Setup() + { + _server = TestServer.Create(builder => builder.UseMiddleware(), new LoggerFactory()).GetAwaiter().GetResult(); + // Recreate client, TestServer.Client has additional logging that can hurt performance + _client = new HttpClient() + { + BaseAddress = _server.HttpClient.BaseAddress + }; + } + + [Benchmark] + public async Task Plaintext() + { + await _client.GetAsync("/plaintext"); + } + + // Copied from https://github.com/aspnet/benchmarks/blob/dev/src/Benchmarks/Middleware/PlaintextMiddleware.cs + public class PlaintextMiddleware + { + private static readonly PathString _path = new PathString("/plaintext"); + private static readonly byte[] _helloWorldPayload = Encoding.UTF8.GetBytes("Hello, World!"); + + private readonly RequestDelegate _next; + + public PlaintextMiddleware(RequestDelegate next) + { + _next = next; + } + + public Task Invoke(HttpContext httpContext) + { + if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal)) + { + return WriteResponse(httpContext.Response); + } + + return _next(httpContext); + } + + public static Task WriteResponse(HttpResponse response) + { + var payloadLength = _helloWorldPayload.Length; + response.StatusCode = 200; + response.ContentType = "text/plain"; + response.ContentLength = payloadLength; + return response.Body.WriteAsync(_helloWorldPayload, 0, payloadLength); + } +} + } +} diff --git a/benchmarks/IIS.Performance/StartupTimeBenchmark.cs b/benchmarks/IIS.Performance/StartupTimeBenchmark.cs index 4cbb53ffaf..4e16e33b49 100644 --- a/benchmarks/IIS.Performance/StartupTimeBenchmark.cs +++ b/benchmarks/IIS.Performance/StartupTimeBenchmark.cs @@ -5,7 +5,6 @@ using System.IO; using System.Net.Http; using System.Threading.Tasks; using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Running; using Microsoft.AspNetCore.Server.IntegrationTesting; using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.Logging.Abstractions; diff --git a/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj b/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj index be9582b9df..baa119b1e6 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj +++ b/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj @@ -1,262 +1,262 @@ - - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {EC82302F-D2F0-4727-99D1-EABC0DD9DC3B} - Win32Proj - AspNetCoreModule - AspNetCore - aspnetcorev2 - false - 10.0.15063.0 - - - - DynamicLibrary - true - v141 - Unicode - - - DynamicLibrary - true - v141 - Unicode - - - DynamicLibrary - false - v141 - true - Unicode - - - DynamicLibrary - false - v141 - true - Unicode - - - - - - - - - - - - - - - - - - - $(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\ - - - - NotUsing - Level4 - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions) - precomp.hxx - $(IntDir)$(TargetName).pch - ..\IISLib;inc;..\CommonLib - ProgramDatabase - MultiThreadedDebug - true - true - true - false - SyncCThrow - 8Bytes - true - false - true - CompileAsCpp - true - - - Windows - true - kernel32.lib;user32.lib;advapi32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies) - Source.def - - - ..\Commonlib - - - - - NotUsing - Level4 - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions) - precomp.hxx - $(IntDir)$(TargetName).pch - ..\IISLib;inc;..\CommonLib - ProgramDatabase - MultiThreadedDebug - true - true - true - false - SyncCThrow - 8Bytes - true - false - true - CompileAsCpp - true - - - Windows - true - kernel32.lib;user32.lib;advapi32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies) - Source.def - - - ..\Commonlib - - - - - Level4 - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions) - ..\IISLib;inc;..\CommonLib - precomp.hxx - MultiThreaded - true - true - true - false - SyncCThrow - 8Bytes - true - false - true - CompileAsCpp - true - - - Windows - false - true - true - Source.def - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;ahadmin.lib;winhttp.lib;odbc32.lib;ws2_32.lib;odbccp32.lib;wbemuuid.lib;iphlpapi.lib;pdh.lib;rpcrt4.lib;%(AdditionalDependencies) - - - ..\Commonlib - - - - - Level4 - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions) - precomp.hxx - ..\IISLib;inc;..\CommonLib - MultiThreaded - true - true - true - false - SyncCThrow - 8Bytes - true - false - true - CompileAsCpp - true - - - Windows - false - true - true - Source.def - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies) - - - ..\Commonlib - - - - - - - - - - - - - - - - - - - - - - - - {55494e58-e061-4c4c-a0a8-837008e72f85} - - - {09d9d1d6-2951-4e14-bc35-76a23cf9391a} - - - - - - - - - - - - PreserveNewest - - - PreserveNewest - - - - - - - - - + + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {EC82302F-D2F0-4727-99D1-EABC0DD9DC3B} + Win32Proj + AspNetCoreModule + AspNetCore + aspnetcorev2 + false + 10.0.15063.0 + + + + DynamicLibrary + true + v141 + Unicode + + + DynamicLibrary + true + v141 + Unicode + + + DynamicLibrary + false + v141 + true + Unicode + + + DynamicLibrary + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + $(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\ + + + + NotUsing + Level4 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions) + precomp.hxx + $(IntDir)$(TargetName).pch + ..\IISLib;inc;..\CommonLib + ProgramDatabase + MultiThreadedDebug + true + true + true + false + SyncCThrow + 8Bytes + true + false + true + CompileAsCpp + true + + + Windows + true + kernel32.lib;user32.lib;advapi32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies) + Source.def + + + ..\Commonlib + + + + + NotUsing + Level4 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions) + precomp.hxx + $(IntDir)$(TargetName).pch + ..\IISLib;inc;..\CommonLib + ProgramDatabase + MultiThreadedDebug + true + true + true + false + SyncCThrow + 8Bytes + true + false + true + CompileAsCpp + true + + + Windows + true + kernel32.lib;user32.lib;advapi32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies) + Source.def + + + ..\Commonlib + + + + + Level4 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions) + ..\IISLib;inc;..\CommonLib + precomp.hxx + MultiThreaded + true + true + true + false + SyncCThrow + 8Bytes + true + false + true + CompileAsCpp + true + + + Windows + false + true + true + Source.def + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;ahadmin.lib;winhttp.lib;odbc32.lib;ws2_32.lib;odbccp32.lib;wbemuuid.lib;iphlpapi.lib;pdh.lib;rpcrt4.lib;%(AdditionalDependencies) + + + ..\Commonlib + + + + + Level4 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;ASPNETCOREMODULE_EXPORTS;%(PreprocessorDefinitions) + precomp.hxx + ..\IISLib;inc;..\CommonLib + MultiThreaded + true + true + true + false + SyncCThrow + 8Bytes + true + false + true + CompileAsCpp + true + + + Windows + false + true + true + Source.def + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;ahadmin.lib;rpcrt4.lib;winhttp.lib;pdh.lib;ws2_32.lib;wbemuuid.lib;iphlpapi.lib;%(AdditionalDependencies) + + + ..\Commonlib + + + + + + + + + + + + + + + + + + + + + + + + {55494e58-e061-4c4c-a0a8-837008e72f85} + + + {09d9d1d6-2951-4e14-bc35-76a23cf9391a} + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + + + + + + + \ No newline at end of file diff --git a/src/AspNetCoreModuleV2/AspNetCore/Inc/applicationinfo.h b/src/AspNetCoreModuleV2/AspNetCore/Inc/applicationinfo.h index b40a16c1a9..1743f6eb29 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/Inc/applicationinfo.h +++ b/src/AspNetCoreModuleV2/AspNetCore/Inc/applicationinfo.h @@ -2,6 +2,7 @@ // Licensed under the MIT License. See License.txt in the project root for license information. #pragma once + #define API_BUFFER_TOO_SMALL 0x80008098 extern BOOL g_fRecycleProcessCalled; @@ -147,14 +148,13 @@ public: HRESULT EnsureApplicationCreated( - IHttpContext *pHttpContext, - STRU* exeLocation + IHttpContext *pHttpContext ); private: - HRESULT FindRequestHandlerAssembly(); - HRESULT FindNativeAssemblyFromGlobalLocation(STRU* struFilename); - HRESULT FindNativeAssemblyFromHostfxr(STRU* struFilename); + HRESULT FindRequestHandlerAssembly(STRU& location); + HRESULT FindNativeAssemblyFromGlobalLocation(PCWSTR libraryName, STRU* location); + HRESULT FindNativeAssemblyFromHostfxr(HOSTFXR_OPTIONS* hostfxrOptions, PCWSTR libraryName, STRU* location); static VOID DoRecycleApplication(LPVOID lpParam); diff --git a/src/AspNetCoreModuleV2/AspNetCore/Inc/aspnetcore_shim_config.h b/src/AspNetCoreModuleV2/AspNetCore/Inc/aspnetcore_shim_config.h index 55cbd4ca7b..8a114a69b4 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/Inc/aspnetcore_shim_config.h +++ b/src/AspNetCoreModuleV2/AspNetCore/Inc/aspnetcore_shim_config.h @@ -26,8 +26,6 @@ public: _In_ IHttpServer *pHttpServer, _In_ HTTP_MODULE_ID pModuleId, _In_ IHttpApplication *pHttpApplication, - _In_ HANDLE hEventLog, - _Out_ STRU *pcwzExePath, _Out_ ASPNETCORE_SHIM_CONFIG **ppAspNetCoreConfig ); @@ -72,24 +70,6 @@ public: return &m_struApplication; } - CONST - PCWSTR* - QueryHostFxrArguments( - VOID - ) - { - return m_ppStrArguments; - } - - CONST - DWORD - QueryHostFxrArgCount( - VOID - ) - { - return m_dwArgc; - } - STRU* QueryConfigPath( VOID @@ -114,14 +94,6 @@ public: return &m_struArguments; } - HRESULT - SetHostFxrFullPath( - PCWSTR pStrHostFxrFullPath - ) - { - return m_struHostFxrLocation.Copy(pStrHostFxrFullPath); - } - APP_HOSTING_MODEL QueryHostingModel( VOID @@ -130,35 +102,10 @@ public: return m_hostingModel; } - CONST - PCWSTR - QueryHostFxrFullPath( - VOID - ) - { - return m_struHostFxrLocation.QueryStr(); - } - - VOID - SetHostFxrArguments( - DWORD dwArgc, - PWSTR* ppStrArguments - ) - { - if (m_ppStrArguments != NULL) - { - delete[] m_ppStrArguments; - } - - m_dwArgc = dwArgc; - m_ppStrArguments = ppStrArguments; - } - private: ASPNETCORE_SHIM_CONFIG() : m_cRefs(1), - m_hostingModel(HOSTING_UNKNOWN), - m_ppStrArguments(NULL) + m_hostingModel(HOSTING_UNKNOWN) { } @@ -170,7 +117,5 @@ private: STRU m_struConfigPath; APP_HOSTING_MODEL m_hostingModel; STRU m_struHostFxrLocation; - PWSTR* m_ppStrArguments; - DWORD m_dwArgc; }; diff --git a/src/AspNetCoreModuleV2/AspNetCore/src/applicationinfo.cpp b/src/AspNetCoreModuleV2/AspNetCore/src/applicationinfo.cpp index 6d7ea5bbf1..c2671bcdda 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/src/applicationinfo.cpp +++ b/src/AspNetCoreModuleV2/AspNetCore/src/applicationinfo.cpp @@ -106,22 +106,16 @@ APPLICATION_INFO::UpdateAppOfflineFileHandle() ReferenceApplicationInfo(); - if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(strFilePath.QueryStr()) && - GetLastError() == ERROR_FILE_NOT_FOUND) + if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(strFilePath.QueryStr())) { // Check if app offline was originally present. // if it was, log that app_offline has been dropped. if (m_fAppOfflineFound) { - STACK_STRU(strEventMsg, 256); - if (SUCCEEDED(strEventMsg.SafeSnwprintf( - ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_REMOVED_MSG))) - { - UTILITY::LogEvent(g_hEventLog, - EVENTLOG_INFORMATION_TYPE, - ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_REMOVED, - strEventMsg.QueryStr()); - } + UTILITY::LogEvent(g_hEventLog, + EVENTLOG_INFORMATION_TYPE, + ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_REMOVED, + ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_REMOVED_MSG); } m_fAppOfflineFound = FALSE; @@ -178,13 +172,13 @@ APPLICATION_INFO::UpdateAppOfflineFileHandle() HRESULT APPLICATION_INFO::EnsureApplicationCreated( - IHttpContext *pHttpContext, - STRU* struExeLocation + IHttpContext *pHttpContext ) { HRESULT hr = S_OK; BOOL fLocked = FALSE; IAPPLICATION *pApplication = NULL; + STRU struExeLocation; STACK_STRU(struFileName, 300); // >MAX_PATH STRU struHostFxrDllLocation; @@ -213,7 +207,7 @@ APPLICATION_INFO::EnsureApplicationCreated( // FindRequestHandlerAssembly obtains a global lock, but after releasing the lock, // there is a period where we could call - hr = FindRequestHandlerAssembly(); + hr = FindRequestHandlerAssembly(struExeLocation); if (FAILED(hr)) { goto Finished; @@ -225,13 +219,14 @@ APPLICATION_INFO::EnsureApplicationCreated( goto Finished; } - hr = m_pfnAspNetCoreCreateApplication(m_pServer, pHttpContext, struExeLocation->QueryStr(), &pApplication); + hr = m_pfnAspNetCoreCreateApplication(m_pServer, pHttpContext, struExeLocation.QueryStr(), &pApplication); m_pApplication = pApplication; } } Finished: + if (fLocked) { ReleaseSRWLockExclusive(&m_srwLock); @@ -240,10 +235,11 @@ Finished: } HRESULT -APPLICATION_INFO::FindRequestHandlerAssembly() +APPLICATION_INFO::FindRequestHandlerAssembly(STRU& location) { HRESULT hr = S_OK; BOOL fLocked = FALSE; + PCWSTR pstrHandlerDllName; STACK_STRU(struFileName, 256); if (g_fAspnetcoreRHLoadedError) @@ -267,46 +263,67 @@ APPLICATION_INFO::FindRequestHandlerAssembly() if (m_pConfiguration->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS) { - if (FAILED(hr = FindNativeAssemblyFromHostfxr(&struFileName))) - { - STACK_STRU(strEventMsg, 256); - if (SUCCEEDED(strEventMsg.SafeSnwprintf( - ASPNETCORE_EVENT_INPROCESS_RH_MISSING_MSG))) - { - UTILITY::LogEvent(g_hEventLog, - EVENTLOG_INFORMATION_TYPE, - ASPNETCORE_EVENT_INPROCESS_RH_MISSING, - strEventMsg.QueryStr()); - } - - goto Finished; - } + pstrHandlerDllName = g_pwzAspnetcoreInProcessRequestHandlerName; } else { - if (FAILED(hr = FindNativeAssemblyFromGlobalLocation(&struFileName))) + pstrHandlerDllName = g_pwzAspnetcoreOutOfProcessRequestHandlerName; + } + + // Try to see if RH is already loaded + g_hAspnetCoreRH = GetModuleHandle(pstrHandlerDllName); + + if (g_hAspnetCoreRH == NULL) + { + if (m_pConfiguration->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS) { - STACK_STRU(strEventMsg, 256); - if (SUCCEEDED(strEventMsg.SafeSnwprintf( - ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG))) + std:: unique_ptr options; + + if (FAILED(hr = HOSTFXR_OPTIONS::Create( + NULL, + m_pConfiguration->QueryProcessPath()->QueryStr(), + m_pConfiguration->QueryApplicationPhysicalPath()->QueryStr(), + m_pConfiguration->QueryArguments()->QueryStr(), + g_hEventLog, + options))) + { + goto Finished; + } + + location.Copy(options->GetExeLocation()); + + if (FAILED(hr = FindNativeAssemblyFromHostfxr(options.get(), pstrHandlerDllName, &struFileName))) + { + UTILITY::LogEvent(g_hEventLog, + EVENTLOG_INFORMATION_TYPE, + ASPNETCORE_EVENT_INPROCESS_RH_MISSING, + ASPNETCORE_EVENT_INPROCESS_RH_MISSING_MSG); + + goto Finished; + } + } + else + { + if (FAILED(hr = FindNativeAssemblyFromGlobalLocation(pstrHandlerDllName, &struFileName))) { UTILITY::LogEvent(g_hEventLog, EVENTLOG_INFORMATION_TYPE, ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING, - strEventMsg.QueryStr()); - } + ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG); + goto Finished; + } + } + + g_hAspnetCoreRH = LoadLibraryW(struFileName.QueryStr()); + + if (g_hAspnetCoreRH == NULL) + { + hr = HRESULT_FROM_WIN32(GetLastError()); goto Finished; } } - g_hAspnetCoreRH = LoadLibraryW(struFileName.QueryStr()); - if (g_hAspnetCoreRH == NULL) - { - hr = HRESULT_FROM_WIN32(GetLastError()); - goto Finished; - } - g_pfnAspNetCoreCreateApplication = (PFN_ASPNETCORE_CREATE_APPLICATION) GetProcAddress(g_hAspnetCoreRH, "CreateApplication"); if (g_pfnAspNetCoreCreateApplication == NULL) @@ -338,7 +355,9 @@ Finished: } HRESULT -APPLICATION_INFO::FindNativeAssemblyFromGlobalLocation(STRU* struFilename) +APPLICATION_INFO::FindNativeAssemblyFromGlobalLocation( + PCWSTR libraryName, + STRU* struFilename) { HRESULT hr = S_OK; DWORD dwSize = MAX_PATH; @@ -385,7 +404,7 @@ APPLICATION_INFO::FindNativeAssemblyFromGlobalLocation(STRU* struFilename) if (FAILED(hr = struFilename->SyncWithBuffer()) || FAILED(hr = struFilename->Append(L"\\")) || - FAILED(hr = struFilename->Append(g_pwzAspnetcoreOutOfProcessRequestHandlerName))) + FAILED(hr = struFilename->Append(libraryName))) { goto Finished; } @@ -401,6 +420,8 @@ Finished: // HRESULT APPLICATION_INFO::FindNativeAssemblyFromHostfxr( + HOSTFXR_OPTIONS* hostfxrOptions, + PCWSTR libraryName, STRU* struFilename ) { @@ -418,7 +439,7 @@ APPLICATION_INFO::FindNativeAssemblyFromHostfxr( DBG_ASSERT(struFileName != NULL); - hmHostFxrDll = LoadLibraryW(m_pConfiguration->QueryHostFxrFullPath()); + hmHostFxrDll = LoadLibraryW(hostfxrOptions->GetHostFxrLocation()); if (hmHostFxrDll == NULL) { @@ -446,8 +467,8 @@ APPLICATION_INFO::FindNativeAssemblyFromHostfxr( while (TRUE) { intHostFxrExitCode = pFnHostFxrSearchDirectories( - m_pConfiguration->QueryHostFxrArgCount(), - m_pConfiguration->QueryHostFxrArguments(), + hostfxrOptions->GetArgc(), + hostfxrOptions->GetArgv(), struNativeSearchPaths.QueryStr(), dwBufferSize, &dwRequiredBufferSize @@ -498,7 +519,7 @@ APPLICATION_INFO::FindNativeAssemblyFromHostfxr( } } - if (FAILED(hr = struNativeDllLocation.Append(g_pwzAspnetcoreInProcessRequestHandlerName))) + if (FAILED(hr = struNativeDllLocation.Append(libraryName))) { goto Finished; } diff --git a/src/AspNetCoreModuleV2/AspNetCore/src/aspnetcore_shim_config.cpp b/src/AspNetCoreModuleV2/AspNetCore/src/aspnetcore_shim_config.cpp index dc100d8d21..d1cf69b705 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/src/aspnetcore_shim_config.cpp +++ b/src/AspNetCoreModuleV2/AspNetCore/src/aspnetcore_shim_config.cpp @@ -5,11 +5,6 @@ ASPNETCORE_SHIM_CONFIG::~ASPNETCORE_SHIM_CONFIG() { - if (m_ppStrArguments != NULL) - { - delete[] m_ppStrArguments; - m_ppStrArguments = NULL; - } } VOID @@ -38,8 +33,6 @@ ASPNETCORE_SHIM_CONFIG::GetConfig( _In_ IHttpServer *pHttpServer, _In_ HTTP_MODULE_ID pModuleId, _In_ IHttpApplication *pHttpApplication, - _In_ HANDLE hEventLog, - _Out_ STRU *struExeLocation, _Out_ ASPNETCORE_SHIM_CONFIG **ppAspNetCoreShimConfig ) { @@ -47,8 +40,7 @@ ASPNETCORE_SHIM_CONFIG::GetConfig( ASPNETCORE_SHIM_CONFIG *pAspNetCoreShimConfig = NULL; STRU struHostFxrDllLocation; STRU struExeAbsolutePath; - BSTR* pwzArgv; - DWORD dwArgCount; + if (ppAspNetCoreShimConfig == NULL) { hr = E_INVALIDARG; @@ -81,32 +73,6 @@ ASPNETCORE_SHIM_CONFIG::GetConfig( goto Finished; } - // Modify Inprocess specific configuration here. - if (pAspNetCoreShimConfig->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS) - { - if (FAILED(hr = HOSTFXR_UTILITY::GetHostFxrParameters( - hEventLog, - pAspNetCoreShimConfig->QueryProcessPath()->QueryStr(), - pAspNetCoreShimConfig->QueryApplicationPhysicalPath()->QueryStr(), - pAspNetCoreShimConfig->QueryArguments()->QueryStr(), - &struHostFxrDllLocation, - &struExeAbsolutePath, - &dwArgCount, - &pwzArgv))) - { - goto Finished; - } - - if (FAILED(hr = pAspNetCoreShimConfig->SetHostFxrFullPath(struHostFxrDllLocation.QueryStr()))) - { - goto Finished; - } - - pAspNetCoreShimConfig->SetHostFxrArguments(dwArgCount, pwzArgv); - - struExeLocation->Copy(struExeAbsolutePath); - } - hr = pHttpApplication->GetModuleContextContainer()-> SetModuleContext(pAspNetCoreShimConfig, pModuleId); diff --git a/src/AspNetCoreModuleV2/AspNetCore/src/precomp.hxx b/src/AspNetCoreModuleV2/AspNetCore/src/precomp.hxx index 8b359c8550..6de0acdc12 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/src/precomp.hxx +++ b/src/AspNetCoreModuleV2/AspNetCore/src/precomp.hxx @@ -119,7 +119,7 @@ inline bool IsSpace(char ch) #include "globalmodule.h" #include "proxymodule.h" #include "applicationinfo.h" - +#include "hostfxroptions.h" FORCEINLINE DWORD diff --git a/src/AspNetCoreModuleV2/AspNetCore/src/proxymodule.cxx b/src/AspNetCoreModuleV2/AspNetCore/src/proxymodule.cxx index 141f3fb36a..a7a708e8d3 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/src/proxymodule.cxx +++ b/src/AspNetCoreModuleV2/AspNetCore/src/proxymodule.cxx @@ -2,6 +2,7 @@ // Licensed under the MIT License. See License.txt in the project root for license information. #include "precomp.hxx" +#include "hostfxroptions.h" __override HRESULT @@ -81,7 +82,6 @@ ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler( APPLICATION_MANAGER *pApplicationManager = NULL; REQUEST_NOTIFICATION_STATUS retVal = RQ_NOTIFICATION_CONTINUE; IAPPLICATION* pApplication = NULL; - STRU struExeLocation; STACK_STRU(struFileName, 256); if (g_fInShutdown) @@ -90,7 +90,7 @@ ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler( goto Finished; } - hr = ASPNETCORE_SHIM_CONFIG::GetConfig(g_pHttpServer, g_pModuleId, pHttpContext->GetApplication(), g_hEventLog, &struExeLocation, &pConfig); + hr = ASPNETCORE_SHIM_CONFIG::GetConfig(g_pHttpServer, g_pModuleId, pHttpContext->GetApplication(), &pConfig); if (FAILED(hr)) { goto Finished; @@ -144,7 +144,7 @@ ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler( } // make sure assmebly is loaded and application is created - hr = m_pApplicationInfo->EnsureApplicationCreated(pHttpContext, &struExeLocation); + hr = m_pApplicationInfo->EnsureApplicationCreated(pHttpContext); if (FAILED(hr)) { goto Finished; diff --git a/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj b/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj index 728c42bb9e..3b33efff12 100644 --- a/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj +++ b/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj @@ -1,228 +1,230 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {55494E58-E061-4C4C-A0A8-837008E72F85} - Win32Proj - NewCommon - 10.0.15063.0 - - - - StaticLibrary - true - v141 - Unicode - - - StaticLibrary - false - v141 - true - Unicode - - - StaticLibrary - true - v141 - Unicode - - - StaticLibrary - false - v141 - false - Unicode - - - - - - - - - - - - - - - - - - - - - true - - - true - - - false - - - false - C:\AspNetCoreModule\src\IISLib;$(IncludePath) - - - - Use - Level4 - true - Disabled - false - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - true - MultiThreadedDebug - false - ProgramDatabase - ..\iislib; - - - Windows - true - - - - - Use - Level4 - true - Disabled - false - _DEBUG;_LIB;%(PreprocessorDefinitions) - true - ProgramDatabase - false - MultiThreadedDebug - false - ..\iislib; - - - Windows - true - - - - - Use - Level4 - true - MaxSpeed - true - true - false - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - true - MultiThreaded - false - ..\iislib; - - - Windows - true - true - true - - - - - Use - Level4 - true - MaxSpeed - true - true - false - NDEBUG;_LIB;%(PreprocessorDefinitions) - true - ..\iislib; - - - MultiThreaded - false - - - Windows - true - true - true - - - ..\iislib - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - {4787a64f-9a3e-4867-a55a-70cb4b2b2ffe} - - - - - Document - mc %(FullPath) - Compiling Event Messages ... - %(Filename).rc;%(Filename).h;MSG0409.bin - mc %(FullPath) - Compiling Event Messages ... - %(Filename).rc;%(Filename).h;MSG0409.bin - mc %(FullPath) - Compiling Event Messages ... - %(Filename).rc;%(Filename).h;MSG0409.bin - mc %(FullPath) - Compiling Event Messages ... - %(Filename).rc;%(Filename).h;MSG0409.bin - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {55494E58-E061-4C4C-A0A8-837008E72F85} + Win32Proj + NewCommon + 10.0.15063.0 + + + + StaticLibrary + true + v141 + Unicode + + + StaticLibrary + false + v141 + true + Unicode + + + StaticLibrary + true + v141 + Unicode + + + StaticLibrary + false + v141 + false + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + C:\AspNetCoreModule\src\IISLib;$(IncludePath) + + + + Use + Level4 + true + Disabled + false + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreadedDebug + false + ProgramDatabase + ..\iislib; + + + Windows + true + + + + + Use + Level4 + true + Disabled + false + _DEBUG;_LIB;%(PreprocessorDefinitions) + true + ProgramDatabase + false + MultiThreadedDebug + false + ..\iislib; + + + Windows + true + + + + + Use + Level4 + true + MaxSpeed + true + true + false + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreaded + false + ..\iislib; + + + Windows + true + true + true + + + + + Use + Level4 + true + MaxSpeed + true + true + false + NDEBUG;_LIB;%(PreprocessorDefinitions) + true + ..\iislib; + + + MultiThreaded + false + + + Windows + true + true + true + + + ..\iislib + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + {4787a64f-9a3e-4867-a55a-70cb4b2b2ffe} + + + + + Document + mc %(FullPath) + Compiling Event Messages ... + %(Filename).rc;%(Filename).h;MSG0409.bin + mc %(FullPath) + Compiling Event Messages ... + %(Filename).rc;%(Filename).h;MSG0409.bin + mc %(FullPath) + Compiling Event Messages ... + %(Filename).rc;%(Filename).h;MSG0409.bin + mc %(FullPath) + Compiling Event Messages ... + %(Filename).rc;%(Filename).h;MSG0409.bin + + + + + \ No newline at end of file diff --git a/src/AspNetCoreModuleV2/CommonLib/environmentvariablehelpers.h b/src/AspNetCoreModuleV2/CommonLib/environmentvariablehelpers.h index d7df903554..9652272d84 100644 --- a/src/AspNetCoreModuleV2/CommonLib/environmentvariablehelpers.h +++ b/src/AspNetCoreModuleV2/CommonLib/environmentvariablehelpers.h @@ -98,9 +98,10 @@ public: dwResult = GetEnvironmentVariable(struNameBuffer.QueryStr(), struValueBuffer.QueryStr(), struValueBuffer.QuerySizeCCH()); - if (struValueBuffer.IsEmpty()) + + if (dwResult <= 0) { - hr = E_UNEXPECTED; + hr = HRESULT_FROM_WIN32(GetLastError()); goto Finished; } fFound = TRUE; @@ -304,7 +305,7 @@ public: dwResult = GetEnvironmentVariable(HOSTING_STARTUP_ASSEMBLIES_ENV_STR, strStartupAssemblyEnv.QueryStr(), strStartupAssemblyEnv.QuerySizeCCH()); - if (strStartupAssemblyEnv.IsEmpty()) + if (dwResult <= 0) { hr = E_UNEXPECTED; goto Finished; @@ -317,11 +318,14 @@ public: } strStartupAssemblyEnv.SyncWithBuffer(); + if (strStartupAssemblyEnv.IndexOf(HOSTING_STARTUP_ASSEMBLIES_VALUE) == -1) + { if (fFound) { strStartupAssemblyEnv.Append(L";"); } strStartupAssemblyEnv.Append(HOSTING_STARTUP_ASSEMBLIES_VALUE); + } // the environment variable was not defined, create it and add to hashtable pHostingEntry = new ENVIRONMENT_VAR_ENTRY(); diff --git a/src/AspNetCoreModuleV2/CommonLib/hostfxroptions.cpp b/src/AspNetCoreModuleV2/CommonLib/hostfxroptions.cpp new file mode 100644 index 0000000000..73493ddc1d --- /dev/null +++ b/src/AspNetCoreModuleV2/CommonLib/hostfxroptions.cpp @@ -0,0 +1,102 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +#include "stdafx.h" + +HRESULT HOSTFXR_OPTIONS::Create( + _In_ PCWSTR pcwzExeLocation, + _In_ PCWSTR pcwzProcessPath, + _In_ PCWSTR pcwzApplicationPhysicalPath, + _In_ PCWSTR pcwzArguments, + _In_ HANDLE hEventLog, + _Out_ std::unique_ptr& ppWrapper) +{ + HRESULT hr = S_OK; + STRU struHostFxrDllLocation; + STRU struExeAbsolutePath; + STRU struExeLocation; + BSTR* pwzArgv; + DWORD dwArgCount; + + if (pcwzExeLocation != NULL && FAILED(struExeLocation.Copy(pcwzExeLocation))) + { + goto Finished; + } + + // If the exe was not provided by the shim, reobtain the hostfxr parameters (which finds dotnet). + if (struExeLocation.IsEmpty()) + { + if (FAILED(hr = HOSTFXR_UTILITY::GetHostFxrParameters( + hEventLog, + pcwzProcessPath, + pcwzApplicationPhysicalPath, + pcwzArguments, + &struHostFxrDllLocation, + &struExeAbsolutePath, + &dwArgCount, + &pwzArgv))) + { + goto Finished; + } + } + else if (HOSTFXR_UTILITY::IsDotnetExecutable(&struExeLocation)) + { + if (FAILED(hr = HOSTFXR_UTILITY::ParseHostfxrArguments( + pcwzArguments, + pcwzExeLocation, + pcwzApplicationPhysicalPath, + hEventLog, + &dwArgCount, + &pwzArgv))) + { + goto Finished; + } + } + else + { + if (FAILED(hr = HOSTFXR_UTILITY::GetStandaloneHostfxrParameters( + pcwzExeLocation, + pcwzApplicationPhysicalPath, + pcwzArguments, + hEventLog, + &struHostFxrDllLocation, + &dwArgCount, + &pwzArgv))) + { + goto Finished; + } + } + + ppWrapper = std::make_unique(); + if (FAILED(hr = ppWrapper->Populate(struHostFxrDllLocation.QueryStr(), struExeAbsolutePath.QueryStr(), dwArgCount, pwzArgv))) + { + goto Finished; + } + +Finished: + + return hr; +} + + +HRESULT HOSTFXR_OPTIONS::Populate(PCWSTR hostFxrLocation, PCWSTR struExeLocation, DWORD argc, BSTR argv[]) +{ + HRESULT hr; + + m_argc = argc; + m_argv = argv; + + if (FAILED(hr = m_hostFxrLocation.Copy(hostFxrLocation))) + { + goto Finished; + } + + if (FAILED(hr = m_exeLocation.Copy(struExeLocation))) + { + goto Finished; + } + + Finished: + + return hr; +} diff --git a/src/AspNetCoreModuleV2/CommonLib/hostfxroptions.h b/src/AspNetCoreModuleV2/CommonLib/hostfxroptions.h new file mode 100644 index 0000000000..360b392760 --- /dev/null +++ b/src/AspNetCoreModuleV2/CommonLib/hostfxroptions.h @@ -0,0 +1,58 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +#pragma once + +class HOSTFXR_OPTIONS +{ +public: + HOSTFXR_OPTIONS() {} + + ~HOSTFXR_OPTIONS() + { + delete[] m_argv; + } + + DWORD + GetArgc() const + { + return m_argc; + } + + BSTR* + GetArgv() const + { + return m_argv; + } + + PCWSTR + GetHostFxrLocation() const + { + return m_hostFxrLocation.QueryStr(); + } + + PCWSTR + GetExeLocation() const + { + return m_exeLocation.QueryStr(); + } + + static + HRESULT Create( + _In_ PCWSTR pcwzExeLocation, + _In_ PCWSTR pcwzProcessPath, + _In_ PCWSTR pcwzApplicationPhysicalPath, + _In_ PCWSTR pcwzArguments, + _In_ HANDLE hEventLog, + _Out_ std::unique_ptr& ppWrapper); + +private: + + HRESULT Populate(PCWSTR hostFxrLocation, PCWSTR struExeLocation, DWORD argc, BSTR argv[]); + + STRU m_exeLocation; + STRU m_hostFxrLocation; + + DWORD m_argc; + BSTR* m_argv; +}; diff --git a/src/AspNetCoreModuleV2/CommonLib/requesthandler_config.cpp b/src/AspNetCoreModuleV2/CommonLib/requesthandler_config.cpp index 555e711922..01ca92f1ce 100644 --- a/src/AspNetCoreModuleV2/CommonLib/requesthandler_config.cpp +++ b/src/AspNetCoreModuleV2/CommonLib/requesthandler_config.cpp @@ -25,16 +25,12 @@ HRESULT REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig( _In_ IHttpServer *pHttpServer, _In_ IHttpApplication *pHttpApplication, - _In_ PCWSTR pwzExeLocation, - _In_ HANDLE hEventLog, _Out_ REQUESTHANDLER_CONFIG **ppAspNetCoreConfig ) { HRESULT hr = S_OK; REQUESTHANDLER_CONFIG *pRequestHandlerConfig = NULL; STRU struHostFxrDllLocation; - BSTR* pwzArgv; - DWORD dwArgCount; STRU struExeLocation; if (ppAspNetCoreConfig == NULL) @@ -58,60 +54,6 @@ REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig( goto Finished; } - // Modify config for inprocess. - if (pRequestHandlerConfig->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS) - { - if (FAILED(struExeLocation.Copy(pwzExeLocation))) - { - goto Finished; - } - // If the exe was not provided by the shim, reobtain the hostfxr parameters (which finds dotnet). - if (struExeLocation.IsEmpty()) - { - if (FAILED(hr = HOSTFXR_UTILITY::GetHostFxrParameters( - hEventLog, - pRequestHandlerConfig->QueryProcessPath()->QueryStr(), - pRequestHandlerConfig->QueryApplicationPhysicalPath()->QueryStr(), - pRequestHandlerConfig->QueryArguments()->QueryStr(), - &struHostFxrDllLocation, - &struExeLocation, - &dwArgCount, - &pwzArgv))) - { - goto Finished; - } - } - else if (HOSTFXR_UTILITY::IsDotnetExecutable(&struExeLocation)) - { - if (FAILED(hr = HOSTFXR_UTILITY::ParseHostfxrArguments( - pRequestHandlerConfig->QueryArguments()->QueryStr(), - pwzExeLocation, - pRequestHandlerConfig->QueryApplicationPhysicalPath()->QueryStr(), - hEventLog, - &dwArgCount, - &pwzArgv))) - { - goto Finished; - } - } - else - { - if (FAILED(hr = HOSTFXR_UTILITY::GetStandaloneHostfxrParameters( - pwzExeLocation, - pRequestHandlerConfig->QueryApplicationPhysicalPath()->QueryStr(), - pRequestHandlerConfig->QueryArguments()->QueryStr(), - hEventLog, - &struHostFxrDllLocation, - &dwArgCount, - &pwzArgv))) - { - goto Finished; - } - } - - pRequestHandlerConfig->SetHostFxrArguments(dwArgCount, pwzArgv); - } - DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, "REQUESTHANDLER_CONFIG::GetConfig, set config to ModuleContext"); // set appliction info here instead of inside Populate() diff --git a/src/AspNetCoreModuleV2/CommonLib/requesthandler_config.h b/src/AspNetCoreModuleV2/CommonLib/requesthandler_config.h index 45c9518413..d9c368468a 100644 --- a/src/AspNetCoreModuleV2/CommonLib/requesthandler_config.h +++ b/src/AspNetCoreModuleV2/CommonLib/requesthandler_config.h @@ -62,8 +62,6 @@ public: CreateRequestHandlerConfig( _In_ IHttpServer *pHttpServer, _In_ IHttpApplication *pHttpApplication, - _In_ PCWSTR pwzExeLocation, - _In_ HANDLE hEventLog, _Out_ REQUESTHANDLER_CONFIG **ppAspNetCoreConfig ); @@ -211,45 +209,11 @@ public: return &m_struConfigPath; } - CONST - PCWSTR* - QueryHostFxrArguments( - VOID - ) - { - return m_ppStrArguments; - } - - CONST - DWORD - QueryHostFxrArgCount( - VOID - ) - { - return m_dwArgc; - } - - CONST - VOID - SetHostFxrArguments( - DWORD dwArgc, - PWSTR* ppStrArguments - ) - { - if (m_ppStrArguments != NULL) - { - delete[] m_ppStrArguments; - } - - m_dwArgc = dwArgc; - m_ppStrArguments = ppStrArguments; - } - private: // // private constructor - // + // REQUESTHANDLER_CONFIG() : m_fStdoutLogEnabled(FALSE), m_pEnvironmentVariables(NULL), diff --git a/src/AspNetCoreModuleV2/CommonLib/stdafx.h b/src/AspNetCoreModuleV2/CommonLib/stdafx.h index 8bb2ef7406..821d975c93 100644 --- a/src/AspNetCoreModuleV2/CommonLib/stdafx.h +++ b/src/AspNetCoreModuleV2/CommonLib/stdafx.h @@ -32,4 +32,4 @@ #include "aspnetcore_msg.h" #include "fx_ver.h" #include "hostfxr_utility.h" - +#include "hostfxroptions.h" diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cxx b/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cxx index aa557dfbef..00002cd023 100644 --- a/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cxx +++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cxx @@ -113,13 +113,13 @@ CreateApplication( // Initialze some global variables here InitializeGlobalConfiguration(pServer); - hr = REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(pServer, pHttpContext->GetApplication(), pwzExeLocation, g_hEventLog, &pConfig); + hr = REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(pServer, pHttpContext->GetApplication(), &pConfig); if (FAILED(hr)) { return hr; } - pApplication = new IN_PROCESS_APPLICATION(pServer, pConfig); + pApplication = new IN_PROCESS_APPLICATION(pServer, pConfig, pwzExeLocation); if (pApplication == NULL) { hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY); diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocess/inprocessapplication.cpp b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocess/inprocessapplication.cpp index 08e5526879..4551c177b3 100644 --- a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocess/inprocessapplication.cpp +++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocess/inprocessapplication.cpp @@ -1,10 +1,13 @@ #include "..\precomp.hxx" +#include "hostfxroptions.h" IN_PROCESS_APPLICATION* IN_PROCESS_APPLICATION::s_Application = NULL; +hostfxr_main_fn IN_PROCESS_APPLICATION::s_fMainCallback = NULL; IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION( - IHttpServer* pHttpServer, - REQUESTHANDLER_CONFIG *pConfig) : + IHttpServer *pHttpServer, + REQUESTHANDLER_CONFIG *pConfig, + PCWSTR pDotnetExeLocation) : m_pHttpServer(pHttpServer), m_ProcessExitCode(0), m_hLogFileHandle(INVALID_HANDLE_VALUE), @@ -16,7 +19,8 @@ IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION( m_fInitialized(FALSE), m_fShutdownCalledFromNative(FALSE), m_fShutdownCalledFromManaged(FALSE), - m_srwLock() + m_srwLock(), + m_pstrDotnetExeLocation(pDotnetExeLocation) { // is it guaranteed that we have already checked app offline at this point? // If so, I don't think there is much to do here. @@ -116,7 +120,7 @@ Finished: // Managed layer may block the shutdown and lead to shutdown timeout // Assumption: only one inprocess application is hosted. // Call process exit to force shutdown - // + // exit(hr); } } @@ -262,7 +266,6 @@ IN_PROCESS_APPLICATION::Recycle( // IISExpress scenario // Shutdown the managed application and call exit to terminate current process ShutDown(); - exit(0); } } @@ -808,33 +811,55 @@ IN_PROCESS_APPLICATION::ExecuteApplication( ) { HRESULT hr = S_OK; - HMODULE hModule; + HMODULE hModule = nullptr; + DWORD hostfxrArgc = 0; + BSTR *hostfxrArgv = NULL; hostfxr_main_fn pProc; + std::unique_ptr hostFxrOptions = NULL; DBG_ASSERT(m_status == APPLICATION_STATUS::STARTING); - // hostfxr should already be loaded by the shim. If not, then we will need - // to load it ourselves by finding hostfxr again. - hModule = LoadLibraryW(L"hostfxr.dll"); - - if (hModule == NULL) + pProc = s_fMainCallback; + if (pProc == nullptr) { - // .NET Core not installed (we can log a more detailed error message here) - hr = ERROR_BAD_ENVIRONMENT; - goto Finished; - } + // hostfxr should already be loaded by the shim. If not, then we will need + // to load it ourselves by finding hostfxr again. + hModule = LoadLibraryW(L"hostfxr.dll"); - // Get the entry point for main - pProc = (hostfxr_main_fn)GetProcAddress(hModule, "hostfxr_main"); - if (pProc == NULL) - { - hr = ERROR_BAD_ENVIRONMENT; - goto Finished; - } + if (hModule == NULL) + { + // .NET Core not installed (we can log a more detailed error message here) + hr = ERROR_BAD_ENVIRONMENT; + goto Finished; + } - if (FAILED(hr = SetEnvironementVariablesOnWorkerProcess())) - { - goto Finished; + // Get the entry point for main + pProc = (hostfxr_main_fn)GetProcAddress(hModule, "hostfxr_main"); + if (pProc == NULL) + { + hr = ERROR_BAD_ENVIRONMENT; + goto Finished; + } + + if (FAILED(hr = HOSTFXR_OPTIONS::Create( + m_pstrDotnetExeLocation, + m_pConfig->QueryProcessPath()->QueryStr(), + m_pConfig->QueryApplicationPhysicalPath()->QueryStr(), + m_pConfig->QueryArguments()->QueryStr(), + g_hEventLog, + hostFxrOptions + ))) + { + goto Finished; + } + + hostfxrArgc = hostFxrOptions->GetArgc(); + hostfxrArgv = hostFxrOptions->GetArgv(); + + if (FAILED(hr = SetEnvironementVariablesOnWorkerProcess())) + { + goto Finished; + } } // There can only ever be a single instance of .NET Core @@ -845,7 +870,7 @@ IN_PROCESS_APPLICATION::ExecuteApplication( // set the callbacks s_Application = this; - hr = RunDotnetApplication(m_pConfig->QueryHostFxrArgCount(), m_pConfig->QueryHostFxrArguments(), pProc); + hr = RunDotnetApplication(hostfxrArgc, hostfxrArgv, pProc); Finished: diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocess/inprocessapplication.h b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocess/inprocessapplication.h index cc504cf48c..e72d921e1d 100644 --- a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocess/inprocessapplication.h +++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocess/inprocessapplication.h @@ -11,7 +11,10 @@ typedef REQUEST_NOTIFICATION_STATUS(WINAPI * PFN_MANAGED_CONTEXT_HANDLER)(void * class IN_PROCESS_APPLICATION : public APPLICATION { public: - IN_PROCESS_APPLICATION(IHttpServer* pHttpServer, REQUESTHANDLER_CONFIG *pConfig); + IN_PROCESS_APPLICATION( + IHttpServer* pHttpServer, + REQUESTHANDLER_CONFIG *pConfig, + PCWSTR pDotnetExeLocation); ~IN_PROCESS_APPLICATION(); @@ -102,6 +105,12 @@ public: m_fShutdownCalledFromManaged = TRUE; } + static + VOID SetMainCallback(hostfxr_main_fn mainCallback) + { + s_fMainCallback = mainCallback; + } + static IN_PROCESS_APPLICATION* GetInstance( @@ -176,10 +185,15 @@ private: HANDLE m_hErrThread; CHAR m_pzFileContents[4096] = { 0 }; DWORD m_dwStdErrReadTotal; + PCWSTR m_pstrDotnetExeLocation; static IN_PROCESS_APPLICATION* s_Application; REQUESTHANDLER_CONFIG* m_pConfig; + // Allows to override call to hostfxr_main with custome callback + // used in testing + static hostfxr_main_fn s_fMainCallback; + VOID SetStdOut( VOID diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cxx b/src/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cxx index 5d7abb77da..1f4528c6b3 100644 --- a/src/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cxx +++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cxx @@ -442,4 +442,11 @@ http_stop_incoming_requests() IN_PROCESS_APPLICATION::GetInstance()->StopIncomingRequests(); } +EXTERN_C __MIDL_DECLSPEC_DLLEXPORT +VOID +set_main_handler(_In_ hostfxr_main_fn main) +{ + IN_PROCESS_APPLICATION::SetMainCallback(main); +} + // End of export diff --git a/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/dllmain.cxx b/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/dllmain.cxx index d1b3179970..23b7816ca6 100644 --- a/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/dllmain.cxx +++ b/src/AspNetCoreModuleV2/OutOfProcessRequestHandler/dllmain.cxx @@ -285,10 +285,12 @@ CreateApplication( HRESULT hr = S_OK; IAPPLICATION *pApplication = NULL; REQUESTHANDLER_CONFIG *pConfig = NULL; + UNREFERENCED_PARAMETER(pwzExeLocation); + // Initialze some global variables here InitializeGlobalConfiguration(pServer); - hr = REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(pServer, pHttpContext->GetApplication(), pwzExeLocation, g_hEventLog, &pConfig); + hr = REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(pServer, pHttpContext->GetApplication(), &pConfig); if (FAILED(hr)) { return hr; diff --git a/src/Microsoft.AspNetCore.Server.IIS/Core/IISHttpServer.cs b/src/Microsoft.AspNetCore.Server.IIS/Core/IISHttpServer.cs index df6b9a20b6..9838417df7 100644 --- a/src/Microsoft.AspNetCore.Server.IIS/Core/IISHttpServer.cs +++ b/src/Microsoft.AspNetCore.Server.IIS/Core/IISHttpServer.cs @@ -136,6 +136,8 @@ namespace Microsoft.AspNetCore.Server.IIS.Core } _memoryPool.Dispose(); + + GC.SuppressFinalize(this); } private static NativeMethods.REQUEST_NOTIFICATION_STATUS HandleRequest(IntPtr pInProcessHandler, IntPtr pvRequestContext) diff --git a/src/Microsoft.AspNetCore.Server.IIS/NativeMethods.cs b/src/Microsoft.AspNetCore.Server.IIS/NativeMethods.cs index 9c5978db13..bd4a31db78 100644 --- a/src/Microsoft.AspNetCore.Server.IIS/NativeMethods.cs +++ b/src/Microsoft.AspNetCore.Server.IIS/NativeMethods.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.IIS private const string KERNEL32 = "kernel32.dll"; - private const string AspNetCoreModuleDll = "aspnetcorev2_inprocess.dll"; + internal const string AspNetCoreModuleDll = "aspnetcorev2_inprocess.dll"; [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)] diff --git a/test/IISIntegration.FunctionalTests/AppHostConfig/TestServer.config b/test/IISIntegration.FunctionalTests/AppHostConfig/TestServer.config new file mode 100644 index 0000000000..a0fa1187f8 --- /dev/null +++ b/test/IISIntegration.FunctionalTests/AppHostConfig/TestServer.config @@ -0,0 +1,201 @@ + + + + + + + + +
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+
+ +
+ + +
+
+
+
+ +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/IISIntegration.FunctionalTests/IISIntegration.FunctionalTests.csproj b/test/IISIntegration.FunctionalTests/IISIntegration.FunctionalTests.csproj index be7eb2a1d4..69861d7aa6 100644 --- a/test/IISIntegration.FunctionalTests/IISIntegration.FunctionalTests.csproj +++ b/test/IISIntegration.FunctionalTests/IISIntegration.FunctionalTests.csproj @@ -6,17 +6,33 @@ + + Never + + False + + + + + + + + + + + + @@ -26,4 +42,10 @@ + + + PreserveNewest + + + diff --git a/test/IISIntegration.FunctionalTests/Inprocess/TestServerTest.cs b/test/IISIntegration.FunctionalTests/Inprocess/TestServerTest.cs new file mode 100644 index 0000000000..5e78794eb1 --- /dev/null +++ b/test/IISIntegration.FunctionalTests/Inprocess/TestServerTest.cs @@ -0,0 +1,41 @@ +// 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.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using IISIntegration.FunctionalTests.Utilities; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Testing.xunit; +using Microsoft.Extensions.Logging.Testing; +using Xunit; +using Xunit.Abstractions; + +namespace IISIntegration.FunctionalTests.Inprocess +{ + [SkipIfHostableWebCoreNotAvailible] + public class TestServerTest: LoggedTest + { + public TestServerTest(ITestOutputHelper output = null) : base(output) + { + } + + [ConditionalFact] + public async Task Test() + { + var helloWorld = "Hello World"; + var expectedPath = "/Path"; + + string path = null; + using (var testServer = await TestServer.Create(ctx => { + path = ctx.Request.Path.ToString(); + return ctx.Response.WriteAsync(helloWorld); + }, LoggerFactory)) + { + var result = await testServer.HttpClient.GetAsync(expectedPath); + Assert.Equal(helloWorld, await result.Content.ReadAsStringAsync()); + Assert.Equal(expectedPath, path); + } + } + } +} diff --git a/test/IISIntegration.FunctionalTests/Utilities/SkipIfHostableWebCoreNotAvailibleAttribute.cs b/test/IISIntegration.FunctionalTests/Utilities/SkipIfHostableWebCoreNotAvailibleAttribute.cs new file mode 100644 index 0000000000..046d430317 --- /dev/null +++ b/test/IISIntegration.FunctionalTests/Utilities/SkipIfHostableWebCoreNotAvailibleAttribute.cs @@ -0,0 +1,17 @@ +// 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 Microsoft.AspNetCore.Testing.xunit; + +namespace IISIntegration.FunctionalTests.Utilities +{ + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)] + public sealed class SkipIfHostableWebCoreNotAvailibleAttribute : Attribute, ITestCondition + { + public bool IsMet { get; } = File.Exists(TestServer.HostableWebCoreLocation); + + public string SkipReason { get; } = $"Hostable Web Core not availible, {TestServer.HostableWebCoreLocation} not found."; + } +} diff --git a/test/IISIntegration.FunctionalTests/Utilities/TestServer.cs b/test/IISIntegration.FunctionalTests/Utilities/TestServer.cs new file mode 100644 index 0000000000..10f526f860 --- /dev/null +++ b/test/IISIntegration.FunctionalTests/Utilities/TestServer.cs @@ -0,0 +1,144 @@ +// 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.Net.Http; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Server.IntegrationTesting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace IISIntegration.FunctionalTests.Utilities +{ + public class TestServer: IDisposable, IStartup + { + private const string InProcessHandlerDll = "aspnetcorev2_inprocess.dll"; + private const string AspNetCoreModuleDll = "aspnetcorev2.dll"; + private const string HWebCoreDll = "hwebcore.dll"; + + internal static string HostableWebCoreLocation => Environment.ExpandEnvironmentVariables($@"%windir%\system32\inetsrv\{HWebCoreDll}"); + + private static readonly SemaphoreSlim WebCoreLock = new SemaphoreSlim(1, 1); + + // Currently this is hardcoded in TestServer.config + private static readonly int BasePort = 50691; + private static readonly Uri BaseUri = new Uri("http://localhost:" + BasePort); + + private readonly TaskCompletionSource _startedTaskCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + private readonly Action _appBuilder; + private readonly ILoggerFactory _loggerFactory; + + public HttpClient HttpClient { get; } + public TestConnection CreateConnection() => new TestConnection(BasePort); + + private IWebHost _host; + + private TestServer(Action appBuilder, ILoggerFactory loggerFactory) + { + _appBuilder = appBuilder; + _loggerFactory = loggerFactory; + + HttpClient = new HttpClient(new LoggingHandler(new SocketsHttpHandler(), _loggerFactory.CreateLogger())) + { + BaseAddress = BaseUri + }; + } + + public static async Task Create(Action appBuilder, ILoggerFactory loggerFactory) + { + await WebCoreLock.WaitAsync(); + var server = new TestServer(appBuilder, loggerFactory); + server.Start(); + await server.HttpClient.GetAsync("/start"); + await server._startedTaskCompletionSource.Task; + return server; + } + + public static Task Create(RequestDelegate app, ILoggerFactory loggerFactory) + { + return Create(builder => builder.Run(app), loggerFactory); + } + + private void Start() + { + LoadLibrary(HostableWebCoreLocation); + LoadLibrary(InProcessHandlerDll); + LoadLibrary(AspNetCoreModuleDll); + + set_main_handler(Main); + var startResult = WebCoreActivate(Path.GetFullPath("AppHostConfig/TestServer.config"), null, "Instance"); + if (startResult != 0) + { + throw new InvalidOperationException($"Error while running WebCoreActivate: {startResult}"); + } + } + + private int Main(IntPtr argc, IntPtr argv) + { + _host = new WebHostBuilder() + .UseIIS() + .ConfigureServices(services => { + services.AddSingleton(this); + services.AddSingleton(_loggerFactory); + }) + .UseSetting(WebHostDefaults.ApplicationKey, typeof(TestServer).GetTypeInfo().Assembly.FullName) + .Build(); + + var doneEvent = new ManualResetEventSlim(); + var lifetime = _host.Services.GetService(); + + lifetime.ApplicationStopping.Register(() => doneEvent.Set()); + _host.Start(); + _startedTaskCompletionSource.SetResult(null); + doneEvent.Wait(); + _host.Dispose(); + return 0; + } + + public void Dispose() + { + HttpClient.Dispose(); + WebCoreShutdown(false); + WebCoreLock.Release(); + } + + public IServiceProvider ConfigureServices(IServiceCollection services) + { + return services.BuildServiceProvider(); + } + + public void Configure(IApplicationBuilder app) + { + app.Map("/start", builder => builder.Run(context => context.Response.WriteAsync("Done"))); + _appBuilder(app); + } + + private delegate int hostfxr_main_fn(IntPtr argc, IntPtr argv); + + [DllImport(HWebCoreDll)] + private static extern int WebCoreActivate( + [In, MarshalAs(UnmanagedType.LPWStr)] + string appHostConfigPath, + [In, MarshalAs(UnmanagedType.LPWStr)] + string rootWebConfigPath, + [In, MarshalAs(UnmanagedType.LPWStr)] + string instanceName); + + [DllImport(HWebCoreDll)] + private static extern int WebCoreShutdown(bool immediate); + + [DllImport(InProcessHandlerDll)] + private static extern int set_main_handler(hostfxr_main_fn main); + + [DllImport("kernel32", SetLastError=true, CharSet = CharSet.Ansi)] + private static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName); + } +}