From 2018a43d63d2dd8896443b2f51db725f4c9b0b4d Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 23 Sep 2018 19:16:57 +0000 Subject: [PATCH 1/3] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 54 ++++++++++++++++++++-------------------- korebuild-lock.txt | 4 +-- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 784065f4b9..8a43fc832e 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,39 +4,39 @@ 0.10.13 - 2.2.0-preview1-20180911.1 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 0.6.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 + 2.2.0-preview1-20180918.1 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 0.6.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 15.6.82 15.6.82 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 - 2.2.0-preview3-35252 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 + 2.2.0-preview3-35301 2.0.9 2.1.3 2.2.0-preview2-26905-02 1.0.1 - 2.2.0-preview3-35252 + 2.2.0-preview3-35301 15.6.1 11.1.0 2.0.3 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index 1090ad6a92..8491de70e6 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview1-20180911.1 -commithash:ddfecdfc6e8e4859db5a0daea578070b862aac65 +version:2.2.0-preview1-20180918.1 +commithash:ad5e3fc53442741a0dd49bce437d2ac72f4b5800 From 1eb5da31e5e37efe1c0f3b43f6f8f701d4a284e1 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Tue, 25 Sep 2018 15:40:15 -0700 Subject: [PATCH 2/3] Improve error messages and add static html pages for failure to start site. (#1421) --- .../AspNetCore/AspNetCore.vcxproj | 19 ++- .../AspNetCore/HandlerResolver.cpp | 109 +++++++++--------- .../AspNetCore/HandlerResolver.h | 5 +- .../AspNetCore/HtmlResponses.rc | Bin 0 -> 3324 bytes .../AspNetCore/InProcessShimStaticHtml.htm | 45 ++++++++ .../AspNetCore/OutOfProcessShimStaticHtml.htm | 44 +++++++ .../AspNetCore/ServerErrorApplication.h | 15 ++- .../AspNetCore/ServerErrorHandler.h | 23 ---- .../AspNetCore/ShimOptions.cpp | 1 + .../AspNetCore/ShimOptions.h | 7 ++ .../AspNetCore/applicationinfo.cpp | 103 +++++++++++------ .../AspNetCore/applicationinfo.h | 3 + .../AspNetCore/applicationmanager.cpp | 3 +- src/AspNetCoreModuleV2/AspNetCore/resource.h | 19 +++ .../CommonLib/CommonLib.vcxproj | 4 +- .../CommonLib/FileOutputManager.cpp | 2 - .../CommonLib/ServerErrorHandler.h | 32 +++++ .../CommonLib/file_utility.cpp | 22 ++++ .../CommonLib/file_utility.h | 6 + .../CommonLib/iapplication.h | 10 ++ .../CommonLib/requesthandler.h | 26 +++++ src/AspNetCoreModuleV2/CommonLib/resources.h | 6 +- .../InProcessRequestHandler/HtmlResponses.rc | Bin 0 -> 3112 bytes .../InProcessRequestHandler.vcxproj | 8 +- .../InProcessRhStaticHtml.htm | 44 +++++++ .../StartupExceptionApplication.cpp | 10 -- .../StartupExceptionApplication.h | 18 ++- .../StartupExceptionHandler.cpp | 55 --------- .../StartupExceptionHandler.h | 31 +++-- .../InProcessRequestHandler/dllmain.cpp | 10 +- .../InProcessRequestHandler/resource.h | 16 +++ .../IISDeployer.cs | 2 +- .../ConfigurationChangeTests.cs | 2 +- .../Utilities/EventLogHelpers.cs | 40 ++++++- .../Utilities/Helpers.cs | 11 ++ .../Inprocess/StdOutRedirectionTests.cs | 13 +-- .../RequiresIISAttribute.cs | 4 +- .../InProcess/StartupTests.cs | 56 ++++++++- .../OutOfProcess/GlobalVersionTests.cs | 2 + 39 files changed, 596 insertions(+), 230 deletions(-) create mode 100644 src/AspNetCoreModuleV2/AspNetCore/HtmlResponses.rc create mode 100644 src/AspNetCoreModuleV2/AspNetCore/InProcessShimStaticHtml.htm create mode 100644 src/AspNetCoreModuleV2/AspNetCore/OutOfProcessShimStaticHtml.htm delete mode 100644 src/AspNetCoreModuleV2/AspNetCore/ServerErrorHandler.h create mode 100644 src/AspNetCoreModuleV2/AspNetCore/resource.h create mode 100644 src/AspNetCoreModuleV2/CommonLib/ServerErrorHandler.h create mode 100644 src/AspNetCoreModuleV2/InProcessRequestHandler/HtmlResponses.rc create mode 100644 src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRhStaticHtml.htm delete mode 100644 src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.cpp delete mode 100644 src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.cpp create mode 100644 src/AspNetCoreModuleV2/InProcessRequestHandler/resource.h diff --git a/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj b/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj index bd0129be53..4b2c6129e8 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj +++ b/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj @@ -232,14 +232,14 @@ + + + - - - @@ -248,11 +248,11 @@ + - Create Create @@ -284,6 +284,17 @@ PreserveNewest + + + + + + true + + + true + + diff --git a/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp index 7414f51161..726229cc9e 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp +++ b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp @@ -73,21 +73,18 @@ HandlerResolver::LoadRequestHandlerAssembly(const IHttpApplication &pApplication pApplication.GetApplicationPhysicalPath(), outputManager)); - outputManager->TryStartRedirection(); - hr = FindNativeAssemblyFromHostfxr(*options.get(), pstrHandlerDllName, handlerDllPath); + hr = FindNativeAssemblyFromHostfxr(*options.get(), pstrHandlerDllName, handlerDllPath, outputManager.get()); - outputManager->TryStopRedirection(); - - if (FAILED(hr) && m_hHostFxrDll != nullptr) + if (FAILED_LOG(hr)) { auto output = outputManager->GetStdOutContent(); EventLog::Error( ASPNETCORE_EVENT_GENERAL_ERROR, ASPNETCORE_EVENT_INPROCESS_RH_ERROR_MSG, - handlerDllPath.empty()? s_pwzAspnetcoreInProcessRequestHandlerName : handlerDllPath.c_str(), output.c_str()); + return hr; } } else @@ -122,55 +119,38 @@ HandlerResolver::LoadRequestHandlerAssembly(const IHttpApplication &pApplication } HRESULT -HandlerResolver::GetApplicationFactory(const IHttpApplication &pApplication, std::unique_ptr& pApplicationFactory) +HandlerResolver::GetApplicationFactory(const IHttpApplication &pApplication, std::unique_ptr& pApplicationFactory, const ShimOptions& options) { - try + SRWExclusiveLock lock(m_requestHandlerLoadLock); + if (m_loadedApplicationHostingModel != HOSTING_UNKNOWN) { - const WebConfigConfigurationSource configurationSource(m_pServer.GetAdminManager(), pApplication); - ShimOptions options(configurationSource); - - SRWExclusiveLock lock(m_requestHandlerLoadLock); - if (m_loadedApplicationHostingModel != HOSTING_UNKNOWN) + // Mixed hosting models + if (m_loadedApplicationHostingModel != options.QueryHostingModel()) { - // Mixed hosting models - if (m_loadedApplicationHostingModel != options.QueryHostingModel()) - { - EventLog::Error( - ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR, - ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG, - pApplication.GetApplicationId(), - options.QueryHostingModel()); + EventLog::Error( + ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR, + ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG, + pApplication.GetApplicationId(), + options.QueryHostingModel()); - return E_FAIL; - } - // Multiple in-process apps - if (m_loadedApplicationHostingModel == HOSTING_IN_PROCESS && m_loadedApplicationId != pApplication.GetApplicationId()) - { - EventLog::Error( - ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP, - ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP_MSG, - pApplication.GetApplicationId()); - - return E_FAIL; - } + return E_FAIL; } + // Multiple in-process apps + if (m_loadedApplicationHostingModel == HOSTING_IN_PROCESS && m_loadedApplicationId != pApplication.GetApplicationId()) + { + EventLog::Error( + ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP, + ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP_MSG, + pApplication.GetApplicationId()); - m_loadedApplicationHostingModel = options.QueryHostingModel(); - m_loadedApplicationId = pApplication.GetApplicationId(); - RETURN_IF_FAILED(LoadRequestHandlerAssembly(pApplication, options, pApplicationFactory)); - + return E_FAIL; + } } - catch(ConfigurationLoadException &ex) - { - EventLog::Error( - ASPNETCORE_CONFIGURATION_LOAD_ERROR, - ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG, - ex.get_message().c_str()); - - RETURN_HR(E_FAIL); - } - CATCH_RETURN(); + m_loadedApplicationHostingModel = options.QueryHostingModel(); + m_loadedApplicationId = pApplication.GetApplicationId(); + RETURN_IF_FAILED(LoadRequestHandlerAssembly(pApplication, options, pApplicationFactory)); + return S_OK; } @@ -222,7 +202,8 @@ HRESULT HandlerResolver::FindNativeAssemblyFromHostfxr( const HOSTFXR_OPTIONS& hostfxrOptions, PCWSTR libraryName, - std::wstring& handlerDllPath + std::wstring& handlerDllPath, + BaseOutputManager* outputManager ) { std::wstring struNativeSearchPaths; @@ -230,23 +211,29 @@ HandlerResolver::FindNativeAssemblyFromHostfxr( size_t intPrevIndex = 0; DWORD dwBufferSize = s_initialGetNativeSearchDirectoriesBufferSize; DWORD dwRequiredBufferSize = 0; + hostfxr_get_native_search_directories_fn pFnHostFxrSearchDirectories = nullptr; RETURN_LAST_ERROR_IF_NULL(m_hHostFxrDll = LoadLibraryW(hostfxrOptions.GetHostFxrLocation().c_str())); - const auto pFnHostFxrSearchDirectories = ModuleHelpers::GetKnownProcAddress(m_hHostFxrDll, "hostfxr_get_native_search_directories"); - if (pFnHostFxrSearchDirectories == nullptr) + try + { + pFnHostFxrSearchDirectories = ModuleHelpers::GetKnownProcAddress(m_hHostFxrDll, "hostfxr_get_native_search_directories"); + } + catch (...) { EventLog::Error( ASPNETCORE_EVENT_GENERAL_ERROR, ASPNETCORE_EVENT_HOSTFXR_DLL_INVALID_VERSION_MSG, hostfxrOptions.GetHostFxrLocation().c_str() - ); - RETURN_IF_FAILED(E_FAIL); + ); + return OBSERVE_CAUGHT_EXCEPTION(); } RETURN_LAST_ERROR_IF_NULL(pFnHostFxrSearchDirectories); struNativeSearchPaths.resize(dwBufferSize); + outputManager->TryStartRedirection(); + while (TRUE) { DWORD hostfxrArgc; @@ -273,11 +260,23 @@ HandlerResolver::FindNativeAssemblyFromHostfxr( } else { - // Log "Error finding native search directories from aspnetcore application. + // Stop redirecting before logging to event log to avoid logging debug logs + // twice. + outputManager->TryStopRedirection(); + + // If hostfxr didn't set the required buffer size, something in the app is misconfigured + // Ex: Framework not found. + EventLog::Error( + ASPNETCORE_EVENT_GENERAL_ERROR, + ASPNETCORE_EVENT_HOSTFXR_FAILURE_MSG + ); + return E_UNEXPECTED; } } + outputManager->TryStopRedirection(); + struNativeSearchPaths.resize(struNativeSearchPaths.find(L'\0')); auto fFound = FALSE; @@ -307,6 +306,10 @@ HandlerResolver::FindNativeAssemblyFromHostfxr( if (!fFound) { + EventLog::Error( + ASPNETCORE_EVENT_GENERAL_ERROR, + ASPNETCORE_EVENT_INPROCESS_RH_REFERENCE_MSG, + handlerDllPath.empty() ? s_pwzAspnetcoreInProcessRequestHandlerName : handlerDllPath.c_str()); return HRESULT_FROM_WIN32(ERROR_DLL_NOT_FOUND); } diff --git a/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h index 7b230a928f..1cd9029347 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h +++ b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h @@ -9,18 +9,19 @@ #include "hostfxroptions.h" #include "HandleWrapper.h" #include "ApplicationFactory.h" +#include "BaseOutputManager.h" class HandlerResolver { public: HandlerResolver(HMODULE hModule, const IHttpServer &pServer); - HRESULT GetApplicationFactory(const IHttpApplication &pApplication, std::unique_ptr& pApplicationFactory); + HRESULT GetApplicationFactory(const IHttpApplication &pApplication, std::unique_ptr& pApplicationFactory, const ShimOptions& options); void ResetHostingModel(); private: HRESULT LoadRequestHandlerAssembly(const IHttpApplication &pApplication, const ShimOptions& pConfiguration, std::unique_ptr& pApplicationFactory); HRESULT FindNativeAssemblyFromGlobalLocation(const ShimOptions& pConfiguration, PCWSTR libraryName, std::wstring& handlerDllPath); - HRESULT FindNativeAssemblyFromHostfxr(const HOSTFXR_OPTIONS& hostfxrOptions, PCWSTR libraryName, std::wstring& handlerDllPath); + HRESULT FindNativeAssemblyFromHostfxr(const HOSTFXR_OPTIONS& hostfxrOptions, PCWSTR libraryName, std::wstring& handlerDllPath, BaseOutputManager* outputManager); HMODULE m_hModule; const IHttpServer &m_pServer; diff --git a/src/AspNetCoreModuleV2/AspNetCore/HtmlResponses.rc b/src/AspNetCoreModuleV2/AspNetCore/HtmlResponses.rc new file mode 100644 index 0000000000000000000000000000000000000000..d923a2121ce3d06fb24905f7322ee6080da33f16 GIT binary patch literal 3324 zcmds)ZEq4m5Xb+oP5cfgys^;~A3i~W3Pc_n4w{;f5K}xQp;yB}eB)a3U}4g zzBtY1n7z4~*_qjy|1Lj&)KpWXp60sLQrF6O60P8!!^^bRM=f}3=mjIvXMIx2vxL8b z&fqPfrnhEx$vooCtj+ZmnPWZG6IQ7?T7{ePb%FHE$yWCCkM%_rCvBQlCzm)qvwfm7 z#Tsd>raBsEs-aHdHktR;)dx5+zdhCAbeV_s&4==h;9a1RTI6Ln#|c@w))n!u$d2V< zMAR4jc8Iz`oR*JM_-}Z2cjV7|@Xh7d>)pS5`?0aUWJ2A@jj*xoGe% zVs}&eZ^2Gw)Ig-??0L#t=);(q@5)R^IaQEt_0-(u>)EZ|nql!o@2D!@Q!)KBrn?%f zJf*t2472;45fy5VurZ{Dr)c%jKXR*f;r8KHj9eX#*V&br z^3`{>uKppB_sE}PV6m*6eb+oA#3CzentCuQ_%$6no!Xm`!`+|dGz)`kM6rp)#34sPBV=0!!RNbZ}zJ# z>`}Q;W!oF`(B1=$=)w`_XZJTJ#9+})Ie&-rlc7S)u+z3pZS~yDy5G*E25-Si$XP!9 zJE@Is1?wq3*m-ETjf@e4hjUKHfPi+JX@iDWprxH=Hrw1N4An;XHvsD%E1LU9G2jNY z!iVHRu@u+ls52-uA{kEUxzyJh1;Q K`**;6O#TIKC57bx literal 0 HcmV?d00001 diff --git a/src/AspNetCoreModuleV2/AspNetCore/InProcessShimStaticHtml.htm b/src/AspNetCoreModuleV2/AspNetCore/InProcessShimStaticHtml.htm new file mode 100644 index 0000000000..b7e575552a --- /dev/null +++ b/src/AspNetCoreModuleV2/AspNetCore/InProcessShimStaticHtml.htm @@ -0,0 +1,45 @@ + + + + + + IIS 500 Error + + + + +
+
+

HTTP Error 500.0 - ANCM InProcess Startup Failure

+
+
+
+

Common causes of this issue:

+
    +
  • The specified version of Microsoft.NetCore.App or Microsoft.AspNetCore.App was not found.
  • +
  • The in process request handler, Microsoft.AspNetCore.Server.IIS, was not referenced in the application.
  • +
  • ANCM could not find dotnet.
  • +
+
+
+
+
+

Troubleshooting steps:

+
    +
  • Check the system event log for error messages
  • +
  • Enable logging the application process' stdout messages
  • +
  • Attach a debugger to the application process and inspect
  • +
+
+
+

For more information visit: + + https://go.microsoft.com/fwlink/?LinkID=808681 + +

+
+
+
+ + + diff --git a/src/AspNetCoreModuleV2/AspNetCore/OutOfProcessShimStaticHtml.htm b/src/AspNetCoreModuleV2/AspNetCore/OutOfProcessShimStaticHtml.htm new file mode 100644 index 0000000000..475ce26956 --- /dev/null +++ b/src/AspNetCoreModuleV2/AspNetCore/OutOfProcessShimStaticHtml.htm @@ -0,0 +1,44 @@ + + + + + + IIS 500 Error + + + + +
+
+

HTTP Error 500.0 - ANCM OutOfProcess Startup Failure

+
+
+
+

Common causes of this issue:

+
    +
  • The out of process request handler, aspnetcorev2_outofprocess.dll, could not be found next to the aspnetcorev2.dll.
  • +
  • Could not read configuration correctly. Check the application's associated web.config.
  • +
+
+
+
+
+

Troubleshooting steps:

+
    +
  • Check the system event log for error messages
  • +
  • Enable logging the application process' stdout messages
  • +
  • Attach a debugger to the application process and inspect
  • +
+
+
+

For more information visit: + + https://go.microsoft.com/fwlink/?LinkID=808681 + +

+
+
+
+ + + \ No newline at end of file diff --git a/src/AspNetCoreModuleV2/AspNetCore/ServerErrorApplication.h b/src/AspNetCoreModuleV2/AspNetCore/ServerErrorApplication.h index df686adbc4..ac5bd85aaf 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/ServerErrorApplication.h +++ b/src/AspNetCoreModuleV2/AspNetCore/ServerErrorApplication.h @@ -9,8 +9,16 @@ class ServerErrorApplication : public PollingAppOfflineApplication { public: - ServerErrorApplication(const IHttpApplication& pApplication, HRESULT hr) + ServerErrorApplication(const IHttpApplication& pApplication, HRESULT hr, HINSTANCE moduleInstance) + : ServerErrorApplication(pApplication, hr, moduleInstance, true /* disableStartupPage*/, 0 /* page */) + { + } + + ServerErrorApplication(const IHttpApplication& pApplication, HRESULT hr, HINSTANCE moduleInstance, bool disableStartupPage, int page) : m_HR(hr), + m_disableStartupPage(disableStartupPage), + m_page(page), + m_moduleInstance(moduleInstance), PollingAppOfflineApplication(pApplication, PollingAppOfflineApplicationMode::StopWhenAdded) { } @@ -19,7 +27,7 @@ public: HRESULT CreateHandler(IHttpContext *pHttpContext, IREQUEST_HANDLER ** pRequestHandler) override { - auto handler = std::make_unique(*pHttpContext, m_HR); + auto handler = std::make_unique(*pHttpContext, m_HR, m_moduleInstance, m_disableStartupPage, m_page); *pRequestHandler = handler.release(); return S_OK; } @@ -27,5 +35,8 @@ public: HRESULT OnAppOfflineFound() noexcept override { return S_OK; } private: HRESULT m_HR; + bool m_disableStartupPage; + int m_page; + HINSTANCE m_moduleInstance; }; diff --git a/src/AspNetCoreModuleV2/AspNetCore/ServerErrorHandler.h b/src/AspNetCoreModuleV2/AspNetCore/ServerErrorHandler.h deleted file mode 100644 index 10cf3ee049..0000000000 --- a/src/AspNetCoreModuleV2/AspNetCore/ServerErrorHandler.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -#pragma once -#include "requesthandler.h" - -class ServerErrorHandler : public REQUEST_HANDLER -{ -public: - ServerErrorHandler(IHttpContext &pContext, HRESULT hr) : m_pContext(pContext), m_HR(hr) - { - } - - REQUEST_NOTIFICATION_STATUS OnExecuteRequestHandler() override - { - m_pContext.GetResponse()->SetStatus(500, "Internal Server Error", 0, m_HR); - return RQ_NOTIFICATION_FINISH_REQUEST; - } - -private: - IHttpContext &m_pContext; - HRESULT m_HR; -}; diff --git a/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp b/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp index 3ba1db7889..cb7f1488d7 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp +++ b/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp @@ -40,4 +40,5 @@ ShimOptions::ShimOptions(const ConfigurationSource &configurationSource) : m_strArguments = section->GetString(CS_ASPNETCORE_PROCESS_ARGUMENTS).value_or(CS_ASPNETCORE_PROCESS_ARGUMENTS_DEFAULT); m_fStdoutLogEnabled = section->GetRequiredBool(CS_ASPNETCORE_STDOUT_LOG_ENABLED); m_struStdoutLogFile = section->GetRequiredString(CS_ASPNETCORE_STDOUT_LOG_FILE); + m_fDisableStartupPage = section->GetRequiredBool(CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE); } diff --git a/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.h b/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.h index 4b934ad9b4..3cfb47169e 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.h +++ b/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.h @@ -53,6 +53,12 @@ public: return m_struStdoutLogFile; } + bool + QueryDisableStartupPage() const noexcept + { + return m_fDisableStartupPage; + } + ShimOptions(const ConfigurationSource &configurationSource); private: @@ -62,4 +68,5 @@ private: std::wstring m_strHandlerVersion; std::wstring m_struStdoutLogFile; bool m_fStdoutLogEnabled; + bool m_fDisableStartupPage; }; diff --git a/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp b/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp index 85bb5c6398..9b95d94f16 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp +++ b/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp @@ -12,6 +12,11 @@ #include "EventLog.h" #include "ServerErrorApplication.h" #include "AppOfflineApplication.h" +#include "WebConfigConfigurationSource.h" +#include "ConfigurationLoadException.h" +#include "resource.h" + +extern HINSTANCE g_hServerModule; HRESULT APPLICATION_INFO::CreateHandler( @@ -23,7 +28,7 @@ APPLICATION_INFO::CreateHandler( { SRWSharedLock lock(m_applicationLock); - + RETURN_IF_FAILED(hr = TryCreateHandler(pHttpContext, pHandler)); if (hr == S_OK) @@ -31,10 +36,10 @@ APPLICATION_INFO::CreateHandler( return S_OK; } } - + { SRWExclusiveLock lock(m_applicationLock); - + // check if other thread created application RETURN_IF_FAILED(hr = TryCreateHandler(pHttpContext, pHandler)); @@ -66,48 +71,78 @@ APPLICATION_INFO::CreateHandler( HRESULT APPLICATION_INFO::CreateApplication(const IHttpApplication& pHttpApplication) { - HRESULT hr = S_OK; - if (AppOfflineApplication::ShouldBeStarted(pHttpApplication)) { LOG_INFO(L"Detected app_offline file, creating polling application"); - #pragma warning( push ) - #pragma warning ( disable : 26409 ) // Disable "Avoid using new", using custom deleter here - m_pApplication.reset(new AppOfflineApplication(pHttpApplication)); - #pragma warning( pop ) + m_pApplication = make_application(pHttpApplication); + + return S_OK; } else { - FINISHED_IF_FAILED(m_handlerResolver.GetApplicationFactory(pHttpApplication, m_pApplicationFactory)); + try + { + const WebConfigConfigurationSource configurationSource(m_pServer.GetAdminManager(), pHttpApplication); + ShimOptions options(configurationSource); - LOG_INFO(L"Creating handler application"); - IAPPLICATION * newApplication; - FINISHED_IF_FAILED(m_pApplicationFactory->Execute( - &m_pServer, - &pHttpApplication, - &newApplication)); + const auto hr = TryCreateApplication(pHttpApplication, options); - m_pApplication.reset(newApplication); + if (FAILED_LOG(hr)) + { + // Log the failure and update application info to not try again + EventLog::Error( + ASPNETCORE_EVENT_ADD_APPLICATION_ERROR, + ASPNETCORE_EVENT_ADD_APPLICATION_ERROR_MSG, + pHttpApplication.GetApplicationId(), + hr); + + m_pApplication = make_application( + pHttpApplication, + hr, + g_hServerModule, + options.QueryDisableStartupPage(), + options.QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS ? IN_PROCESS_SHIM_STATIC_HTML : OUT_OF_PROCESS_SHIM_STATIC_HTML); + } + return S_OK; + } + catch (ConfigurationLoadException &ex) + { + EventLog::Error( + ASPNETCORE_CONFIGURATION_LOAD_ERROR, + ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG, + ex.get_message().c_str()); + } + catch (...) + { + EventLog::Error( + ASPNETCORE_CONFIGURATION_LOAD_ERROR, + ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG, + L""); + } + + m_pApplication = make_application( + pHttpApplication, + E_FAIL, + g_hServerModule); + + return S_OK; } +} -Finished: +HRESULT +APPLICATION_INFO::TryCreateApplication(const IHttpApplication& pHttpApplication, const ShimOptions& options) +{ + RETURN_IF_FAILED(m_handlerResolver.GetApplicationFactory(pHttpApplication, m_pApplicationFactory, options)); + LOG_INFO(L"Creating handler application"); - if (m_pApplication == nullptr || FAILED(hr)) - { - // Log the failure and update application info to not try again - EventLog::Error( - ASPNETCORE_EVENT_ADD_APPLICATION_ERROR, - ASPNETCORE_EVENT_ADD_APPLICATION_ERROR_MSG, - pHttpApplication.GetApplicationId(), - hr); - - #pragma warning( push ) - #pragma warning ( disable : 26409 ) // Disable "Avoid using new", using custom deleter here - m_pApplication.reset(new ServerErrorApplication(pHttpApplication, hr)); - #pragma warning( pop ) - } + IAPPLICATION * newApplication; + RETURN_IF_FAILED(m_pApplicationFactory->Execute( + &m_pServer, + &pHttpApplication, + &newApplication)); - return hr; + m_pApplication.reset(newApplication); + return S_OK; } HRESULT @@ -139,7 +174,7 @@ APPLICATION_INFO::ShutDownApplication(bool fServerInitiated) if (m_pApplication) { LOG_INFOF(L"Stopping application '%ls'", QueryApplicationInfoKey().c_str()); - m_pApplication ->Stop(fServerInitiated); + m_pApplication->Stop(fServerInitiated); m_pApplication = nullptr; m_pApplicationFactory = nullptr; } diff --git a/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.h b/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.h index 9c6d1b7cde..4b190007dd 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.h +++ b/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.h @@ -76,6 +76,9 @@ private: HRESULT CreateApplication(const IHttpApplication& pHttpApplication); + HRESULT + TryCreateApplication(const IHttpApplication& pHttpApplication, const ShimOptions& options); + IHttpServer &m_pServer; HandlerResolver &m_handlerResolver; diff --git a/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp b/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp index 52d9730ec1..d1e2b12375 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp +++ b/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp @@ -13,7 +13,7 @@ extern BOOL g_fInShutdown; // // Retrieves the application info from the application manager -// Will create the application info if it isn't initalized +// Will create the application info if it isn't initialized // HRESULT APPLICATION_MANAGER::GetOrCreateApplicationInfo( @@ -21,7 +21,6 @@ APPLICATION_MANAGER::GetOrCreateApplicationInfo( _Out_ std::shared_ptr& ppApplicationInfo ) { - auto &pApplication = *pHttpContext.GetApplication(); // The configuration path is unique for each application and is used for the diff --git a/src/AspNetCoreModuleV2/AspNetCore/resource.h b/src/AspNetCoreModuleV2/AspNetCore/resource.h new file mode 100644 index 0000000000..289df99bc3 --- /dev/null +++ b/src/AspNetCoreModuleV2/AspNetCore/resource.h @@ -0,0 +1,19 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by HtmlResponses.rc +// +#define IN_PROCESS_SHIM_STATIC_HTML 101 +#define OUT_OF_PROCESS_SHIM_STATIC_HTML 102 +#define UNKNOWN_HOSTING_STATIC_HTML 103 + + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 104 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj b/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj index 8628cc6529..caa53ff29d 100644 --- a/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj +++ b/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj @@ -223,12 +223,14 @@ - + + + diff --git a/src/AspNetCoreModuleV2/CommonLib/FileOutputManager.cpp b/src/AspNetCoreModuleV2/CommonLib/FileOutputManager.cpp index b0442e1a81..1b3772bb4f 100644 --- a/src/AspNetCoreModuleV2/CommonLib/FileOutputManager.cpp +++ b/src/AspNetCoreModuleV2/CommonLib/FileOutputManager.cpp @@ -11,8 +11,6 @@ #include "StdWrapper.h" #include "StringHelpers.h" -extern HINSTANCE g_hModule; - FileOutputManager::FileOutputManager(std::wstring pwzStdOutLogFileName, std::wstring pwzApplicationPath) : FileOutputManager(pwzStdOutLogFileName, pwzApplicationPath, /* fEnableNativeLogging */ true) { } diff --git a/src/AspNetCoreModuleV2/CommonLib/ServerErrorHandler.h b/src/AspNetCoreModuleV2/CommonLib/ServerErrorHandler.h new file mode 100644 index 0000000000..721c0d12eb --- /dev/null +++ b/src/AspNetCoreModuleV2/CommonLib/ServerErrorHandler.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +#pragma once +#include "requesthandler.h" +#include "file_utility.h" + +class ServerErrorHandler : public REQUEST_HANDLER +{ +public: + + ServerErrorHandler(IHttpContext &pContext, HRESULT hr, HINSTANCE moduleInstance, bool disableStartupPage, int page) + : m_pContext(pContext), m_HR(hr), m_disableStartupPage(disableStartupPage), m_page(page), m_moduleInstance(moduleInstance) + { + } + + REQUEST_NOTIFICATION_STATUS OnExecuteRequestHandler() override + { + static std::string s_html500Page = FILE_UTILITY::GetHtml(m_moduleInstance, m_page); + + WriteStaticResponse(m_pContext, s_html500Page, m_HR, m_disableStartupPage); + + return RQ_NOTIFICATION_FINISH_REQUEST; + } + +private: + IHttpContext &m_pContext; + HRESULT m_HR; + bool m_disableStartupPage; + int m_page; + HINSTANCE m_moduleInstance; +}; diff --git a/src/AspNetCoreModuleV2/CommonLib/file_utility.cpp b/src/AspNetCoreModuleV2/CommonLib/file_utility.cpp index a971821208..228c1c0d66 100644 --- a/src/AspNetCoreModuleV2/CommonLib/file_utility.cpp +++ b/src/AspNetCoreModuleV2/CommonLib/file_utility.cpp @@ -5,6 +5,7 @@ #include #include "debugutil.h" +#include "exceptions.h" HRESULT FILE_UTILITY::IsPathUnc( @@ -165,3 +166,24 @@ FILE_UTILITY::EnsureDirectoryPathExist( Finished: return hr; } + +std::string +FILE_UTILITY::GetHtml(HMODULE module, int page) +{ + HRESULT hr = S_OK; + HRSRC rc = nullptr; + HGLOBAL rcData = nullptr; + const char* data = nullptr; + DWORD size = 0; + + FINISHED_LAST_ERROR_IF_NULL(rc = FindResource(module, MAKEINTRESOURCE(page), RT_HTML)); + FINISHED_LAST_ERROR_IF_NULL(rcData = LoadResource(module, rc)); + size = SizeofResource(module, rc); + FINISHED_LAST_ERROR_IF(size == 0); + FINISHED_LAST_ERROR_IF_NULL(data = static_cast(LockResource(rcData))); + + return data; +Finished: + + return ""; +} diff --git a/src/AspNetCoreModuleV2/CommonLib/file_utility.h b/src/AspNetCoreModuleV2/CommonLib/file_utility.h index cc541b712a..686e810cbe 100644 --- a/src/AspNetCoreModuleV2/CommonLib/file_utility.h +++ b/src/AspNetCoreModuleV2/CommonLib/file_utility.h @@ -25,6 +25,11 @@ public: EnsureDirectoryPathExist( _In_ LPCWSTR pszPath ); + + static + std::string + GetHtml(HMODULE module, int page); + private: static HRESULT @@ -32,5 +37,6 @@ private: __in LPCWSTR pszPath, __out BOOL * pfIsUnc ); + }; diff --git a/src/AspNetCoreModuleV2/CommonLib/iapplication.h b/src/AspNetCoreModuleV2/CommonLib/iapplication.h index 3349cb66fb..2e8660748f 100644 --- a/src/AspNetCoreModuleV2/CommonLib/iapplication.h +++ b/src/AspNetCoreModuleV2/CommonLib/iapplication.h @@ -51,3 +51,13 @@ std::unique_ptr ReferenceApplication(APPLICAT application->ReferenceApplication(); return std::unique_ptr(application); }; + +template< class APPLICATION, typename ...Params > +std::unique_ptr make_application(Params&&... params) +{ +#pragma warning( push ) +#pragma warning ( disable : 26409 ) // Disable "Avoid using new", using custom deleter here + return std::unique_ptr(new APPLICATION(std::forward(params)...)); +#pragma warning( pop ) +} + diff --git a/src/AspNetCoreModuleV2/CommonLib/requesthandler.h b/src/AspNetCoreModuleV2/CommonLib/requesthandler.h index a5e16bf022..b4cd3a0e35 100644 --- a/src/AspNetCoreModuleV2/CommonLib/requesthandler.h +++ b/src/AspNetCoreModuleV2/CommonLib/requesthandler.h @@ -46,6 +46,32 @@ public: { } +protected: + + static + void WriteStaticResponse(IHttpContext& pContext, std::string &s_html500Page, HRESULT hr, bool disableStartupErrorPage) + { + if (disableStartupErrorPage) + { + pContext.GetResponse()->SetStatus(500, "Internal Server Error", 30, E_FAIL); + return; + } + + HTTP_DATA_CHUNK dataChunk = {}; + IHttpResponse* pResponse = pContext.GetResponse(); + pResponse->SetStatus(500, "Internal Server Error", 0, hr, nullptr, true); + pResponse->SetHeader("Content-Type", + "text/html", + (USHORT)strlen("text/html"), + FALSE + ); + dataChunk.DataChunkType = HttpDataChunkFromMemory; + + dataChunk.FromMemory.pBuffer = s_html500Page.data(); + dataChunk.FromMemory.BufferLength = static_cast(s_html500Page.size()); + pResponse->WriteEntityChunkByReference(&dataChunk); + } + private: mutable LONG m_cRefs = 1; }; diff --git a/src/AspNetCoreModuleV2/CommonLib/resources.h b/src/AspNetCoreModuleV2/CommonLib/resources.h index d44c6a25f8..fdee8b9578 100644 --- a/src/AspNetCoreModuleV2/CommonLib/resources.h +++ b/src/AspNetCoreModuleV2/CommonLib/resources.h @@ -28,7 +28,7 @@ #define ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL_MSG L"Application '%s' has shutdown." #define ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP_MSG L"Only one inprocess application is allowed per IIS application pool. Please assign the application '%s' to a different IIS application pool." #define ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG L"Mixed hosting model is not supported. Application '%s' configured with different hostingModel value '%d' other than the one of running application(s)." -#define ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG L"Configuration load error. %s" +#define ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG L"Could not load configuration. Exception message: %s" #define ASPNETCORE_EVENT_ADD_APPLICATION_ERROR_MSG L"Failed to start application '%s', ErrorCode '0x%x'." #define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT_MSG L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, exit code = '%d'. Last 4KB characters of captured stdout and stderr logs:\r\n%s" #define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_MSG L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, exit code = '%d'. Please check the stderr logs for more information." @@ -39,9 +39,11 @@ #define ASPNETCORE_EVENT_RECYCLE_FAILURE_CONFIGURATION_MSG L"Failed to recycle application due to a configuration change at '%s'. Recycling worker process." #define ASPNETCORE_EVENT_MODULE_DISABLED_MSG L"AspNetCore Module is disabled" #define ASPNETCORE_EVENT_HOSTFXR_DLL_INVALID_VERSION_MSG L"Hostfxr version used does not support 'hostfxr_get_native_search_directories', update the version of hostfxr to a higher version. Path to hostfxr: '%s'." +#define ASPNETCORE_EVENT_HOSTFXR_FAILURE_MSG L"Invoking hostfxr to find the inprocess request handler failed without finding any native dependencies. This most likely means the app is misconfigured, please check the versions of Microsoft.NetCore.App and Microsoft.AspNetCore.App that are targeted by the application and are installed on the machine." #define ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION_MSG L"Application '%s' with physical root '%s' hit unexpected managed exception, exception code = '0x%x'. Please check the stderr logs for more information." #define ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION_STDOUT_MSG L"Application '%s' with physical root '%s' hit unexpected managed exception, exception code = '0x%x'. Last 4KB characters of captured stdout and stderr logs:\r\n%s" -#define ASPNETCORE_EVENT_INPROCESS_RH_ERROR_MSG L"Could not find the assembly '%s' for in-process application. Please confirm the Microsoft.AspNetCore.Server.IIS package is referenced in your application. Captured output: %s" +#define ASPNETCORE_EVENT_INPROCESS_RH_ERROR_MSG L"Could not find inprocess request handler. Captured output from invoking hostfxr: %s" +#define ASPNETCORE_EVENT_INPROCESS_RH_REFERENCE_MSG L"Could not find the assembly '%s' referenced for the in-process application. Please confirm the Microsoft.AspNetCore.Server.IIS package is referenced in your application." #define ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG L"Could not find the assembly '%s' for out-of-process application. Please confirm the assembly is installed correctly for IIS or IISExpress." #define ASPNETCORE_EVENT_INPROCESS_START_SUCCESS_MSG L"Application '%s' started the coreclr in-process successfully." #define ASPNETCORE_EVENT_INPROCESS_START_ERROR_MSG L"Application '%s' wasn't able to start. %s" diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/HtmlResponses.rc b/src/AspNetCoreModuleV2/InProcessRequestHandler/HtmlResponses.rc new file mode 100644 index 0000000000000000000000000000000000000000..25a99683c5e9730bdb8e0b66e6a68d3229964283 GIT binary patch literal 3112 zcmdUxU2oGc6o%hxB>qE4Zwl_InfsMKYsX~hk{9e9pCkE}^S z6fS}+=Qzjq@%eo1@88;LE7G}Ey3$5BD(IQE@GjvM+UdR4{PpyN7U`otD5r1WZ=p+g z8>sEuF}h+L@n_Oj`plYBJ=6nEX*=42n=`v+_0p}4EBjCNNwHgPJ6mpD=JuKFjxLmF zrn&kW>5WoNbq2T3c%rf1!Aba@s|#n$IGk@fG_M8i0*y4lFZ({u@Y0R0v44wq%nviH ze#>`+)jjMqf1JU8LEn$a?_==A`Pc8e@Bij`ENJAjV~4LSlQQf+E;oYbgWP7(pj||C zbLwwRqzZB%(qm$t^B3wcVdSf_&`C`e6s4M4Ie$I6S6fRYcJzv@@->xEKXa<9$H^(# zHKv)|ue9jk&KWYMh + - @@ -247,8 +247,6 @@ Create Create - - @@ -262,9 +260,13 @@ + + + true + diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRhStaticHtml.htm b/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRhStaticHtml.htm new file mode 100644 index 0000000000..4675db7cdb --- /dev/null +++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRhStaticHtml.htm @@ -0,0 +1,44 @@ + + + + + + + IIS 500.30 Error + + + +
+ +

HTTP Error 500.30 - ANCM In-Process Start Failure

+
+ +
+

Common causes of this issue:

+
    +
  • The application failed to start
  • +
  • The application started but then stopped
  • +
  • The application started but threw an exception during startup
  • +
+
+
+
+ +
+

Troubleshooting steps:

+
    +
  • Check the system event log for error messages
  • +
  • Enable logging the application process' stdout messages
  • +
  • Attach a debugger to the application process and inspect
  • +
+
+
+

+ For more information visit: + https://go.microsoft.com/fwlink/?LinkID=808681 +

+
+
+
+ + diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.cpp b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.cpp deleted file mode 100644 index b198e95909..0000000000 --- a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -#include "StartupExceptionApplication.h" - -HRESULT StartupExceptionApplication::CreateHandler(IHttpContext *pHttpContext, IREQUEST_HANDLER ** pRequestHandler) -{ - *pRequestHandler = new StartupExceptionHandler(pHttpContext, m_disableLogs); - return S_OK; -} diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.h b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.h index d3505315be..7d8acc4e7e 100644 --- a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.h +++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.h @@ -4,7 +4,8 @@ #pragma once #include "InProcessApplicationBase.h" -#include "StartupExceptionHandler.h" +#include "ServerErrorHandler.h" +#include "resource.h" class StartupExceptionApplication : public InProcessApplicationBase { @@ -12,15 +13,24 @@ public: StartupExceptionApplication( IHttpServer& pServer, IHttpApplication& pApplication, - BOOL disableLogs) + HINSTANCE moduleInstance, + BOOL disableLogs, + HRESULT hr) : m_disableLogs(disableLogs), + m_HR(hr), + m_moduleInstance(moduleInstance), InProcessApplicationBase(pServer, pApplication) { } ~StartupExceptionApplication() = default; - HRESULT CreateHandler(IHttpContext * pHttpContext, IREQUEST_HANDLER ** pRequestHandler) override; + HRESULT + CreateHandler(IHttpContext *pHttpContext, IREQUEST_HANDLER ** pRequestHandler) + { + *pRequestHandler = new ServerErrorHandler(*pHttpContext, m_HR,m_moduleInstance, m_disableLogs, IN_PROCESS_RH_STATIC_HTML); + return S_OK; + } std::string& GetStaticHtml500Content() @@ -31,5 +41,7 @@ public: private: std::string html500Page; BOOL m_disableLogs; + HRESULT m_HR; + HINSTANCE m_moduleInstance; }; diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.cpp b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.cpp deleted file mode 100644 index d180460898..0000000000 --- a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -#include "StartupExceptionApplication.h" -#include "StartupExceptionHandler.h" - -std::string StartupExceptionHandler::s_html500Page = " \ - \ - \ - \ - IIS 500.30 Error \ -
\ -

HTTP Error 500.30 - ANCM In-Process Start Failure

\ -
\ -

Common causes of this issue:

\ -
  • The application failed to start
  • \ -
  • The application started but then stopped
  • \ -
  • The application started but threw an exception during startup
\ -
\ -
\ -

Troubleshooting steps:

\ -
  • Check the system event log for error messages
  • \ -
  • Enable logging the application process' stdout messages
  • \ -
  • Attach a debugger to the application process and inspect
\ -

For more information visit: \ - https://go.microsoft.com/fwlink/?LinkID=808681

\ -
\ -
\ -
"; - -REQUEST_NOTIFICATION_STATUS StartupExceptionHandler::OnExecuteRequestHandler() -{ - if (!m_disableLogs) - { - HTTP_DATA_CHUNK DataChunk; - IHttpResponse* pResponse = m_pContext->GetResponse(); - pResponse->SetStatus(500, "Internal Server Error", 30, E_FAIL, NULL, TRUE); - pResponse->SetHeader("Content-Type", - "text/html", - (USHORT)strlen("text/html"), - FALSE - ); - DataChunk.DataChunkType = HttpDataChunkFromMemory; - DataChunk.FromMemory.pBuffer = (PVOID)s_html500Page.c_str(); - DataChunk.FromMemory.BufferLength = (ULONG)s_html500Page.size(); - pResponse->WriteEntityChunkByReference(&DataChunk); - } - else - { - m_pContext->GetResponse()->SetStatus(500, "Internal Server Error", 30, E_FAIL); - } - - return REQUEST_NOTIFICATION_STATUS::RQ_NOTIFICATION_FINISH_REQUEST; -} - diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.h b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.h index 266474e1b5..1d0f3b7cc9 100644 --- a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.h +++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.h @@ -3,31 +3,38 @@ #pragma once -#include #include "requesthandler.h" +#include "resource.h" +#include "file_utility.h" -class StartupExceptionApplication; class StartupExceptionHandler : public REQUEST_HANDLER { public: - StartupExceptionHandler(IHttpContext* pContext, BOOL disableLogs) - : - m_pContext(pContext), - m_disableLogs(disableLogs) + + StartupExceptionHandler(IHttpContext& pContext, BOOL disableLogs, HRESULT hr) + : m_pContext(pContext), + m_disableLogs(disableLogs), + m_HR(hr) { } + ~StartupExceptionHandler() { - } - REQUEST_NOTIFICATION_STATUS OnExecuteRequestHandler() override; + + REQUEST_NOTIFICATION_STATUS OnExecuteRequestHandler() + { + static std::string s_html500Page = FILE_UTILITY::GetHtml(g_hModule, IN_PROCESS_SHIM_STATIC_HTML); + + WriteStaticResponse(m_pContext, s_html500Page, m_HR, m_disableLogs); + + return REQUEST_NOTIFICATION_STATUS::RQ_NOTIFICATION_FINISH_REQUEST; + } private: - IHttpContext * m_pContext; + IHttpContext& m_pContext; BOOL m_disableLogs; - - static - std::string s_html500Page; + HRESULT m_HR; }; diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cpp b/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cpp index 32a314dd50..49f2142fd4 100644 --- a/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cpp +++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cpp @@ -6,7 +6,6 @@ #include #include "inprocessapplication.h" -#include "StartupExceptionApplication.h" #include "inprocesshandler.h" #include "requesthandler_config.h" #include "debugutil.h" @@ -17,6 +16,7 @@ #include "EventLog.h" #include "WebConfigConfigurationSource.h" #include "ConfigurationLoadException.h" +#include "StartupExceptionApplication.h" DECLARE_DEBUG_PRINT_OBJECT("aspnetcorev2_inprocess.dll"); @@ -28,6 +28,7 @@ HINSTANCE g_hWinHttpModule; HINSTANCE g_hAspNetCoreModule; HANDLE g_hEventLog = NULL; bool g_fInProcessApplicationCreated = false; +HINSTANCE g_hServerModule; HRESULT InitializeGlobalConfiguration( @@ -69,7 +70,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, ) { UNREFERENCED_PARAMETER(lpReserved); - + g_hServerModule = hModule; switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: @@ -100,6 +101,7 @@ CreateApplication( { try { + HRESULT hr = S_OK; RETURN_IF_FAILED(InitializeGlobalConfiguration(pServer, pHttpApplication)); // In process application was already created so another call to CreateApplication @@ -114,7 +116,7 @@ CreateApplication( g_fInProcessApplicationCreated = true; std::unique_ptr inProcessApplication; - if (!FAILED_LOG(IN_PROCESS_APPLICATION::Start(*pServer, *pHttpApplication, pParameters, nParameters, inProcessApplication))) + if (!FAILED_LOG(hr = IN_PROCESS_APPLICATION::Start(*pServer, *pHttpApplication, pParameters, nParameters, inProcessApplication))) { *ppApplication = inProcessApplication.release(); } @@ -123,7 +125,7 @@ CreateApplication( std::unique_ptr options; THROW_IF_FAILED(InProcessOptions::Create(*pServer, *pHttpApplication, options)); // Set the currently running application to a fake application that returns startup exceptions. - auto pErrorApplication = std::make_unique(*pServer, *pHttpApplication, options->QueryDisableStartUpErrorPage()); + auto pErrorApplication = std::make_unique(*pServer, *pHttpApplication, g_hServerModule, options->QueryDisableStartUpErrorPage(), hr); RETURN_IF_FAILED(pErrorApplication->StartMonitoringAppOffline()); *ppApplication = pErrorApplication.release(); diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/resource.h b/src/AspNetCoreModuleV2/InProcessRequestHandler/resource.h new file mode 100644 index 0000000000..61f67c2833 --- /dev/null +++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by HtmlResponses.rc +// +#define IN_PROCESS_RH_STATIC_HTML 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs index 76ce9a3800..a2c3360cf4 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs @@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS { private const string DetailedErrorsEnvironmentVariable = "ASPNETCORE_DETAILEDERRORS"; - private static readonly TimeSpan _timeout = TimeSpan.FromSeconds(10); + private static readonly TimeSpan _timeout = TimeSpan.FromSeconds(60); private static readonly TimeSpan _retryDelay = TimeSpan.FromMilliseconds(200); private CancellationTokenSource _hostShutdownToken = new CancellationTokenSource(); diff --git a/test/Common.FunctionalTests/ConfigurationChangeTests.cs b/test/Common.FunctionalTests/ConfigurationChangeTests.cs index 014e2520c4..099cefb97a 100644 --- a/test/Common.FunctionalTests/ConfigurationChangeTests.cs +++ b/test/Common.FunctionalTests/ConfigurationChangeTests.cs @@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests await deploymentResult.HttpClient.RetryRequestAsync("/HelloWorld", r => r.StatusCode == HttpStatusCode.InternalServerError); StopServer(); - EventLogHelpers.VerifyEventLogEvent(deploymentResult, "Could not find the assembly 'aspnetcorev2_inprocess.dll'"); + EventLogHelpers.VerifyEventLogEvent(deploymentResult, "Could not find the assembly 'aspnetcorev2_inprocess.dll'", Logger); } [ConditionalTheory] diff --git a/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs b/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs index 2d7de2a8f1..cf977b76f4 100644 --- a/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs +++ b/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs @@ -1,12 +1,14 @@ // 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.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text.RegularExpressions; using Microsoft.AspNetCore.Server.IntegrationTesting; using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; +using Microsoft.Extensions.Logging; using Xunit; namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests @@ -21,6 +23,25 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests AssertSingleEntry(expectedRegexMatchString, entries); } + public static void VerifyEventLogEvent(IISDeploymentResult deploymentResult, string expectedRegexMatchString, ILogger logger) + { + Assert.True(deploymentResult.HostProcess.HasExited); + + var entries = GetEntries(deploymentResult); + try + { + AssertSingleEntry(expectedRegexMatchString, entries); + } + catch (Exception ex) + { + foreach (var entry in entries) + { + logger.LogInformation(entry.Message); + } + throw ex; + } + } + public static void VerifyEventLogEvents(IISDeploymentResult deploymentResult, params string[] expectedRegexMatchString) { Assert.True(deploymentResult.HostProcess.HasExited); @@ -149,7 +170,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests public static string ConfigurationLoadError(IISDeploymentResult deploymentResult, string reason) { - return $"Configuration load error. {reason}"; + return $"Could not load configuration. Exception message: {reason}"; } public static string OutOfProcessFailedToStart(IISDeploymentResult deploymentResult) @@ -159,6 +180,23 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests $"The last try of listening port is '(.*)'. See previous warnings for details."; } + public static string InProcessHostfxrInvalid(IISDeploymentResult deploymentResult) + { + return $"Hostfxr version used does not support 'hostfxr_get_native_search_directories', update the version of hostfxr to a higher version. Path to hostfxr: '(.*)'."; + } + + public static string InProcessFailedToFindNativeDependencies(IISDeploymentResult deploymentResult) + { + return "Invoking hostfxr to find the inprocess request handler failed without finding any native dependencies. " + + "This most likely means the app is misconfigured, please check the versions of Microsoft.NetCore.App and Microsoft.AspNetCore.App that " + + "are targeted by the application and are installed on the machine."; + } + + public static string InProcessFailedToFindRequestHandler(IISDeploymentResult deploymentResult) + { + return "Could not find the assembly '(.*)' referenced for the in-process application. Please confirm the Microsoft.AspNetCore.Server.IIS package is referenced in your application."; + } + private static string EscapedContentRoot(IISDeploymentResult deploymentResult) { var contentRoot = deploymentResult.ContentRoot; diff --git a/test/Common.FunctionalTests/Utilities/Helpers.cs b/test/Common.FunctionalTests/Utilities/Helpers.cs index cb6779210a..8087b67b1d 100644 --- a/test/Common.FunctionalTests/Utilities/Helpers.cs +++ b/test/Common.FunctionalTests/Utilities/Helpers.cs @@ -12,6 +12,8 @@ using Microsoft.AspNetCore.Server.IntegrationTesting; using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Xunit; namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests @@ -159,5 +161,14 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests return Directory.GetFiles(logFolderPath).Single(); } } + + public static void ModifyFrameworkVersionInRuntimeConfig(IISDeploymentResult deploymentResult) + { + var path = Path.Combine(deploymentResult.ContentRoot, "InProcessWebSite.runtimeconfig.json"); + dynamic depsFileContent = JsonConvert.DeserializeObject(File.ReadAllText(path)); + depsFileContent["runtimeOptions"]["framework"]["version"] = "2.9.9"; + var output = JsonConvert.SerializeObject(depsFileContent); + File.WriteAllText(path, output); + } } } diff --git a/test/IIS.FunctionalTests/Inprocess/StdOutRedirectionTests.cs b/test/IIS.FunctionalTests/Inprocess/StdOutRedirectionTests.cs index deab1d756b..9c89249d1e 100644 --- a/test/IIS.FunctionalTests/Inprocess/StdOutRedirectionTests.cs +++ b/test/IIS.FunctionalTests/Inprocess/StdOutRedirectionTests.cs @@ -32,7 +32,7 @@ namespace IIS.FunctionalTests.Inprocess var deploymentResult = await DeployAsync(deploymentParameters); - InvalidateRuntimeConfig(deploymentResult); + Helpers.ModifyFrameworkVersionInRuntimeConfig(deploymentResult); var response = await deploymentResult.HttpClient.GetAsync("/HelloWorld"); Assert.False(response.IsSuccessStatusCode); @@ -54,7 +54,7 @@ namespace IIS.FunctionalTests.Inprocess var deploymentResult = await DeployAsync(deploymentParameters); - InvalidateRuntimeConfig(deploymentResult); + Helpers.ModifyFrameworkVersionInRuntimeConfig(deploymentResult); var response = await deploymentResult.HttpClient.GetAsync("/HelloWorld"); Assert.False(response.IsSuccessStatusCode); @@ -146,14 +146,5 @@ namespace IIS.FunctionalTests.Inprocess EventLogHelpers.VerifyEventLogEvent(deploymentResult, "Invoked hostfxr"); Assert.Contains("Invoked hostfxr", contents); } - - private static void InvalidateRuntimeConfig(IISDeploymentResult deploymentResult) - { - var path = Path.Combine(deploymentResult.ContentRoot, "InProcessWebSite.runtimeconfig.json"); - dynamic depsFileContent = JsonConvert.DeserializeObject(File.ReadAllText(path)); - depsFileContent["runtimeOptions"]["framework"]["version"] = "2.9.9"; - var output = JsonConvert.SerializeObject(depsFileContent); - File.WriteAllText(path, output); - } } } diff --git a/test/IIS.FunctionalTests/RequiresIISAttribute.cs b/test/IIS.FunctionalTests/RequiresIISAttribute.cs index 507de60279..9fa3a7c502 100644 --- a/test/IIS.FunctionalTests/RequiresIISAttribute.cs +++ b/test/IIS.FunctionalTests/RequiresIISAttribute.cs @@ -151,8 +151,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests if (capabilities.HasFlag(IISCapability.ApplicationInitialization)) { - IsMet &= _dynamicCompressionAvailable; - if (!_dynamicCompressionAvailable) + IsMet &= _applicationInitializationModule; + if (!_applicationInitializationModule) { SkipReason += "The machine does not have IIS ApplicationInitialization installed."; } diff --git a/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs b/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs index 227722e6ca..662aba0727 100644 --- a/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs +++ b/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs @@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities; using Microsoft.AspNetCore.Server.IntegrationTesting; using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.AspNetCore.Testing.xunit; +using Newtonsoft.Json; using Xunit; namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests @@ -60,6 +61,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests StopServer(); EventLogHelpers.VerifyEventLogEvent(deploymentResult, $@"Application '{Regex.Escape(deploymentResult.ContentRoot)}\\' wasn't able to start. {subError}"); + + Assert.Contains("HTTP Error 500.0 - ANCM InProcess Startup Failure", await response.Content.ReadAsStringAsync()); } [ConditionalFact] @@ -185,6 +188,48 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests EventLogHelpers.InProcessThreadExit(deploymentResult, "12")); } + [ConditionalFact] + public async Task RemoveHostfxrFromApp_InProcessHostfxrInvalid() + { + var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.InProcessTestSite, publish: true); + deploymentParameters.ApplicationType = ApplicationType.Standalone; + var deploymentResult = await DeployAsync(deploymentParameters); + + File.Copy( + Path.Combine(deploymentResult.ContentRoot, "aspnetcorev2_inprocess.dll"), + Path.Combine(deploymentResult.ContentRoot, "hostfxr.dll"), + true); + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult); + + EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessHostfxrInvalid(deploymentResult), Logger); + } + + [ConditionalFact] + public async Task TargedDifferenceSharedFramework_FailedToFindNativeDependencies() + { + var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.InProcessTestSite, publish: true); + var deploymentResult = await DeployAsync(deploymentParameters); + + Helpers.ModifyFrameworkVersionInRuntimeConfig(deploymentResult); + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult); + + EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessFailedToFindNativeDependencies(deploymentResult), Logger); + } + + [ConditionalFact] + public async Task RemoveInProcessReference_FailedToFindRequestHandler() + { + var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.InProcessTestSite, publish: true); + deploymentParameters.ApplicationType = ApplicationType.Standalone; + var deploymentResult = await DeployAsync(deploymentParameters); + + File.Delete(Path.Combine(deploymentResult.ContentRoot, "aspnetcorev2_inprocess.dll")); + + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult); + + EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessFailedToFindRequestHandler(deploymentResult), Logger); + } + [ConditionalFact] public async Task StartupTimeoutIsApplied() { @@ -239,7 +284,6 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests StopServer(); EventLogHelpers.VerifyEventLogEvents(deploymentResult, - EventLogHelpers.FailedToStartApplication(deploymentResult, "0x80004005"), EventLogHelpers.ConfigurationLoadError(deploymentResult, "Unknown hosting model 'bogus'. Please specify either hostingModel=\"inprocess\" or hostingModel=\"outofprocess\" in the web.config file.") ); } @@ -259,8 +303,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests Assert.Equal(HttpStatusCode.InternalServerError, result.StatusCode); StopServer(); + EventLogHelpers.VerifyEventLogEvents(deploymentResult, - EventLogHelpers.FailedToStartApplication(deploymentResult, "0x80004005"), EventLogHelpers.ConfigurationLoadError(deploymentResult, expectedError) ); } @@ -407,5 +451,13 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests } }); } + + private async Task AssertSiteFailsToStartWithInProcessStaticContent(IISDeploymentResult deploymentResult) + { + var response = await deploymentResult.HttpClient.GetAsync("/HelloWorld"); + Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); + Assert.Contains("HTTP Error 500.0 - ANCM InProcess Startup Failure", await response.Content.ReadAsStringAsync()); + StopServer(); + } } } diff --git a/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs b/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs index 674550f6fc..855096e026 100644 --- a/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs +++ b/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs @@ -64,6 +64,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests var response = await deploymentResult.HttpClient.GetAsync(_helloWorldRequest); Assert.False(response.IsSuccessStatusCode); + var responseString = await response.Content.ReadAsStringAsync(); + Assert.Contains("HTTP Error 500.0 - ANCM OutOfProcess Startup Failure", responseString); } [ConditionalTheory] From bac0f44fa7e102cf8dc6112c7dfd9f227d56708a Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Fri, 21 Sep 2018 09:13:39 -0700 Subject: [PATCH 3/3] Revert "Disconnect the disconnect handler when request processing ends (#1413)" This reverts commit f808bdc331ed9e5555c315d44bcc9559695f041c. --- .../AspNetCore/DisconnectHandler.cpp | 15 ++--- .../AspNetCore/DisconnectHandler.h | 12 ++-- .../AspNetCore/proxymodule.cpp | 29 +++------ .../AspNetCore/proxymodule.h | 4 +- .../CommonLib/SRWExclusiveLock.cpp | 2 +- .../CommonLib/SRWExclusiveLock.h | 2 +- .../CommonLib/irequesthandler.h | 6 -- .../ClientDisconnectStress.cs | 65 ------------------- test/WebSites/InProcessWebSite/Startup.cs | 11 ---- 9 files changed, 20 insertions(+), 126 deletions(-) delete mode 100644 test/Common.FunctionalTests/ClientDisconnectStress.cs diff --git a/src/AspNetCoreModuleV2/AspNetCore/DisconnectHandler.cpp b/src/AspNetCoreModuleV2/AspNetCore/DisconnectHandler.cpp index 3e8e7754aa..b921994850 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/DisconnectHandler.cpp +++ b/src/AspNetCoreModuleV2/AspNetCore/DisconnectHandler.cpp @@ -4,21 +4,15 @@ #include "DisconnectHandler.h" #include "exceptions.h" #include "proxymodule.h" -#include "SRWExclusiveLock.h" void DisconnectHandler::NotifyDisconnect() { try { - std::unique_ptr module; - { - SRWExclusiveLock lock(m_handlerLock); - m_pHandler.swap(module); - } - + const auto module = m_pModule.exchange(nullptr); if (module != nullptr) { - module->NotifyDisconnect(); + module ->NotifyDisconnect(); } } catch (...) @@ -33,8 +27,7 @@ void DisconnectHandler::CleanupStoredContext() noexcept delete this; } -void DisconnectHandler::SetHandler(std::unique_ptr handler) noexcept +void DisconnectHandler::SetHandler(ASPNET_CORE_PROXY_MODULE * module) noexcept { - SRWExclusiveLock lock(m_handlerLock); - handler.swap(m_pHandler); + m_pModule = module; } diff --git a/src/AspNetCoreModuleV2/AspNetCore/DisconnectHandler.h b/src/AspNetCoreModuleV2/AspNetCore/DisconnectHandler.h index 63b7525356..34c8a24a63 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/DisconnectHandler.h +++ b/src/AspNetCoreModuleV2/AspNetCore/DisconnectHandler.h @@ -2,9 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. #pragma once - -#include -#include "irequesthandler.h" +#include class ASPNET_CORE_PROXY_MODULE; @@ -12,9 +10,8 @@ class DisconnectHandler final: public IHttpConnectionStoredContext { public: DisconnectHandler() - : m_pHandler(nullptr) + : m_pModule(nullptr) { - InitializeSRWLock(&m_handlerLock); } virtual @@ -30,10 +27,9 @@ public: CleanupStoredContext() noexcept override; void - SetHandler(std::unique_ptr handler) noexcept; + SetHandler(ASPNET_CORE_PROXY_MODULE * module) noexcept; private: - SRWLOCK m_handlerLock {}; - std::unique_ptr m_pHandler; + std::atomic m_pModule; }; diff --git a/src/AspNetCoreModuleV2/AspNetCore/proxymodule.cpp b/src/AspNetCoreModuleV2/AspNetCore/proxymodule.cpp index 6f879f2e35..d3d71e8b4b 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/proxymodule.cpp +++ b/src/AspNetCoreModuleV2/AspNetCore/proxymodule.cpp @@ -71,10 +71,6 @@ ASPNET_CORE_PROXY_MODULE::ASPNET_CORE_PROXY_MODULE(HTTP_MODULE_ID moduleId, std: ASPNET_CORE_PROXY_MODULE::~ASPNET_CORE_PROXY_MODULE() { - // At this point m_pDisconnectHandler should be disconnected in - // HandleNotificationStatus - assert(m_pDisconnectHandler == nullptr); - if (m_pDisconnectHandler != nullptr) { m_pDisconnectHandler->SetHandler(nullptr); @@ -116,6 +112,8 @@ ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler( FINISHED_IF_FAILED(moduleContainer->SetConnectionModuleContext(static_cast(disconnectHandler.release()), m_moduleId)); } + m_pDisconnectHandler->SetHandler(this); + FINISHED_IF_FAILED(m_pApplicationManager->GetOrCreateApplicationInfo( *pHttpContext, m_pApplicationInfo)); @@ -123,8 +121,6 @@ ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler( FINISHED_IF_FAILED(m_pApplicationInfo->CreateHandler(*pHttpContext, m_pHandler)); retVal = m_pHandler->OnExecuteRequestHandler(); - - m_pDisconnectHandler->SetHandler(::ReferenceRequestHandler(m_pHandler.get())); } catch (...) { @@ -145,7 +141,7 @@ Finished: } } - return HandleNotificationStatus(retVal); + return retVal; } __override @@ -160,27 +156,18 @@ ASPNET_CORE_PROXY_MODULE::OnAsyncCompletion( { try { - return HandleNotificationStatus(m_pHandler->OnAsyncCompletion( + return m_pHandler->OnAsyncCompletion( pCompletionInfo->GetCompletionBytes(), - pCompletionInfo->GetCompletionStatus())); + pCompletionInfo->GetCompletionStatus()); } catch (...) { OBSERVE_CAUGHT_EXCEPTION(); - return HandleNotificationStatus(RQ_NOTIFICATION_FINISH_REQUEST); + return RQ_NOTIFICATION_FINISH_REQUEST; } } -REQUEST_NOTIFICATION_STATUS ASPNET_CORE_PROXY_MODULE::HandleNotificationStatus(REQUEST_NOTIFICATION_STATUS status) noexcept +void ASPNET_CORE_PROXY_MODULE::NotifyDisconnect() const { - if (status != RQ_NOTIFICATION_PENDING) - { - if (m_pDisconnectHandler != nullptr) - { - m_pDisconnectHandler->SetHandler(nullptr); - m_pDisconnectHandler = nullptr; - } - } - - return status; + m_pHandler->NotifyDisconnect(); } diff --git a/src/AspNetCoreModuleV2/AspNetCore/proxymodule.h b/src/AspNetCoreModuleV2/AspNetCore/proxymodule.h index 24f4794c68..97c126b0f9 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/proxymodule.h +++ b/src/AspNetCoreModuleV2/AspNetCore/proxymodule.h @@ -47,8 +47,8 @@ class ASPNET_CORE_PROXY_MODULE : NonCopyable, public CHttpModule IHttpCompletionInfo * pCompletionInfo ) override; - REQUEST_NOTIFICATION_STATUS - HandleNotificationStatus(REQUEST_NOTIFICATION_STATUS status) noexcept; + void + NotifyDisconnect() const; private: std::shared_ptr m_pApplicationManager; diff --git a/src/AspNetCoreModuleV2/CommonLib/SRWExclusiveLock.cpp b/src/AspNetCoreModuleV2/CommonLib/SRWExclusiveLock.cpp index 896189c8a8..0bc46b8cf5 100644 --- a/src/AspNetCoreModuleV2/CommonLib/SRWExclusiveLock.cpp +++ b/src/AspNetCoreModuleV2/CommonLib/SRWExclusiveLock.cpp @@ -3,7 +3,7 @@ #include "SRWExclusiveLock.h" -SRWExclusiveLock::SRWExclusiveLock(const SRWLOCK& lock) noexcept +SRWExclusiveLock::SRWExclusiveLock(const SRWLOCK& lock) : m_lock(lock) { AcquireSRWLockExclusive(const_cast(&m_lock)); diff --git a/src/AspNetCoreModuleV2/CommonLib/SRWExclusiveLock.h b/src/AspNetCoreModuleV2/CommonLib/SRWExclusiveLock.h index 6c17e13111..7ff977f70d 100644 --- a/src/AspNetCoreModuleV2/CommonLib/SRWExclusiveLock.h +++ b/src/AspNetCoreModuleV2/CommonLib/SRWExclusiveLock.h @@ -8,7 +8,7 @@ class SRWExclusiveLock { public: - SRWExclusiveLock(const SRWLOCK& lock) noexcept; + SRWExclusiveLock(const SRWLOCK& lock); ~SRWExclusiveLock(); private: const SRWLOCK& m_lock; diff --git a/src/AspNetCoreModuleV2/CommonLib/irequesthandler.h b/src/AspNetCoreModuleV2/CommonLib/irequesthandler.h index c89411f8a0..8bd2076072 100644 --- a/src/AspNetCoreModuleV2/CommonLib/irequesthandler.h +++ b/src/AspNetCoreModuleV2/CommonLib/irequesthandler.h @@ -54,9 +54,3 @@ struct IREQUEST_HANDLER_DELETER application->DereferenceRequestHandler(); } }; - -inline std::unique_ptr ReferenceRequestHandler(IREQUEST_HANDLER* handler) -{ - handler->ReferenceRequestHandler(); - return std::unique_ptr(handler); -}; diff --git a/test/Common.FunctionalTests/ClientDisconnectStress.cs b/test/Common.FunctionalTests/ClientDisconnectStress.cs deleted file mode 100644 index 9deeae3f92..0000000000 --- a/test/Common.FunctionalTests/ClientDisconnectStress.cs +++ /dev/null @@ -1,65 +0,0 @@ -// 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.Collections.Generic; -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 -{ - [Collection(PublishedSitesCollection.Name)] - public class ClientDisconnectStressTests: FunctionalTestsBase - { - private readonly PublishedSitesFixture _fixture; - - public ClientDisconnectStressTests(PublishedSitesFixture fixture) - { - _fixture = fixture; - } - - [ConditionalTheory] - [InlineData(HostingModel.InProcess)] - [InlineData(HostingModel.OutOfProcess)] - public async Task ClientDisconnectStress(HostingModel hostingModel) - { - var site = await StartAsync(_fixture.GetBaseDeploymentParameters(hostingModel)); - var maxRequestSize = 1000; - var blockSize = 40; - var random = new Random(); - async Task RunRequests() - { - using (var connection = new TestConnection(site.HttpClient.BaseAddress.Port)) - { - await connection.Send( - "POST /ReadAndFlushEcho HTTP/1.1", - $"Content-Length: {maxRequestSize}", - "Host: localhost", - "Connection: close", - "", - ""); - - var disconnectAfter = random.Next(maxRequestSize); - var data = new byte[blockSize]; - for (int i = 0; i < disconnectAfter / blockSize; i++) - { - await connection.Stream.WriteAsync(data); - } - } - } - - List tasks = new List(); - for (int i = 0; i < 100; i++) - { - tasks.Add(Task.Run(RunRequests)); - } - - await Task.WhenAll(tasks); - - StopServer(); - } - } -} diff --git a/test/WebSites/InProcessWebSite/Startup.cs b/test/WebSites/InProcessWebSite/Startup.cs index eb84272b76..39d3b9f765 100644 --- a/test/WebSites/InProcessWebSite/Startup.cs +++ b/test/WebSites/InProcessWebSite/Startup.cs @@ -324,17 +324,6 @@ namespace TestSite result = await ctx.Request.Body.ReadAsync(readBuffer, 0, readBuffer.Length); } } - private async Task ReadAndFlushEcho(HttpContext ctx) - { - var readBuffer = new byte[4096]; - var result = await ctx.Request.Body.ReadAsync(readBuffer, 0, readBuffer.Length); - while (result != 0) - { - await ctx.Response.WriteAsync(Encoding.UTF8.GetString(readBuffer, 0, result)); - await ctx.Response.Body.FlushAsync(); - result = await ctx.Request.Body.ReadAsync(readBuffer, 0, readBuffer.Length); - } - } private async Task ReadAndWriteEchoLines(HttpContext ctx) {