306 lines
10 KiB
C++
306 lines
10 KiB
C++
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
|
|
|
#include "HandlerResolver.h"
|
|
#include "exceptions.h"
|
|
#include "SRWExclusiveLock.h"
|
|
#include "applicationinfo.h"
|
|
#include "EventLog.h"
|
|
#include "hostfxr_utility.h"
|
|
#include "GlobalVersionUtility.h"
|
|
#include "HandleWrapper.h"
|
|
#include "file_utility.h"
|
|
#include "LoggingHelpers.h"
|
|
#include "resources.h"
|
|
|
|
const PCWSTR HandlerResolver::s_pwzAspnetcoreInProcessRequestHandlerName = L"aspnetcorev2_inprocess.dll";
|
|
const PCWSTR HandlerResolver::s_pwzAspnetcoreOutOfProcessRequestHandlerName = L"aspnetcorev2_outofprocess.dll";
|
|
|
|
HandlerResolver::HandlerResolver(HMODULE hModule, IHttpServer &pServer)
|
|
: m_hModule(hModule),
|
|
m_pServer(pServer),
|
|
m_loadedApplicationHostingModel(HOSTING_UNKNOWN)
|
|
{
|
|
InitializeSRWLock(&m_requestHandlerLoadLock);
|
|
}
|
|
|
|
HRESULT
|
|
HandlerResolver::LoadRequestHandlerAssembly(IHttpApplication &pApplication, ASPNETCORE_SHIM_CONFIG& pConfiguration, std::unique_ptr<ApplicationFactory>& pApplicationFactory)
|
|
{
|
|
HRESULT hr;
|
|
PCWSTR pstrHandlerDllName;
|
|
bool preventUnload;
|
|
if (pConfiguration.QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
|
|
{
|
|
preventUnload = false;
|
|
pstrHandlerDllName = s_pwzAspnetcoreInProcessRequestHandlerName;
|
|
}
|
|
else
|
|
{
|
|
// OutOfProcess handler is not able to handle unload correctly
|
|
// It has code running after application.Stop exits
|
|
preventUnload = true;
|
|
pstrHandlerDllName = s_pwzAspnetcoreOutOfProcessRequestHandlerName;
|
|
}
|
|
HandleWrapper<ModuleHandleTraits> hRequestHandlerDll;
|
|
std::wstring location;
|
|
std::wstring handlerDllPath;
|
|
// Try to see if RH is already loaded, use GetModuleHandleEx to increment ref count
|
|
if (!GetModuleHandleEx(0, pstrHandlerDllName, &hRequestHandlerDll))
|
|
{
|
|
if (pConfiguration.QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
|
|
{
|
|
std::unique_ptr<HOSTFXR_OPTIONS> options;
|
|
std::unique_ptr<IOutputManager> outputManager;
|
|
|
|
RETURN_IF_FAILED(HOSTFXR_OPTIONS::Create(
|
|
NULL,
|
|
pConfiguration.QueryProcessPath().c_str(),
|
|
pApplication.GetApplicationPhysicalPath(),
|
|
pConfiguration.QueryArguments().c_str(),
|
|
options));
|
|
|
|
location = options->GetExeLocation();
|
|
|
|
RETURN_IF_FAILED(LoggingHelpers::CreateLoggingProvider(
|
|
pConfiguration.QueryStdoutLogEnabled(),
|
|
!m_pServer.IsCommandLineLaunch(),
|
|
pConfiguration.QueryStdoutLogFile()->QueryStr(),
|
|
pApplication.GetApplicationPhysicalPath(),
|
|
outputManager));
|
|
|
|
outputManager->Start();
|
|
|
|
hr = FindNativeAssemblyFromHostfxr(*options.get(), pstrHandlerDllName, handlerDllPath);
|
|
outputManager->Stop();
|
|
|
|
if (FAILED(hr) && m_hHostFxrDll != NULL)
|
|
{
|
|
STRA content;
|
|
STRU struStdMsg;
|
|
|
|
outputManager->GetStdOutContent(&content);
|
|
if (content.QueryCCH() > 0)
|
|
{
|
|
struStdMsg.CopyA(content.QueryStr());
|
|
}
|
|
|
|
EventLog::Error(
|
|
ASPNETCORE_EVENT_GENERAL_ERROR,
|
|
ASPNETCORE_EVENT_INPROCESS_RH_ERROR_MSG,
|
|
handlerDllPath.empty()? s_pwzAspnetcoreInProcessRequestHandlerName : handlerDllPath.c_str(),
|
|
struStdMsg.QueryStr());
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (FAILED_LOG(hr = FindNativeAssemblyFromGlobalLocation(pConfiguration, pstrHandlerDllName, handlerDllPath)))
|
|
{
|
|
EventLog::Error(
|
|
ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING,
|
|
ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG,
|
|
handlerDllPath.empty() ? s_pwzAspnetcoreOutOfProcessRequestHandlerName : handlerDllPath.c_str());
|
|
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
LOG_INFOF("Loading request handler: %S", handlerDllPath.c_str());
|
|
|
|
hRequestHandlerDll = LoadLibrary(handlerDllPath.c_str());
|
|
if (preventUnload)
|
|
{
|
|
// Pin module in memory
|
|
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN, pstrHandlerDllName, &hRequestHandlerDll);
|
|
}
|
|
RETURN_LAST_ERROR_IF_NULL(hRequestHandlerDll);
|
|
}
|
|
|
|
auto pfnAspNetCoreCreateApplication = reinterpret_cast<PFN_ASPNETCORE_CREATE_APPLICATION>(GetProcAddress(hRequestHandlerDll, "CreateApplication"));
|
|
RETURN_LAST_ERROR_IF_NULL(pfnAspNetCoreCreateApplication);
|
|
|
|
pApplicationFactory = std::make_unique<ApplicationFactory>(hRequestHandlerDll.release(), location, pfnAspNetCoreCreateApplication);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
HandlerResolver::GetApplicationFactory(IHttpApplication &pApplication, std::unique_ptr<ApplicationFactory>& pApplicationFactory)
|
|
{
|
|
try
|
|
{
|
|
ASPNETCORE_SHIM_CONFIG pConfiguration;
|
|
RETURN_IF_FAILED(pConfiguration.Populate(&m_pServer, &pApplication));
|
|
|
|
SRWExclusiveLock lock(m_requestHandlerLoadLock);
|
|
if (m_loadedApplicationHostingModel != HOSTING_UNKNOWN)
|
|
{
|
|
// Mixed hosting models
|
|
if (m_loadedApplicationHostingModel != pConfiguration.QueryHostingModel())
|
|
{
|
|
EventLog::Error(
|
|
ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR,
|
|
ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG,
|
|
pApplication.GetApplicationId(),
|
|
pConfiguration.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;
|
|
}
|
|
}
|
|
|
|
m_loadedApplicationHostingModel = pConfiguration.QueryHostingModel();
|
|
m_loadedApplicationId = pApplication.GetApplicationId();
|
|
RETURN_IF_FAILED(LoadRequestHandlerAssembly(pApplication, pConfiguration, pApplicationFactory));
|
|
|
|
}
|
|
CATCH_RETURN();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void HandlerResolver::ResetHostingModel()
|
|
{
|
|
SRWExclusiveLock lock(m_requestHandlerLoadLock);
|
|
|
|
m_loadedApplicationHostingModel = APP_HOSTING_MODEL::HOSTING_UNKNOWN;
|
|
m_loadedApplicationId.resize(0);
|
|
}
|
|
|
|
HRESULT
|
|
HandlerResolver::FindNativeAssemblyFromGlobalLocation(
|
|
ASPNETCORE_SHIM_CONFIG& pConfiguration,
|
|
PCWSTR pstrHandlerDllName,
|
|
std::wstring& handlerDllPath
|
|
)
|
|
{
|
|
try
|
|
{
|
|
std::wstring modulePath = GlobalVersionUtility::GetModuleName(m_hModule);
|
|
|
|
modulePath = GlobalVersionUtility::RemoveFileNameFromFolderPath(modulePath);
|
|
|
|
handlerDllPath = GlobalVersionUtility::GetGlobalRequestHandlerPath(modulePath.c_str(),
|
|
pConfiguration.QueryHandlerVersion().c_str(),
|
|
pstrHandlerDllName
|
|
);
|
|
}
|
|
catch (...)
|
|
{
|
|
EventLog::Info(
|
|
ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING,
|
|
ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG,
|
|
pstrHandlerDllName);
|
|
|
|
return OBSERVE_CAUGHT_EXCEPTION();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// Tries to find aspnetcorerh.dll from the application
|
|
// Calls into hostfxr.dll to find it.
|
|
// Will leave hostfxr.dll loaded as it will be used again to call hostfxr_main.
|
|
//
|
|
HRESULT
|
|
HandlerResolver::FindNativeAssemblyFromHostfxr(
|
|
HOSTFXR_OPTIONS& hostfxrOptions,
|
|
PCWSTR libraryName,
|
|
std::wstring& handlerDllPath
|
|
)
|
|
{
|
|
std::wstring struNativeSearchPaths;
|
|
size_t intIndex;
|
|
size_t intPrevIndex = 0;
|
|
DWORD dwBufferSize = s_initialGetNativeSearchDirectoriesBufferSize;
|
|
DWORD dwRequiredBufferSize = 0;
|
|
|
|
RETURN_LAST_ERROR_IF_NULL(m_hHostFxrDll = LoadLibraryW(hostfxrOptions.GetHostFxrLocation()));
|
|
|
|
auto pFnHostFxrSearchDirectories = reinterpret_cast<hostfxr_get_native_search_directories_fn>(GetProcAddress(m_hHostFxrDll, "hostfxr_get_native_search_directories"));
|
|
if (pFnHostFxrSearchDirectories == nullptr)
|
|
{
|
|
EventLog::Error(
|
|
ASPNETCORE_EVENT_GENERAL_ERROR,
|
|
ASPNETCORE_EVENT_HOSTFXR_DLL_INVALID_VERSION_MSG,
|
|
hostfxrOptions.GetHostFxrLocation()
|
|
);
|
|
RETURN_IF_FAILED(E_FAIL);
|
|
}
|
|
|
|
RETURN_LAST_ERROR_IF_NULL(pFnHostFxrSearchDirectories);
|
|
struNativeSearchPaths.resize(dwBufferSize);
|
|
|
|
while (TRUE)
|
|
{
|
|
const auto intHostFxrExitCode = pFnHostFxrSearchDirectories(
|
|
hostfxrOptions.GetArgc(),
|
|
hostfxrOptions.GetArgv(),
|
|
struNativeSearchPaths.data(),
|
|
dwBufferSize,
|
|
&dwRequiredBufferSize
|
|
);
|
|
|
|
if (intHostFxrExitCode == 0)
|
|
{
|
|
break;
|
|
}
|
|
else if (dwRequiredBufferSize > dwBufferSize)
|
|
{
|
|
dwBufferSize = dwRequiredBufferSize + 1; // for null terminator
|
|
|
|
struNativeSearchPaths.resize(dwBufferSize);
|
|
}
|
|
else
|
|
{
|
|
// Log "Error finding native search directories from aspnetcore application.
|
|
return E_UNEXPECTED;
|
|
}
|
|
}
|
|
|
|
struNativeSearchPaths.resize(struNativeSearchPaths.find(L'\0'));
|
|
|
|
auto fFound = FALSE;
|
|
|
|
// The native search directories are semicolon delimited.
|
|
// Split on semicolons, append aspnetcorerh.dll, and check if the file exists.
|
|
while ((intIndex = struNativeSearchPaths.find(L';', intPrevIndex)) != std::wstring::npos)
|
|
{
|
|
auto path = struNativeSearchPaths.substr(intPrevIndex, intIndex - intPrevIndex);
|
|
|
|
if (!path.empty() && !(path[path.length() - 1] == L'\\'))
|
|
{
|
|
path.append(L"\\");
|
|
}
|
|
|
|
path.append(libraryName);
|
|
|
|
if (std::filesystem::is_regular_file(path))
|
|
{
|
|
handlerDllPath = path;
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
|
|
intPrevIndex = intIndex + 1;
|
|
}
|
|
|
|
if (!fFound)
|
|
{
|
|
return HRESULT_FROM_WIN32(ERROR_DLL_NOT_FOUND);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|