diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp index cb4893196f..bb42023988 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp @@ -64,6 +64,7 @@ HandlerResolver::LoadRequestHandlerAssembly(const IHttpApplication &pApplication pConfiguration.QueryProcessPath(), pApplication.GetApplicationPhysicalPath(), pConfiguration.QueryArguments(), + errorContext, options)); location = options->GetDotnetExeLocation(); diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj index 8816dafbda..5d9726d821 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj @@ -196,6 +196,7 @@ + diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/ErrorContext.h b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/ErrorContext.h new file mode 100644 index 0000000000..aa53a8249f --- /dev/null +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/ErrorContext.h @@ -0,0 +1,14 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +#pragma once + +struct ErrorContext +{ + // TODO consider adding HRESULT here + std::string detailedErrorContent; + USHORT statusCode; + USHORT subStatusCode; + std::string generalErrorType; + std::string errorReason; +}; diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.h b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.h index ccd8fff54f..526222322e 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.h @@ -28,16 +28,6 @@ typedef int(*hostfxr_set_runtime_property_value_fn)(void* host_context_handle, P typedef int(*hostfxr_run_app_fn)(void* host_context_handle); typedef int(*hostfxr_close_fn)(void* hostfxr_context_handle); -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/CommonLib/HostFxrResolutionResult.cpp b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolutionResult.cpp index 269aec7660..9a80749f2c 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolutionResult.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolutionResult.cpp @@ -23,6 +23,7 @@ HRESULT HostFxrResolutionResult::Create( _In_ const std::wstring& pcwzProcessPath, _In_ const std::wstring& pcwzApplicationPhysicalPath, _In_ const std::wstring& pcwzArguments, + _In_ ErrorContext& errorContext, _Out_ std::unique_ptr& ppWrapper) { std::filesystem::path knownDotnetLocation; @@ -42,7 +43,8 @@ HRESULT HostFxrResolutionResult::Create( pcwzArguments, hostFxrDllPath, knownDotnetLocation, - arguments); + arguments, + errorContext); LOG_INFOF(L"Parsed hostfxr options: dotnet location: '%ls' hostfxr path: '%ls' arguments:", knownDotnetLocation.c_str(), hostFxrDllPath.c_str()); for (size_t i = 0; i < arguments.size(); i++) diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolutionResult.h b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolutionResult.h index 25b502fc15..a0bbf17003 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolutionResult.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolutionResult.h @@ -10,6 +10,8 @@ #include #include +#include "ErrorContext.h" + class HostFxrResolutionResult { public: @@ -44,6 +46,7 @@ public: _In_ const std::wstring& pcwzProcessPath, _In_ const std::wstring& pcwzApplicationPhysicalPath, _In_ const std::wstring& pcwzArguments, + _In_ ErrorContext& errorContext, _Out_ std::unique_ptr& ppWrapper); private: diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp index e6bfdfb0c6..45e3699fad 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp @@ -21,7 +21,8 @@ HostFxrResolver::GetHostFxrParameters( const std::wstring &applicationArguments, fs::path &hostFxrDllPath, fs::path &dotnetExePath, - std::vector &arguments + std::vector &arguments, + ErrorContext& errorContext ) { LOG_INFOF(L"Resolving hostfxr parameters for application: '%ls' arguments: '%ls' path: '%ls'", @@ -93,7 +94,13 @@ HostFxrResolver::GetHostFxrParameters( LOG_INFOF(L"Checking application.dll at '%ls'", applicationDllPath.c_str()); if (!is_regular_file(applicationDllPath)) { - throw InvalidOperationException(format(L"Application .dll was not found at %s", applicationDllPath.c_str())); + errorContext.subStatusCode = 38; + errorContext.errorReason = "Application DLL not found. Confirm the application dll is present. Single-file deployments are not supported in IIS."; + errorContext.generalErrorType = "ANCM Application DLL Not Found"; + errorContext.detailedErrorContent = format("Application DLL was not found at %s.", to_multi_byte_string(applicationDllPath, CP_UTF8).c_str()); + throw InvalidOperationException( + format(L"Application DLL was not found at %s. Confirm the application dll is present. Single-file deployments are not supported in IIS.", + applicationDllPath.c_str())); } hostFxrDllPath = executablePath.parent_path() / "hostfxr.dll"; diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.h b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.h index 1ff9ac8d14..70f63fca6f 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.h @@ -9,6 +9,8 @@ #include #include +#include "ErrorContext.h" + #define READ_BUFFER_SIZE 4096 class HostFxrResolver @@ -23,7 +25,8 @@ public: const std::wstring &applicationArguments, std::filesystem::path &hostFxrDllPath, std::filesystem::path &dotnetExePath, - std::vector &arguments + std::vector &arguments, + ErrorContext& errorContext ); static diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLibTests/CommonLibTests.vcxproj b/src/Servers/IIS/AspNetCoreModuleV2/CommonLibTests/CommonLibTests.vcxproj index 46dd0a68c4..7268908ebd 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLibTests/CommonLibTests.vcxproj +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLibTests/CommonLibTests.vcxproj @@ -43,7 +43,6 @@ - @@ -187,4 +186,4 @@ true - + \ No newline at end of file diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLibTests/hostfxr_utility_tests.cpp b/src/Servers/IIS/AspNetCoreModuleV2/CommonLibTests/hostfxr_utility_tests.cpp deleted file mode 100644 index 31ddd86dc4..0000000000 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLibTests/hostfxr_utility_tests.cpp +++ /dev/null @@ -1,122 +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. - -#include "stdafx.h" -#include -#include -#include -#include "HostFxrResolver.h" -#include "Environment.h" - -TEST(ParseHostFxrArguments, BasicHostFxrArguments) -{ - std::vector bstrArray; - - HostFxrResolver::AppendArguments( - L"exec \"test.dll\"", // args - L"invalid", // physical path to application - bstrArray); // args array. - - EXPECT_EQ(2, bstrArray.size()); - ASSERT_STREQ(L"exec", bstrArray[0].c_str()); - ASSERT_STREQ(L"test.dll", bstrArray[1].c_str()); -} - -TEST(ParseHostFxrArguments, NoExecProvided) -{ - std::vector bstrArray; - - HostFxrResolver::AppendArguments( - L"test.dll", // args - L"ignored", // physical path to application - bstrArray); // args array. - - EXPECT_EQ(1, bstrArray.size()); - ASSERT_STREQ(L"test.dll", bstrArray[0].c_str()); -} - -TEST(ParseHostFxrArguments, ConvertDllToAbsolutePath) -{ - std::vector bstrArray; - // we need to use existing dll so let's use ntdll that we know exists everywhere - auto system32 = Environment::ExpandEnvironmentVariables(L"%WINDIR%\\System32"); - HostFxrResolver::AppendArguments( - L"exec \"ntdll.dll\"", // args - system32, // physical path to application - bstrArray, // args array. - true); // expandDllPaths - - EXPECT_EQ(2, bstrArray.size()); - ASSERT_STREQ(L"exec", bstrArray[0].c_str()); - ASSERT_STREQ((system32 + L"\\ntdll.dll").c_str(), bstrArray[1].c_str()); -} - -TEST(ParseHostFxrArguments, ProvideNoArgs_InvalidArgs) -{ - std::vector bstrArray; - std::filesystem::path struHostFxrDllLocation; - std::filesystem::path struExeLocation; - - EXPECT_THROW(HostFxrResolver::GetHostFxrParameters( - L"dotnet", // processPath - L"some\\path", // application physical path, ignored. - L"", //arguments - struHostFxrDllLocation, - struExeLocation, - bstrArray), // args array. - InvalidOperationException); -} - -TEST(GetAbsolutePathToDotnetFromProgramFiles, BackupWorks) -{ - STRU struAbsolutePathToDotnet; - BOOL fDotnetInProgramFiles; - BOOL is64Bit; - BOOL fIsWow64 = FALSE; - SYSTEM_INFO systemInfo; - IsWow64Process(GetCurrentProcess(), &fIsWow64); - if (fIsWow64) - { - is64Bit = FALSE; - } - else - { - GetNativeSystemInfo(&systemInfo); - is64Bit = systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64; - } - - if (is64Bit) - { - fDotnetInProgramFiles = std::filesystem::is_regular_file(L"C:/Program Files/dotnet/dotnet.exe"); - } - else - { - fDotnetInProgramFiles = std::filesystem::is_regular_file(L"C:/Program Files (x86)/dotnet/dotnet.exe"); - } - - auto dotnetPath = HostFxrResolver::GetAbsolutePathToDotnetFromProgramFiles(); - if (fDotnetInProgramFiles) - { - EXPECT_TRUE(dotnetPath.has_value()); - } - else - { - EXPECT_FALSE(dotnetPath.has_value()); - } -} - -TEST(GetHostFxrArguments, InvalidParams) -{ - std::vector bstrArray; - std::filesystem::path struHostFxrDllLocation; - std::filesystem::path struExeLocation; - - EXPECT_THROW(HostFxrResolver::GetHostFxrParameters( - L"bogus", // processPath - L"", // application physical path, ignored. - L"ignored", //arguments - struHostFxrDllLocation, - struExeLocation, - bstrArray), // args array. - InvalidOperationException); -} diff --git a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp index cbc741959d..5707e4cd77 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp @@ -195,6 +195,8 @@ IN_PROCESS_APPLICATION::ExecuteApplication() auto context = std::make_shared(); + ErrorContext errorContext; // unused + if (s_fMainCallback == nullptr) { THROW_IF_FAILED(HostFxrResolutionResult::Create( @@ -202,6 +204,7 @@ IN_PROCESS_APPLICATION::ExecuteApplication() m_pConfig->QueryProcessPath(), QueryApplicationPhysicalPath(), m_pConfig->QueryArguments(), + errorContext, hostFxrResolutionResult )); 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 62b9ea0d1f..11467d4424 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/StartupTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/StartupTests.cs @@ -365,6 +365,24 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.InProcess EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessFailedToFindNativeDependencies(deploymentResult), Logger); } + [ConditionalFact] + public async Task SingleExecutable_FailedToFindNativeDependencies() + { + var deploymentParameters = Fixture.GetBaseDeploymentParameters(Fixture.InProcessTestSite); + deploymentParameters.ApplicationType = ApplicationType.Standalone; + var deploymentResult = await DeployAsync(deploymentParameters); + + File.Delete(Path.Combine(deploymentResult.ContentRoot, "InProcessWebSite.dll")); + if (DeployerSelector.HasNewShim) + { + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult, "HTTP Error 500.38 - ANCM Application DLL Not Found"); + } + else + { + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult); + } + } + [ConditionalFact] public async Task TargedDifferenceSharedFramework_FailedToFindNativeDependenciesErrorInResponse() { diff --git a/src/Servers/IIS/IIS/test/IIS.Tests/MaxRequestBodySizeTests.cs b/src/Servers/IIS/IIS/test/IIS.Tests/MaxRequestBodySizeTests.cs index 1b34f9a371..2408a8efa2 100644 --- a/src/Servers/IIS/IIS/test/IIS.Tests/MaxRequestBodySizeTests.cs +++ b/src/Servers/IIS/IIS/test/IIS.Tests/MaxRequestBodySizeTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Diagnostics; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http.Features;