diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj index d53a438f03..db33b281cd 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj @@ -233,8 +233,6 @@ - - @@ -249,7 +247,6 @@ - diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp index 8491edc5a4..cb4893196f 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp @@ -28,7 +28,10 @@ HandlerResolver::HandlerResolver(HMODULE hModule, const IHttpServer &pServer) } HRESULT -HandlerResolver::LoadRequestHandlerAssembly(const IHttpApplication &pApplication, const ShimOptions& pConfiguration, std::unique_ptr& pApplicationFactory) +HandlerResolver::LoadRequestHandlerAssembly(const IHttpApplication &pApplication, + const ShimOptions& pConfiguration, + std::unique_ptr& pApplicationFactory, + ErrorContext& errorContext) { HRESULT hr = S_OK; PCWSTR pstrHandlerDllName = nullptr; @@ -53,6 +56,7 @@ HandlerResolver::LoadRequestHandlerAssembly(const IHttpApplication &pApplication { if (pConfiguration.QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS) { + errorContext.generalErrorType = "ANCM In-Process Handler Load Failure"; std::unique_ptr options; RETURN_IF_FAILED(HostFxrResolutionResult::Create( @@ -66,12 +70,12 @@ HandlerResolver::LoadRequestHandlerAssembly(const IHttpApplication &pApplication auto redirectionOutput = std::make_shared(); - hr = FindNativeAssemblyFromHostfxr(*options, pstrHandlerDllName, handlerDllPath, pApplication, pConfiguration, redirectionOutput); + hr = FindNativeAssemblyFromHostfxr(*options, pstrHandlerDllName, handlerDllPath, pApplication, pConfiguration, redirectionOutput, errorContext); + + auto output = redirectionOutput->GetOutput(); if (FAILED_LOG(hr)) { - auto output = redirectionOutput->GetOutput(); - EventLog::Error( ASPNETCORE_EVENT_GENERAL_ERROR, ASPNETCORE_EVENT_INPROCESS_RH_ERROR_MSG, @@ -81,12 +85,20 @@ HandlerResolver::LoadRequestHandlerAssembly(const IHttpApplication &pApplication } else { + errorContext.generalErrorType = "ANCM Out-Of-Process Handler Load Failure"; + if (FAILED_LOG(hr = FindNativeAssemblyFromGlobalLocation(pConfiguration, pstrHandlerDllName, handlerDllPath))) { + auto handlerName = handlerDllPath.empty() ? s_pwzAspnetcoreOutOfProcessRequestHandlerName : handlerDllPath.c_str(); EventLog::Error( ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING, ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG, - handlerDllPath.empty() ? s_pwzAspnetcoreOutOfProcessRequestHandlerName : handlerDllPath.c_str()); + handlerName); + + errorContext.detailedErrorContent = to_multi_byte_string(format(ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG, handlerName), CP_UTF8); + errorContext.statusCode = 500i16; + errorContext.subStatusCode = 36i16; + errorContext.errorReason = "The out of process request handler, aspnetcorev2_outofprocess.dll, could not be found next to the aspnetcorev2.dll."; return hr; } @@ -96,6 +108,7 @@ HandlerResolver::LoadRequestHandlerAssembly(const IHttpApplication &pApplication hRequestHandlerDll = LoadLibrary(handlerDllPath.c_str()); RETURN_LAST_ERROR_IF_NULL(hRequestHandlerDll); + if (preventUnload) { // Pin module in memory @@ -111,7 +124,7 @@ HandlerResolver::LoadRequestHandlerAssembly(const IHttpApplication &pApplication } HRESULT -HandlerResolver::GetApplicationFactory(const IHttpApplication &pApplication, std::unique_ptr& pApplicationFactory, const ShimOptions& options) +HandlerResolver::GetApplicationFactory(const IHttpApplication& pApplication, std::unique_ptr& pApplicationFactory, const ShimOptions& options, ErrorContext& errorContext) { SRWExclusiveLock lock(m_requestHandlerLoadLock); if (m_loadedApplicationHostingModel != HOSTING_UNKNOWN) @@ -119,6 +132,12 @@ HandlerResolver::GetApplicationFactory(const IHttpApplication &pApplication, std // Mixed hosting models if (m_loadedApplicationHostingModel != options.QueryHostingModel()) { + errorContext.detailedErrorContent = to_multi_byte_string(format(ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG, pApplication.GetApplicationId(), options.QueryHostingModel()), CP_UTF8); + errorContext.statusCode = 500i16; + errorContext.subStatusCode = 34i16; + errorContext.generalErrorType = "ANCM Mixed Hosting Models Not Supported"; + errorContext.errorReason = "Select a different application pool to create another application."; + EventLog::Error( ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR, ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG, @@ -130,6 +149,13 @@ HandlerResolver::GetApplicationFactory(const IHttpApplication &pApplication, std // Multiple in-process apps if (m_loadedApplicationHostingModel == HOSTING_IN_PROCESS && m_loadedApplicationId != pApplication.GetApplicationId()) { + errorContext.detailedErrorContent = to_multi_byte_string(format(ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP_MSG, pApplication.GetApplicationId()), CP_UTF8); + + errorContext.statusCode = 500i16; + errorContext.subStatusCode = 35i16; + errorContext.generalErrorType = "ANCM Multiple In-Process Applications in same Process"; + errorContext.errorReason = "Select a different application pool to create another in-process application."; + EventLog::Error( ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP, ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP_MSG, @@ -141,7 +167,7 @@ HandlerResolver::GetApplicationFactory(const IHttpApplication &pApplication, std m_loadedApplicationHostingModel = options.QueryHostingModel(); m_loadedApplicationId = pApplication.GetApplicationId(); - RETURN_IF_FAILED(LoadRequestHandlerAssembly(pApplication, options, pApplicationFactory)); + RETURN_IF_FAILED(LoadRequestHandlerAssembly(pApplication, options, pApplicationFactory, errorContext)); return S_OK; } @@ -181,7 +207,7 @@ HandlerResolver::FindNativeAssemblyFromGlobalLocation( } catch (...) { - EventLog::Info( + EventLog::Info( ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING, ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG, pstrHandlerDllName); @@ -204,7 +230,8 @@ HandlerResolver::FindNativeAssemblyFromHostfxr( std::wstring& handlerDllPath, const IHttpApplication &pApplication, const ShimOptions& pConfiguration, - std::shared_ptr stringRedirectionOutput + std::shared_ptr stringRedirectionOutput, + ErrorContext& errorContext ) try { @@ -214,14 +241,25 @@ try DWORD dwBufferSize = s_initialGetNativeSearchDirectoriesBufferSize; DWORD dwRequiredBufferSize = 0; - m_hHostFxrDll.Load(hostfxrOptions.GetHostFxrLocation()); - + try + { + m_hHostFxrDll.Load(hostfxrOptions.GetHostFxrLocation()); + } + catch (...) + { + errorContext.detailedErrorContent = "Could not load hostfxr.dll."; + errorContext.statusCode = 500i16; + errorContext.subStatusCode = 32i16; + errorContext.generalErrorType = "ANCM Failed to Load dll"; + errorContext.errorReason = "The application was likely published for a different bitness than w3wp.exe/iisexpress.exe is running as."; + throw; + } { auto redirectionOutput = LoggingHelpers::CreateOutputs( pConfiguration.QueryStdoutLogEnabled(), pConfiguration.QueryStdoutLogFile(), pApplication.GetApplicationPhysicalPath(), - std::move(stringRedirectionOutput) + stringRedirectionOutput ); StandardStreamRedirection stdOutRedirection(*redirectionOutput.get(), m_pServer.IsCommandLineLaunch()); @@ -256,7 +294,16 @@ try else { // If hostfxr didn't set the required buffer size, something in the app is misconfigured - // Ex: Framework not found. + // This like almost always is framework not found. + auto output = to_multi_byte_string(stringRedirectionOutput->GetOutput(), CP_UTF8); + errorContext.detailedErrorContent.resize(output.length()); + memcpy(&errorContext.detailedErrorContent[0], output.c_str(), output.length()); + + errorContext.statusCode = 500i16; + errorContext.subStatusCode = 31i16; + errorContext.generalErrorType = "ANCM Failed to Find Native Dependencies"; + errorContext.errorReason = "The specified version of Microsoft.NetCore.App or Microsoft.AspNetCore.App was not found."; + EventLog::Error( ASPNETCORE_EVENT_GENERAL_ERROR, ASPNETCORE_EVENT_HOSTFXR_FAILURE_MSG @@ -296,6 +343,16 @@ try if (!fFound) { + // This only occurs if the request handler isn't referenced by the app, which rarely happens if they are targeting the shared framework. + errorContext.statusCode = 500i16; + errorContext.subStatusCode = 33i16; + errorContext.generalErrorType = "ANCM Request Handler Load Failure"; + errorContext.detailedErrorContent = to_multi_byte_string(format(ASPNETCORE_EVENT_INPROCESS_RH_REFERENCE_MSG, handlerDllPath.empty() + ? s_pwzAspnetcoreInProcessRequestHandlerName + : handlerDllPath.c_str()), + CP_UTF8); + errorContext.errorReason = "Make sure Microsoft.AspNetCore.App is referenced by your application."; + EventLog::Error( ASPNETCORE_EVENT_GENERAL_ERROR, ASPNETCORE_EVENT_INPROCESS_RH_REFERENCE_MSG, diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h index faa81855c3..9ab017bb50 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h @@ -16,11 +16,11 @@ class HandlerResolver { public: HandlerResolver(HMODULE hModule, const IHttpServer &pServer); - HRESULT GetApplicationFactory(const IHttpApplication &pApplication, std::unique_ptr& pApplicationFactory, const ShimOptions& options); + HRESULT GetApplicationFactory(const IHttpApplication &pApplication, std::unique_ptr& pApplicationFactory, const ShimOptions& options, ErrorContext& errorContext); void ResetHostingModel(); private: - HRESULT LoadRequestHandlerAssembly(const IHttpApplication &pApplication, const ShimOptions& pConfiguration, std::unique_ptr& pApplicationFactory); + HRESULT LoadRequestHandlerAssembly(const IHttpApplication &pApplication, const ShimOptions& pConfiguration, std::unique_ptr& pApplicationFactory, ErrorContext& errorContext); HRESULT FindNativeAssemblyFromGlobalLocation(const ShimOptions& pConfiguration, PCWSTR libraryName, std::wstring& handlerDllPath); HRESULT FindNativeAssemblyFromHostfxr( const HostFxrResolutionResult& hostfxrOptions, @@ -28,7 +28,8 @@ private: std::wstring& handlerDllPath, const IHttpApplication &pApplication, const ShimOptions& pConfiguration, - std::shared_ptr stringRedirectionOutput); + std::shared_ptr stringRedirectionOutput, + ErrorContext& errorContext); HMODULE m_hModule; const IHttpServer &m_pServer; diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/InProcessShimStaticHtml.htm b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/InProcessShimStaticHtml.htm index a8c9d7fe1f..a9e6d96c75 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/InProcessShimStaticHtml.htm +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/InProcessShimStaticHtml.htm @@ -2,7 +2,7 @@ - HTTP Error 500.0 - ANCM In-Process Handler Load Failure + HTTP Error %d.%d - %s -

HTTP Error 500.0 - ANCM In-Process Handler Load Failure

+

HTTP Error %d.%d - %s

-

Common causes of this issue:

+ %s -
    -
  • 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.
  • -
+ %s

Troubleshooting steps:

diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/OutOfProcessShimStaticHtml.htm b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/OutOfProcessShimStaticHtml.htm index 1194cf4025..b15ed7dccb 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/OutOfProcessShimStaticHtml.htm +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/OutOfProcessShimStaticHtml.htm @@ -2,7 +2,7 @@ - HTTP Error 500.0 - ANCM Out-Of-Process Handler Load Failure + HTTP Error %d.%d - %s -

HTTP Error 500.0 - ANCM Out-Of-Process Handler Load Failure

+

HTTP Error %d.%d - %s

-

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.
  • -
+ %s + + %s

Troubleshooting steps:

    diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp index cb7f1488d7..fa1282cdb6 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp @@ -5,6 +5,7 @@ #include "StringHelpers.h" #include "ConfigurationLoadException.h" +#include "Environment.h" #define CS_ASPNETCORE_HANDLER_VERSION L"handlerVersion" @@ -41,4 +42,16 @@ ShimOptions::ShimOptions(const ConfigurationSource &configurationSource) : 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); + + // This will not include environment variables defined in the web.config. + // Reading environment variables can be added here, but it adds more code to the shim. + const auto detailedErrors = Environment::GetEnvironmentVariableValue(L"ASPNETCORE_DETAILEDERRORS").value_or(L""); + const auto aspnetCoreEnvironment = Environment::GetEnvironmentVariableValue(L"ASPNETCORE_ENVIRONMENT").value_or(L""); + const auto dotnetEnvironment = Environment::GetEnvironmentVariableValue(L"DOTNET_ENVIRONMENT").value_or(L""); + + auto detailedErrorsEnabled = equals_ignore_case(L"1", detailedErrors) || equals_ignore_case(L"true", detailedErrors); + auto aspnetCoreEnvironmentEnabled = equals_ignore_case(L"Development", aspnetCoreEnvironment); + auto dotnetEnvironmentEnabled = equals_ignore_case(L"Development", dotnetEnvironment); + + m_fShowDetailedErrors = detailedErrorsEnabled || aspnetCoreEnvironmentEnabled || dotnetEnvironmentEnabled; } diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.h b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.h index 3cfb47169e..5d1c04f8ab 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.h @@ -59,6 +59,12 @@ public: return m_fDisableStartupPage; } + bool + QueryShowDetailedErrors() const noexcept + { + return m_fShowDetailedErrors; + } + ShimOptions(const ConfigurationSource &configurationSource); private: @@ -69,4 +75,5 @@ private: std::wstring m_struStdoutLogFile; bool m_fStdoutLogEnabled; bool m_fDisableStartupPage; + bool m_fShowDetailedErrors; }; diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp index 317a8a5d4b..a0a6bfeb3b 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp @@ -15,6 +15,7 @@ #include "WebConfigConfigurationSource.h" #include "ConfigurationLoadException.h" #include "resource.h" +#include "file_utility.h" extern HINSTANCE g_hServerModule; @@ -86,23 +87,39 @@ APPLICATION_INFO::CreateApplication(IHttpContext& pHttpContext) const WebConfigConfigurationSource configurationSource(m_pServer.GetAdminManager(), pHttpApplication); ShimOptions options(configurationSource); - const auto hr = TryCreateApplication(pHttpContext, options); + ErrorContext errorContext; + errorContext.statusCode = 500i16; + errorContext.subStatusCode = 0i16; + + const auto hr = TryCreateApplication(pHttpContext, options, errorContext); 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); + auto page = options.QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS ? IN_PROCESS_SHIM_STATIC_HTML : OUT_OF_PROCESS_SHIM_STATIC_HTML; + std::string responseContent; + if (options.QueryShowDetailedErrors()) + { + responseContent = FILE_UTILITY::GetHtml(g_hServerModule, page, errorContext.statusCode, errorContext.subStatusCode, errorContext.generalErrorType, errorContext.errorReason, errorContext.detailedErrorContent); + } + else + { + responseContent = FILE_UTILITY::GetHtml(g_hServerModule, page, errorContext.statusCode, errorContext.subStatusCode, errorContext.generalErrorType, errorContext.errorReason); + } + 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); + responseContent, + errorContext.statusCode, + errorContext.subStatusCode, + "Internal Server Error"); } return S_OK; } @@ -124,14 +141,18 @@ APPLICATION_INFO::CreateApplication(IHttpContext& pHttpContext) m_pApplication = make_application( pHttpApplication, E_FAIL, - g_hServerModule); + false /* disableStartupPage */, + "" /* responseContent */, + 500i16 /* statusCode */, + 0i16 /* subStatusCode */, + "Internal Server Error"); return S_OK; } } HRESULT -APPLICATION_INFO::TryCreateApplication(IHttpContext& pHttpContext, const ShimOptions& options) +APPLICATION_INFO::TryCreateApplication(IHttpContext& pHttpContext, const ShimOptions& options, ErrorContext& error) { const auto startupEvent = Environment::GetEnvironmentVariableValue(L"ASPNETCORE_STARTUP_SUSPEND_EVENT"); if (startupEvent.has_value()) @@ -157,7 +178,7 @@ APPLICATION_INFO::TryCreateApplication(IHttpContext& pHttpContext, const ShimOpt } } - RETURN_IF_FAILED(m_handlerResolver.GetApplicationFactory(*pHttpContext.GetApplication(), m_pApplicationFactory, options)); + RETURN_IF_FAILED(m_handlerResolver.GetApplicationFactory(*pHttpContext.GetApplication(), m_pApplicationFactory, options, error)); LOG_INFO(L"Creating handler application"); IAPPLICATION * newApplication; diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.h b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.h index 252d4e0d2d..f90b0588d9 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.h @@ -77,7 +77,7 @@ private: CreateApplication(IHttpContext& pHttpContext); HRESULT - TryCreateApplication(IHttpContext& pHttpContext, const ShimOptions& options); + TryCreateApplication(IHttpContext& pHttpContext, const ShimOptions& options, ErrorContext& error); IHttpServer &m_pServer; HandlerResolver &m_handlerResolver; diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj index fc02995961..8816dafbda 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj @@ -196,6 +196,7 @@ + @@ -220,11 +221,11 @@ + - @@ -249,6 +250,7 @@ + @@ -277,4 +279,4 @@ - + \ No newline at end of file diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/Environment.cpp b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/Environment.cpp index be6484e16b..118a67198b 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/Environment.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/Environment.cpp @@ -45,6 +45,13 @@ Environment::GetEnvironmentVariableValue(const std::wstring & str) throw std::system_error(GetLastError(), std::system_category(), "GetEnvironmentVariableW"); } + else if (requestedSize == 1) + { + // String just contains a nullcharacter, return empty string + // GetEnvironmentVariableW has inconsistent behavior when returning size for an empty + // environment variable. + return L""; + } std::wstring expandedStr; do @@ -53,6 +60,10 @@ Environment::GetEnvironmentVariableValue(const std::wstring & str) requestedSize = GetEnvironmentVariableW(str.c_str(), expandedStr.data(), requestedSize); if (requestedSize == 0) { + if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) + { + return std::nullopt; + } throw std::system_error(GetLastError(), std::system_category(), "ExpandEnvironmentStringsW"); } } while (expandedStr.size() != requestedSize + 1); diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.h b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.h index 990963b6e7..85cae5b1ba 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.h @@ -12,6 +12,16 @@ typedef INT(*hostfxr_main_fn) (DWORD argc, CONST PCWSTR argv[]); typedef void(*corehost_error_writer_fn) (const WCHAR* message); typedef corehost_error_writer_fn(*corehost_set_error_writer_fn) (corehost_error_writer_fn error_writer); +struct ErrorContext +{ + // TODO consider adding HRESULT here + std::string detailedErrorContent; + USHORT statusCode; + USHORT subStatusCode; + std::string generalErrorType; + std::string errorReason; +}; + class HostFxrErrorRedirector: NonCopyable { public: diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/PollingAppOfflineApplication.cpp b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.cpp similarity index 100% rename from src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/PollingAppOfflineApplication.cpp rename to src/Servers/IIS/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.cpp diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/PollingAppOfflineApplication.h b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.h similarity index 100% rename from src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/PollingAppOfflineApplication.h rename to src/Servers/IIS/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.h diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ServerErrorApplication.h b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/ServerErrorApplication.h similarity index 58% rename from src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ServerErrorApplication.h rename to src/Servers/IIS/AspNetCoreModuleV2/CommonLib/ServerErrorApplication.h index b5b86aa20c..6cb0cd9342 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ServerErrorApplication.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/ServerErrorApplication.h @@ -9,16 +9,13 @@ class ServerErrorApplication : public PollingAppOfflineApplication { public: - 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) + ServerErrorApplication(const IHttpApplication& pApplication, HRESULT hr, bool disableStartupPage, const std::string& responseContent, USHORT status, USHORT substatus, const std::string& statusText) : m_HR(hr), m_disableStartupPage(disableStartupPage), - m_page(page), - m_moduleInstance(moduleInstance), + m_responseContent(responseContent), + m_statusCode(status), + m_subStatusCode(substatus), + m_statusText(statusText), PollingAppOfflineApplication(pApplication, PollingAppOfflineApplicationMode::StopWhenAdded) { } @@ -27,8 +24,8 @@ public: HRESULT CreateHandler(IHttpContext *pHttpContext, IREQUEST_HANDLER ** pRequestHandler) override { - auto handler = std::make_unique(*pHttpContext, 500ui16, 0ui16, "Internal Server Error", m_HR, m_moduleInstance, m_disableStartupPage, m_page); - *pRequestHandler = handler.release(); + *pRequestHandler = std::make_unique(*pHttpContext, m_statusCode, m_subStatusCode, m_statusText, m_HR, m_disableStartupPage, m_responseContent).release(); + return S_OK; } @@ -36,6 +33,8 @@ public: private: HRESULT m_HR; bool m_disableStartupPage; - int m_page; - HINSTANCE m_moduleInstance; + std::string m_responseContent; + USHORT m_statusCode; + USHORT m_subStatusCode; + std::string m_statusText; }; diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/ServerErrorHandler.h b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/ServerErrorHandler.h index 3296c68c11..77d94230b2 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/ServerErrorHandler.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/ServerErrorHandler.h @@ -9,44 +9,36 @@ class ServerErrorHandler : public REQUEST_HANDLER { public: - ServerErrorHandler(IHttpContext& pContext, USHORT statusCode, USHORT subStatusCode, const std::string& statusText, HRESULT hr, HINSTANCE module, bool disableStartupPage, int page) noexcept - : ServerErrorHandler(pContext, statusCode, subStatusCode, statusText, hr, module, disableStartupPage, page, std::vector()) - { - } - - ServerErrorHandler(IHttpContext& pContext, USHORT statusCode, USHORT subStatusCode, const std::string& statusText, HRESULT hr, HINSTANCE module, bool disableStartupPage, int page, const std::vector& content) noexcept + ServerErrorHandler(IHttpContext& pContext, USHORT statusCode, USHORT subStatusCode, const std::string& statusText, HRESULT hr, bool disableStartupPage, std::string& responseContent) noexcept : REQUEST_HANDLER(pContext), - m_pContext(pContext), m_HR(hr), m_disableStartupPage(disableStartupPage), m_statusCode(statusCode), m_subStatusCode(subStatusCode), m_statusText(std::move(statusText)), - m_page(page), - m_ExceptionInfoContent(content), - m_moduleInstance(module) + m_ExceptionInfoContent(responseContent) { } REQUEST_NOTIFICATION_STATUS ExecuteRequestHandler() override { - WriteStaticResponse(m_pContext, m_HR, m_disableStartupPage); + WriteResponse(); return RQ_NOTIFICATION_FINISH_REQUEST; } private: - void WriteStaticResponse(IHttpContext& pContext, HRESULT hr, bool disableStartupErrorPage) + void WriteResponse() { - if (disableStartupErrorPage) + if (m_disableStartupPage) { - pContext.GetResponse()->SetStatus(m_statusCode, m_statusText.c_str(), m_subStatusCode, E_FAIL); + m_pHttpContext.GetResponse()->SetStatus(m_statusCode, m_statusText.c_str(), m_subStatusCode, E_FAIL); return; } HTTP_DATA_CHUNK dataChunk = {}; - IHttpResponse* pResponse = pContext.GetResponse(); - pResponse->SetStatus(m_statusCode, m_statusText.c_str(), m_subStatusCode, hr, nullptr, true); + IHttpResponse* pResponse = m_pHttpContext.GetResponse(); + pResponse->SetStatus(m_statusCode, m_statusText.c_str(), m_subStatusCode, m_HR, nullptr, true); pResponse->SetHeader("Content-Type", "text/html", (USHORT)strlen("text/html"), @@ -54,62 +46,16 @@ private: ); dataChunk.DataChunkType = HttpDataChunkFromMemory; - if (m_ExceptionInfoContent.size() > 0) - { - dataChunk.FromMemory.pBuffer = &m_ExceptionInfoContent[0]; - dataChunk.FromMemory.BufferLength = static_cast(m_ExceptionInfoContent.size()); - } - else - { - static std::string s_html500Page = GetHtml(m_moduleInstance, m_page); - dataChunk.FromMemory.pBuffer = s_html500Page.data(); - dataChunk.FromMemory.BufferLength = static_cast(s_html500Page.size()); - } - + dataChunk.FromMemory.pBuffer = m_ExceptionInfoContent.data(); + dataChunk.FromMemory.BufferLength = static_cast(m_ExceptionInfoContent.size()); + pResponse->WriteEntityChunkByReference(&dataChunk); } - std::string - GetHtml(HMODULE module, int page) - { - try - { - HRSRC rc = nullptr; - HGLOBAL rcData = nullptr; - std::string data; - const char* pTempData = nullptr; - - THROW_LAST_ERROR_IF_NULL(rc = FindResource(module, MAKEINTRESOURCE(page), RT_HTML)); - THROW_LAST_ERROR_IF_NULL(rcData = LoadResource(module, rc)); - auto const size = SizeofResource(module, rc); - THROW_LAST_ERROR_IF(size == 0); - THROW_LAST_ERROR_IF_NULL(pTempData = static_cast(LockResource(rcData))); - data = std::string(pTempData, size); - - auto additionalErrorLink = Environment::GetEnvironmentVariableValue(L"ANCM_ADDITIONAL_ERROR_PAGE_LINK"); - std::string additionalHtml; - - if (additionalErrorLink.has_value()) - { - additionalHtml = format(" %S and ", additionalErrorLink->c_str(), additionalErrorLink->c_str()); - } - - return format(data, additionalHtml.c_str()); - } - catch (...) - { - OBSERVE_CAUGHT_EXCEPTION(); - return ""; - } - } - - IHttpContext& m_pContext; HRESULT m_HR; bool m_disableStartupPage; - int m_page; - HINSTANCE m_moduleInstance; USHORT m_statusCode; USHORT m_subStatusCode; std::string m_statusText; - std::vector m_ExceptionInfoContent; + std::string& m_ExceptionInfoContent; }; diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/file_utility.cpp b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/file_utility.cpp index 2831eac64d..fb10427e3f 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/file_utility.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/file_utility.cpp @@ -6,6 +6,7 @@ #include #include "debugutil.h" #include "exceptions.h" +#include "Environment.h" HRESULT FILE_UTILITY::IsPathUnc( @@ -167,3 +168,53 @@ Finished: return hr; } +std::string FILE_UTILITY::GetHtml(HMODULE module, int page, USHORT statusCode, USHORT subStatusCode, const std::string& speicificReasonPhrase, const std::string& solution) +{ + return GetHtml(module, page, statusCode, subStatusCode, speicificReasonPhrase, solution, std::string()); +} + +std::string +FILE_UTILITY::GetHtml(HMODULE module, int page, USHORT statusCode, USHORT subStatusCode, const std::string& specificReasonPhrase, const std::string& errorReason, const std::string& specificError) +{ + try + { + HRSRC rc = nullptr; + HGLOBAL rcData = nullptr; + std::string data; + const char* pTempData = nullptr; + + THROW_LAST_ERROR_IF_NULL(rc = FindResource(module, MAKEINTRESOURCE(page), RT_HTML)); + THROW_LAST_ERROR_IF_NULL(rcData = LoadResource(module, rc)); + auto const size = SizeofResource(module, rc); + THROW_LAST_ERROR_IF(size == 0); + THROW_LAST_ERROR_IF_NULL(pTempData = static_cast(LockResource(rcData))); + data = std::string(pTempData, size); + + auto additionalErrorLink = Environment::GetEnvironmentVariableValue(L"ANCM_ADDITIONAL_ERROR_PAGE_LINK"); + std::string additionalHtml; + + if (additionalErrorLink.has_value()) + { + additionalHtml = format(" %S and ", additionalErrorLink->c_str(), additionalErrorLink->c_str()); + } + + std::string formattedError; + if (!specificError.empty()) + { + formattedError = format("

    Specific error detected by ANCM:

    %s

    ", specificError.c_str()); + } + + std::string formattedErrorReason; + if (!errorReason.empty()) + { + formattedErrorReason = format("

    Common solutions to this issue:

    %s", errorReason.c_str()); + } + + return format(data, statusCode, subStatusCode, specificReasonPhrase.c_str(), statusCode, subStatusCode, specificReasonPhrase.c_str(), formattedErrorReason.c_str(), formattedError.c_str(), additionalHtml.c_str()); + } + catch (...) + { + OBSERVE_CAUGHT_EXCEPTION(); + return ""; + } +} diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/file_utility.h b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/file_utility.h index 686e810cbe..fc3ce8935b 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/file_utility.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/file_utility.h @@ -28,7 +28,11 @@ public: static std::string - GetHtml(HMODULE module, int page); + GetHtml(HMODULE module, int page, USHORT statusCode, USHORT subStatusCode, const std::string& speicificReasonPhrase, const std::string& solution); + + static + std::string + GetHtml(HMODULE module, int page, USHORT statusCode, USHORT subStatusCode, const std::string& speicificReasonPhrase, const std::string& solution, const std::string& error); private: static diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/requesthandler.h b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/requesthandler.h index 6274efc07e..1c78fcd0ca 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/requesthandler.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/requesthandler.h @@ -75,7 +75,7 @@ public: { } -private: +protected: IHttpContext& m_pHttpContext; mutable LONG m_cRefs = 1; }; diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/resources.h b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/resources.h index 04ee2e0944..9535d1c0cb 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/resources.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/resources.h @@ -43,7 +43,7 @@ #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'. First 30KB characters of captured stdout and stderr logs:\r\n%s" #define ASPNETCORE_EVENT_INPROCESS_RH_ERROR_MSG L"Could not find 'aspnetcorev2_inprocess.dll'. Exception message:\r\n%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_INPROCESS_RH_REFERENCE_MSG L"Could not find the assembly '%s' referenced for the in-process application. Please confirm the Microsoft.AspNetCore.Server.IIS or Microsoft.AspNetCore.App 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 successfully." #define ASPNETCORE_EVENT_INPROCESS_START_ERROR_MSG L"Application '%s' failed to start. Exception message:\r\n%s" diff --git a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRhStaticHtml.htm b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRhStaticHtml.htm index 59d6b0dacb..8783b58adb 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRhStaticHtml.htm +++ b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRhStaticHtml.htm @@ -2,7 +2,7 @@ - HTTP Error 500.30 - ANCM In-Process Start Failure + HTTP Error %d.%d - %s -

    HTTP Error 500.30 - ANCM In-Process Start Failure

    +

    HTTP Error %d.%d - %s

    -

    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
    • -
    + %s + + %s

    Troubleshooting steps:

      diff --git a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.h b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.h index 6db5fee164..d3e50e620f 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.h @@ -13,15 +13,18 @@ public: StartupExceptionApplication( IHttpServer& pServer, IHttpApplication& pApplication, - HINSTANCE moduleInstance, BOOL disableLogs, HRESULT hr, - std::vector&& errorPageContent - ) + const std::string& errorPageContent, + USHORT statusCode, + USHORT subStatusCode, + const std::string& statusText) : m_disableLogs(disableLogs), m_HR(hr), - m_moduleInstance(moduleInstance), - m_errorPageContent(std::move(errorPageContent)), + m_error(errorPageContent), + m_statusCode(statusCode), + m_subStatusCode(subStatusCode), + m_statusText(std::move(statusText)), InProcessApplicationBase(pServer, pApplication) { } @@ -30,15 +33,17 @@ public: HRESULT CreateHandler(IHttpContext* pHttpContext, IREQUEST_HANDLER** pRequestHandler) { - *pRequestHandler = new ServerErrorHandler(*pHttpContext, 500, 30, "Internal Server Error", m_HR, m_moduleInstance, m_disableLogs, IN_PROCESS_RH_STATIC_HTML, m_errorPageContent); + *pRequestHandler = new ServerErrorHandler(*pHttpContext, m_statusCode, m_subStatusCode, m_statusText, m_HR, m_disableLogs, m_error); return S_OK; } private: - std::vector m_errorPageContent; + std::string m_error; BOOL m_disableLogs; HRESULT m_HR; - HINSTANCE m_moduleInstance; + USHORT m_statusCode; + USHORT m_subStatusCode; + std::string m_statusText; }; diff --git a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cpp b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cpp index 710bbee754..cd9261a56c 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cpp @@ -17,6 +17,7 @@ #include "WebConfigConfigurationSource.h" #include "ConfigurationLoadException.h" #include "StartupExceptionApplication.h" +#include "file_utility.h" DECLARE_DEBUG_PRINT_OBJECT("aspnetcorev2_inprocess.dll"); @@ -28,7 +29,7 @@ HINSTANCE g_hWinHttpModule; HINSTANCE g_hAspNetCoreModule; HANDLE g_hEventLog = NULL; bool g_fInProcessApplicationCreated = false; -std::vector g_errorPageContent; +std::string g_errorPageContent; HINSTANCE g_hServerModule; HRESULT @@ -120,6 +121,10 @@ CreateApplication( g_fInProcessApplicationCreated = true; std::unique_ptr inProcessApplication; + + // TODO not sure how easy it will be to untangle errors here + // ErrorContext errorContext; + if (!FAILED_LOG(hr = IN_PROCESS_APPLICATION::Start(*pServer, pSite, *pHttpApplication, pParameters, nParameters, inProcessApplication))) { *ppApplication = inProcessApplication.release(); @@ -129,7 +134,20 @@ CreateApplication( std::unique_ptr options; THROW_IF_FAILED(InProcessOptions::Create(*pServer, pSite, *pHttpApplication, options)); // Set the currently running application to a fake application that returns startup exceptions. - auto pErrorApplication = std::make_unique(*pServer, *pHttpApplication, g_hServerModule, options->QueryDisableStartUpErrorPage(), hr, std::move(g_errorPageContent)); + auto pErrorApplication = std::make_unique(*pServer, + *pHttpApplication, + options->QueryDisableStartUpErrorPage(), + hr, + FILE_UTILITY::GetHtml(g_hServerModule, + IN_PROCESS_RH_STATIC_HTML, + 500i16, + 30i16, + "ANCM In-Process Start Failure", + "
      • The application failed to start
      • The application started but then stopped
      • The application started but threw an exception during startup
      ", + g_errorPageContent), + 500i16, + 30i16, + "Internal Server Error"); RETURN_IF_FAILED(pErrorApplication->StartMonitoringAppOffline()); *ppApplication = pErrorApplication.release(); diff --git a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp index e52ec8c8e4..a7bcaa3675 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp @@ -7,7 +7,7 @@ #include "EventLog.h" extern bool g_fInProcessApplicationCreated; -extern std::vector g_errorPageContent; +extern std::string g_errorPageContent; extern IHttpServer* g_pHttpServer; // diff --git a/src/Servers/IIS/AspNetCoreModuleV2/OutOfProcessRequestHandler/OutOfProcessRhStaticHtml.htm b/src/Servers/IIS/AspNetCoreModuleV2/OutOfProcessRequestHandler/OutOfProcessRhStaticHtml.htm index e7d2f04e7c..bedf0a8dce 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/OutOfProcessRequestHandler/OutOfProcessRhStaticHtml.htm +++ b/src/Servers/IIS/AspNetCoreModuleV2/OutOfProcessRequestHandler/OutOfProcessRhStaticHtml.htm @@ -2,7 +2,7 @@ - HTTP Error 502.5 - ANCM Out-Of-Process Startup Failure + HTTP Error %d.%d - %s -

      HTTP Error 502.5 - ANCM Out-Of-Process Startup Failure

      +

      HTTP Error %d.%d - %s

      -

      Common causes of this issue:

      + %s -
        -
      • The application process failed to start
      • -
      • The application process started but then stopped
      • -
      • The application process started but failed to listen on the configured port
      • -
      + %s -

      Troubleshooting steps:

      +

      Troubleshooting steps:

      • Check the system event log for error messages
      • diff --git a/src/Servers/IIS/AspNetCoreModuleV2/OutOfProcessRequestHandler/forwardinghandler.cpp b/src/Servers/IIS/AspNetCoreModuleV2/OutOfProcessRequestHandler/forwardinghandler.cpp index 551d10c9f9..4fbf2abf40 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/OutOfProcessRequestHandler/forwardinghandler.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/OutOfProcessRequestHandler/forwardinghandler.cpp @@ -4,8 +4,10 @@ #include "forwardinghandler.h" #include "url_utility.h" #include "exceptions.h" +#include "ServerErrorApplication.h" #include "ServerErrorHandler.h" #include "resource.h" +#include "file_utility.h" // Just to be aware of the FORWARDING_HANDLER object size. C_ASSERT(sizeof(FORWARDING_HANDLER) <= 632); @@ -302,7 +304,21 @@ Failure: } else if (fFailedToStartKestrel && !m_pApplication->QueryConfig()->QueryDisableStartUpErrorPage()) { - ServerErrorHandler handler(*m_pW3Context, 502, 5, "Bad Gateway", hr, g_hOutOfProcessRHModule, m_pApplication->QueryConfig()->QueryDisableStartUpErrorPage(), OUT_OF_PROCESS_RH_STATIC_HTML); + static std::string htmlResponse = FILE_UTILITY::GetHtml(g_hOutOfProcessRHModule, + OUT_OF_PROCESS_RH_STATIC_HTML, + 502, + 5, + "ANCM Out-Of-Process Startup Failure", + "
        • The application process failed to start
        • The application process started but then stopped
        • The application process started but failed to listen on the configured port
        "); + + ServerErrorHandler handler(*m_pW3Context, + 502, + 5, + "Bad Gateway", + hr, + m_pApplication->QueryConfig()->QueryDisableStartUpErrorPage(), + htmlResponse); + handler.ExecuteRequestHandler(); } else diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/StartupTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/StartupTests.cs index 4374ba519a..7acbc1d2e3 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/StartupTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/StartupTests.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Net; +using System.Net.Http; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; @@ -268,11 +269,60 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests Path.Combine(deploymentResult.ContentRoot, "aspnetcorev2_inprocess.dll"), Path.Combine(deploymentResult.ContentRoot, "hostfxr.dll"), true); - await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult); + + if (DeployerSelector.HasNewShim) + { + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult, "HTTP Error 500.32 - ANCM Failed to Load dll"); + } + else + { + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult); + } EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessHostfxrInvalid(deploymentResult), Logger); } + [ConditionalFact] + public async Task PublishWithWrongBitness() + { + var deploymentParameters = Fixture.GetBaseDeploymentParameters(Fixture.InProcessTestSite); + + if (deploymentParameters.ServerType == ServerType.IISExpress) + { + // TODO skip conditions for IISExpress + return; + } + + deploymentParameters.ApplicationType = ApplicationType.Standalone; + deploymentParameters.AddServerConfigAction(element => + { + element.RequiredElement("system.applicationHost").RequiredElement("applicationPools").RequiredElement("add").SetAttributeValue("enable32BitAppOnWin64", "true"); + }); + + // Change ANCM dll to 32 bit + deploymentParameters.AddServerConfigAction( + element => + { + var ancmElement = element + .RequiredElement("system.webServer") + .RequiredElement("globalModules") + .Elements("add") + .FirstOrDefault(e => e.Attribute("name").Value == "AspNetCoreModuleV2"); + + ancmElement.SetAttributeValue("image", ancmElement.Attribute("image").Value.Replace("x64", "x86")); + }); + var deploymentResult = await DeployAsync(deploymentParameters); + + if (DeployerSelector.HasNewShim) + { + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult, "500.32 - ANCM Failed to Load dll"); + } + else + { + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult, "500.0 - ANCM In-Process Handler Load Failure"); + } + } + [ConditionalFact] [RequiresNewShim] public async Task RemoveHostfxrFromApp_InProcessHostfxrLoadFailure() @@ -283,7 +333,15 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests // We don't distinguish between load failure types so making dll empty should be enough File.WriteAllText(Path.Combine(deploymentResult.ContentRoot, "hostfxr.dll"), ""); - await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult); + + if (DeployerSelector.HasNewShim) + { + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult, "HTTP Error 500.32 - ANCM Failed to Load dll"); + } + else + { + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult); + } EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessHostfxrUnableToLoad(deploymentResult), Logger); } @@ -295,7 +353,14 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests var deploymentResult = await DeployAsync(deploymentParameters); Helpers.ModifyFrameworkVersionInRuntimeConfig(deploymentResult); - await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult); + if (DeployerSelector.HasNewShim) + { + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult, "HTTP Error 500.31 - ANCM Failed to Find Native Dependencies"); + } + else + { + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult); + } EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessFailedToFindNativeDependencies(deploymentResult), Logger); } @@ -309,14 +374,23 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests File.Delete(Path.Combine(deploymentResult.ContentRoot, "aspnetcorev2_inprocess.dll")); - await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult); - - if (DeployerSelector.IsForwardsCompatibilityTest) + if (DeployerSelector.HasNewShim && DeployerSelector.HasNewHandler) { + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult, "HTTP Error 500.33 - ANCM Request Handler Load Failure "); + + EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessFailedToFindRequestHandler(deploymentResult), Logger); + } + else if (DeployerSelector.HasNewShim) + { + // Forwards compat tests fail earlier due to a error with the M.AspNetCore.Server.IIS package. + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult, "HTTP Error 500.31 - ANCM Failed to Find Native Dependencies"); + EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessFailedToFindNativeDependencies(deploymentResult), Logger); } else { + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult); + EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessFailedToFindRequestHandler(deploymentResult), Logger); } } @@ -750,11 +824,23 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests }); } - private async Task AssertSiteFailsToStartWithInProcessStaticContent(IISDeploymentResult deploymentResult) + private Task AssertSiteFailsToStartWithInProcessStaticContent(IISDeploymentResult deploymentResult) { - var response = await deploymentResult.HttpClient.GetAsync("/HelloWorld"); + return AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult, "HTTP Error 500.0 - ANCM In-Process Handler Load Failure"); + } + + private async Task AssertSiteFailsToStartWithInProcessStaticContent(IISDeploymentResult deploymentResult, string error) + { + HttpResponseMessage response = null; + + // Make sure strings aren't freed. + for (var i = 0; i < 2; i++) + { + response = await deploymentResult.HttpClient.GetAsync("/HelloWorld"); + } + Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); - Assert.Contains("HTTP Error 500.0 - ANCM In-Process Handler Load Failure", await response.Content.ReadAsStringAsync()); + Assert.Contains(error, await response.Content.ReadAsStringAsync()); StopServer(); } } diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/MultiApplicationTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/MultiApplicationTests.cs index 87d9c73dd0..d22856610f 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/MultiApplicationTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/MultiApplicationTests.cs @@ -47,6 +47,12 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests Assert.Equal(200, (int)result1.StatusCode); Assert.Equal(500, (int)result2.StatusCode); StopServer(); + + if (DeployerSelector.HasNewShim) + { + Assert.Contains("500.35 - ANCM Multiple In-Process Applications in same Process", await result2.Content.ReadAsStringAsync()); + } + EventLogHelpers.VerifyEventLogEvent(result, EventLogHelpers.OnlyOneAppPerAppPool(), Logger); } @@ -68,6 +74,12 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests Assert.Equal(200, (int)result1.StatusCode); Assert.Equal(500, (int)result2.StatusCode); StopServer(); + + if (DeployerSelector.HasNewShim) + { + Assert.Contains("500.34 - ANCM Mixed Hosting Models Not Supported", await result2.Content.ReadAsStringAsync()); + } + EventLogHelpers.VerifyEventLogEvent(result, "Mixed hosting model is not supported.", Logger); } diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs index d2a94632c4..a487ba20dd 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs @@ -259,7 +259,15 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests 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."; + if (DeployerSelector.HasNewShim) + { + return "Could not find the assembly '(.*)' referenced for the in-process application. Please confirm the Microsoft.AspNetCore.Server.IIS or Microsoft.AspNetCore.App is referenced in your application."; + + } + else + { + 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."; + } } public static string CouldNotStartStdoutFileRedirection(string file, IISDeploymentResult deploymentResult) diff --git a/src/Servers/IIS/IntegrationTesting.IIS/src/IISDeploymentParameters.cs b/src/Servers/IIS/IntegrationTesting.IIS/src/IISDeploymentParameters.cs index 04d4dfa7ce..b57a68eff1 100644 --- a/src/Servers/IIS/IntegrationTesting.IIS/src/IISDeploymentParameters.cs +++ b/src/Servers/IIS/IntegrationTesting.IIS/src/IISDeploymentParameters.cs @@ -47,6 +47,5 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS public IDictionary WebConfigBasedEnvironmentVariables { get; set; } = new Dictionary(); public IDictionary HandlerSettings { get; set; } = new Dictionary(); - } }