Cleanup application manager (#1250)
This commit is contained in:
parent
e23d9cb4ac
commit
e26231b613
|
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <string>
|
||||||
|
#include "iapplication.h"
|
||||||
|
#include "HandleWrapper.h"
|
||||||
|
|
||||||
|
typedef
|
||||||
|
HRESULT
|
||||||
|
(WINAPI * PFN_ASPNETCORE_CREATE_APPLICATION)(
|
||||||
|
_In_ IHttpServer *pServer,
|
||||||
|
_In_ IHttpApplication *pHttpApplication,
|
||||||
|
_In_ APPLICATION_PARAMETER *pParameters,
|
||||||
|
_In_ DWORD nParameters,
|
||||||
|
_Out_ IAPPLICATION **pApplication
|
||||||
|
);
|
||||||
|
|
||||||
|
class ApplicationFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ApplicationFactory(HMODULE hRequestHandlerDll, std::wstring location, PFN_ASPNETCORE_CREATE_APPLICATION pfnAspNetCoreCreateApplication):
|
||||||
|
m_pfnAspNetCoreCreateApplication(pfnAspNetCoreCreateApplication),
|
||||||
|
m_location(location),
|
||||||
|
m_hRequestHandlerDll(hRequestHandlerDll)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT Execute(
|
||||||
|
_In_ IHttpServer *pServer,
|
||||||
|
_In_ IHttpApplication *pHttpApplication,
|
||||||
|
_Out_ IAPPLICATION **pApplication) const
|
||||||
|
{
|
||||||
|
std::array<APPLICATION_PARAMETER, 1> parameters {
|
||||||
|
{"InProcessExeLocation", reinterpret_cast<const void*>(m_location.data())}
|
||||||
|
};
|
||||||
|
return m_pfnAspNetCoreCreateApplication(pServer, pHttpApplication, parameters.data(), static_cast<DWORD>(parameters.size()), pApplication);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PFN_ASPNETCORE_CREATE_APPLICATION m_pfnAspNetCoreCreateApplication;
|
||||||
|
std::wstring m_location;
|
||||||
|
HandleWrapper<ModuleHandleTraits> m_hRequestHandlerDll;
|
||||||
|
};
|
||||||
|
|
@ -227,6 +227,7 @@
|
||||||
</ResourceCompile>
|
</ResourceCompile>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="ApplicationFactory.h" />
|
||||||
<ClInclude Include="applicationinfo.h" />
|
<ClInclude Include="applicationinfo.h" />
|
||||||
<ClInclude Include="AppOfflineApplication.h" />
|
<ClInclude Include="AppOfflineApplication.h" />
|
||||||
<ClInclude Include="AppOfflineHandler.h" />
|
<ClInclude Include="AppOfflineHandler.h" />
|
||||||
|
|
|
||||||
|
|
@ -19,56 +19,59 @@ const PCWSTR HandlerResolver::s_pwzAspnetcoreOutOfProcessRequestHandlerName = L"
|
||||||
HandlerResolver::HandlerResolver(HMODULE hModule, IHttpServer &pServer)
|
HandlerResolver::HandlerResolver(HMODULE hModule, IHttpServer &pServer)
|
||||||
: m_hModule(hModule),
|
: m_hModule(hModule),
|
||||||
m_pServer(pServer),
|
m_pServer(pServer),
|
||||||
m_fAspnetcoreRHLoadResult(S_FALSE),
|
m_loadedApplicationHostingModel(HOSTING_UNKNOWN)
|
||||||
m_loadedApplicationHostingModel(HOSTING_UNKNOWN),
|
|
||||||
m_hRequestHandlerDll(nullptr),
|
|
||||||
m_pfnAspNetCoreCreateApplication(nullptr)
|
|
||||||
{
|
{
|
||||||
InitializeSRWLock(&m_requestHandlerLoadLock);
|
InitializeSRWLock(&m_requestHandlerLoadLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
HandlerResolver::LoadRequestHandlerAssembly(IHttpApplication &pApplication, STRU& location, ASPNETCORE_SHIM_CONFIG * pConfiguration)
|
HandlerResolver::LoadRequestHandlerAssembly(IHttpApplication &pApplication, ASPNETCORE_SHIM_CONFIG& pConfiguration, std::unique_ptr<ApplicationFactory>& pApplicationFactory)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
STACK_STRU(struFileName, MAX_PATH);
|
|
||||||
PCWSTR pstrHandlerDllName;
|
PCWSTR pstrHandlerDllName;
|
||||||
if (pConfiguration->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
|
bool preventUnload;
|
||||||
|
if (pConfiguration.QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
|
||||||
{
|
{
|
||||||
|
preventUnload = false;
|
||||||
pstrHandlerDllName = s_pwzAspnetcoreInProcessRequestHandlerName;
|
pstrHandlerDllName = s_pwzAspnetcoreInProcessRequestHandlerName;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// OutOfProcess handler is not able to handle unload correctly
|
||||||
|
// It has code running after application.Stop exits
|
||||||
|
preventUnload = true;
|
||||||
pstrHandlerDllName = s_pwzAspnetcoreOutOfProcessRequestHandlerName;
|
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
|
// Try to see if RH is already loaded, use GetModuleHandleEx to increment ref count
|
||||||
if (!GetModuleHandleEx(0, pstrHandlerDllName, &m_hRequestHandlerDll))
|
if (!GetModuleHandleEx(0, pstrHandlerDllName, &hRequestHandlerDll))
|
||||||
{
|
{
|
||||||
if (pConfiguration->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
|
if (pConfiguration.QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
|
||||||
{
|
{
|
||||||
std::unique_ptr<HOSTFXR_OPTIONS> options;
|
std::unique_ptr<HOSTFXR_OPTIONS> options;
|
||||||
std::unique_ptr<IOutputManager> outputManager;
|
std::unique_ptr<IOutputManager> outputManager;
|
||||||
|
|
||||||
RETURN_IF_FAILED(HOSTFXR_OPTIONS::Create(
|
RETURN_IF_FAILED(HOSTFXR_OPTIONS::Create(
|
||||||
NULL,
|
NULL,
|
||||||
pConfiguration->QueryProcessPath()->QueryStr(),
|
pConfiguration.QueryProcessPath().c_str(),
|
||||||
pApplication.GetApplicationPhysicalPath(),
|
pApplication.GetApplicationPhysicalPath(),
|
||||||
pConfiguration->QueryArguments()->QueryStr(),
|
pConfiguration.QueryArguments().c_str(),
|
||||||
options));
|
options));
|
||||||
|
|
||||||
RETURN_IF_FAILED(location.Copy(options->GetExeLocation()));
|
location = options->GetExeLocation();
|
||||||
|
|
||||||
RETURN_IF_FAILED(LoggingHelpers::CreateLoggingProvider(
|
RETURN_IF_FAILED(LoggingHelpers::CreateLoggingProvider(
|
||||||
pConfiguration->QueryStdoutLogEnabled(),
|
pConfiguration.QueryStdoutLogEnabled(),
|
||||||
!m_pServer.IsCommandLineLaunch(),
|
!m_pServer.IsCommandLineLaunch(),
|
||||||
pConfiguration->QueryStdoutLogFile()->QueryStr(),
|
pConfiguration.QueryStdoutLogFile()->QueryStr(),
|
||||||
pApplication.GetApplicationPhysicalPath(),
|
pApplication.GetApplicationPhysicalPath(),
|
||||||
outputManager));
|
outputManager));
|
||||||
|
|
||||||
outputManager->Start();
|
outputManager->Start();
|
||||||
|
|
||||||
hr = FindNativeAssemblyFromHostfxr(options.get(), pstrHandlerDllName, &struFileName);
|
hr = FindNativeAssemblyFromHostfxr(*options.get(), pstrHandlerDllName, handlerDllPath);
|
||||||
outputManager->Stop();
|
outputManager->Stop();
|
||||||
|
|
||||||
if (FAILED(hr) && m_hHostFxrDll != NULL)
|
if (FAILED(hr) && m_hHostFxrDll != NULL)
|
||||||
|
|
@ -85,85 +88,99 @@ HandlerResolver::LoadRequestHandlerAssembly(IHttpApplication &pApplication, STRU
|
||||||
EventLog::Error(
|
EventLog::Error(
|
||||||
ASPNETCORE_EVENT_GENERAL_ERROR,
|
ASPNETCORE_EVENT_GENERAL_ERROR,
|
||||||
ASPNETCORE_EVENT_INPROCESS_RH_ERROR_MSG,
|
ASPNETCORE_EVENT_INPROCESS_RH_ERROR_MSG,
|
||||||
struFileName.IsEmpty() ? s_pwzAspnetcoreInProcessRequestHandlerName : struFileName.QueryStr(),
|
handlerDllPath.empty()? s_pwzAspnetcoreInProcessRequestHandlerName : handlerDllPath.c_str(),
|
||||||
struStdMsg.QueryStr());
|
struStdMsg.QueryStr());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (FAILED_LOG(hr = FindNativeAssemblyFromGlobalLocation(pConfiguration, pstrHandlerDllName, &struFileName)))
|
if (FAILED_LOG(hr = FindNativeAssemblyFromGlobalLocation(pConfiguration, pstrHandlerDllName, handlerDllPath)))
|
||||||
{
|
{
|
||||||
EventLog::Error(
|
EventLog::Error(
|
||||||
ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING,
|
ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING,
|
||||||
ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG,
|
ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG,
|
||||||
struFileName.IsEmpty() ? s_pwzAspnetcoreOutOfProcessRequestHandlerName : struFileName.QueryStr());
|
handlerDllPath.empty() ? s_pwzAspnetcoreOutOfProcessRequestHandlerName : handlerDllPath.c_str());
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFOF("Loading request handler: %S", struFileName.QueryStr());
|
LOG_INFOF("Loading request handler: %S", handlerDllPath.c_str());
|
||||||
|
|
||||||
m_hRequestHandlerDll = LoadLibraryW(struFileName.QueryStr());
|
hRequestHandlerDll = LoadLibrary(handlerDllPath.c_str());
|
||||||
RETURN_LAST_ERROR_IF_NULL(m_hRequestHandlerDll);
|
if (preventUnload)
|
||||||
|
{
|
||||||
|
// Pin module in memory
|
||||||
|
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN, pstrHandlerDllName, &hRequestHandlerDll);
|
||||||
|
}
|
||||||
|
RETURN_LAST_ERROR_IF_NULL(hRequestHandlerDll);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pfnAspNetCoreCreateApplication = reinterpret_cast<PFN_ASPNETCORE_CREATE_APPLICATION>(GetProcAddress(m_hRequestHandlerDll, "CreateApplication"));
|
auto pfnAspNetCoreCreateApplication = reinterpret_cast<PFN_ASPNETCORE_CREATE_APPLICATION>(GetProcAddress(hRequestHandlerDll, "CreateApplication"));
|
||||||
|
RETURN_LAST_ERROR_IF_NULL(pfnAspNetCoreCreateApplication);
|
||||||
RETURN_LAST_ERROR_IF_NULL(m_pfnAspNetCoreCreateApplication);
|
|
||||||
|
|
||||||
|
pApplicationFactory = std::make_unique<ApplicationFactory>(hRequestHandlerDll.release(), location, pfnAspNetCoreCreateApplication);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
HandlerResolver::GetApplicationFactory(IHttpApplication &pApplication, STRU& location, PFN_ASPNETCORE_CREATE_APPLICATION * pfnCreateApplication)
|
HandlerResolver::GetApplicationFactory(IHttpApplication &pApplication, std::unique_ptr<ApplicationFactory>& pApplicationFactory)
|
||||||
{
|
{
|
||||||
ASPNETCORE_SHIM_CONFIG pConfiguration;
|
try
|
||||||
RETURN_IF_FAILED(pConfiguration.Populate(&m_pServer, &pApplication));
|
|
||||||
|
|
||||||
if (m_fAspnetcoreRHLoadResult == S_FALSE)
|
|
||||||
{
|
{
|
||||||
|
ASPNETCORE_SHIM_CONFIG pConfiguration;
|
||||||
|
RETURN_IF_FAILED(pConfiguration.Populate(&m_pServer, &pApplication));
|
||||||
|
|
||||||
SRWExclusiveLock lock(m_requestHandlerLoadLock);
|
SRWExclusiveLock lock(m_requestHandlerLoadLock);
|
||||||
if (m_fAspnetcoreRHLoadResult == S_FALSE)
|
if (m_loadedApplicationHostingModel != HOSTING_UNKNOWN)
|
||||||
{
|
{
|
||||||
m_loadedApplicationHostingModel = pConfiguration.QueryHostingModel();
|
// Mixed hosting models
|
||||||
m_loadedApplicationId = pApplication.GetApplicationId();
|
if (m_loadedApplicationHostingModel != pConfiguration.QueryHostingModel())
|
||||||
LOG_IF_FAILED(m_fAspnetcoreRHLoadResult = LoadRequestHandlerAssembly(pApplication, location, &pConfiguration));
|
{
|
||||||
|
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();
|
||||||
|
|
||||||
// Mixed hosting models
|
return S_OK;
|
||||||
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;
|
void HandlerResolver::ResetHostingModel()
|
||||||
}
|
{
|
||||||
// Multiple in-process apps
|
SRWExclusiveLock lock(m_requestHandlerLoadLock);
|
||||||
else 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 = APP_HOSTING_MODEL::HOSTING_UNKNOWN;
|
||||||
}
|
m_loadedApplicationId.resize(0);
|
||||||
|
|
||||||
*pfnCreateApplication = m_pfnAspNetCoreCreateApplication;
|
|
||||||
return m_fAspnetcoreRHLoadResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
HandlerResolver::FindNativeAssemblyFromGlobalLocation(
|
HandlerResolver::FindNativeAssemblyFromGlobalLocation(
|
||||||
ASPNETCORE_SHIM_CONFIG * pConfiguration,
|
ASPNETCORE_SHIM_CONFIG& pConfiguration,
|
||||||
PCWSTR pstrHandlerDllName,
|
PCWSTR pstrHandlerDllName,
|
||||||
STRU* struFilename
|
std::wstring& handlerDllPath
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
@ -172,12 +189,10 @@ HandlerResolver::FindNativeAssemblyFromGlobalLocation(
|
||||||
|
|
||||||
modulePath = GlobalVersionUtility::RemoveFileNameFromFolderPath(modulePath);
|
modulePath = GlobalVersionUtility::RemoveFileNameFromFolderPath(modulePath);
|
||||||
|
|
||||||
std::wstring retval = GlobalVersionUtility::GetGlobalRequestHandlerPath(modulePath.c_str(),
|
handlerDllPath = GlobalVersionUtility::GetGlobalRequestHandlerPath(modulePath.c_str(),
|
||||||
pConfiguration->QueryHandlerVersion()->QueryStr(),
|
pConfiguration.QueryHandlerVersion().c_str(),
|
||||||
pstrHandlerDllName
|
pstrHandlerDllName
|
||||||
);
|
);
|
||||||
|
|
||||||
RETURN_IF_FAILED(struFilename->Copy(retval.c_str()));
|
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
|
@ -199,25 +214,18 @@ HandlerResolver::FindNativeAssemblyFromGlobalLocation(
|
||||||
//
|
//
|
||||||
HRESULT
|
HRESULT
|
||||||
HandlerResolver::FindNativeAssemblyFromHostfxr(
|
HandlerResolver::FindNativeAssemblyFromHostfxr(
|
||||||
HOSTFXR_OPTIONS* hostfxrOptions,
|
HOSTFXR_OPTIONS& hostfxrOptions,
|
||||||
PCWSTR libraryName,
|
PCWSTR libraryName,
|
||||||
STRU* struFilename
|
std::wstring& handlerDllPath
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
STRU struApplicationFullPath;
|
std::wstring struNativeSearchPaths;
|
||||||
STRU struNativeSearchPaths;
|
size_t intIndex;
|
||||||
STRU struNativeDllLocation;
|
size_t intPrevIndex = 0;
|
||||||
INT intIndex = -1;
|
DWORD dwBufferSize = s_initialGetNativeSearchDirectoriesBufferSize;
|
||||||
INT intPrevIndex = 0;
|
DWORD dwRequiredBufferSize = 0;
|
||||||
BOOL fFound = FALSE;
|
|
||||||
DWORD dwBufferSize = 1024 * 10;
|
|
||||||
DWORD dwRequiredBufferSize = 0;
|
|
||||||
STRA output;
|
|
||||||
|
|
||||||
|
RETURN_LAST_ERROR_IF_NULL(m_hHostFxrDll = LoadLibraryW(hostfxrOptions.GetHostFxrLocation()));
|
||||||
DBG_ASSERT(struFilename != NULL);
|
|
||||||
|
|
||||||
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"));
|
auto pFnHostFxrSearchDirectories = reinterpret_cast<hostfxr_get_native_search_directories_fn>(GetProcAddress(m_hHostFxrDll, "hostfxr_get_native_search_directories"));
|
||||||
if (pFnHostFxrSearchDirectories == nullptr)
|
if (pFnHostFxrSearchDirectories == nullptr)
|
||||||
|
|
@ -225,20 +233,20 @@ HandlerResolver::FindNativeAssemblyFromHostfxr(
|
||||||
EventLog::Error(
|
EventLog::Error(
|
||||||
ASPNETCORE_EVENT_GENERAL_ERROR,
|
ASPNETCORE_EVENT_GENERAL_ERROR,
|
||||||
ASPNETCORE_EVENT_HOSTFXR_DLL_INVALID_VERSION_MSG,
|
ASPNETCORE_EVENT_HOSTFXR_DLL_INVALID_VERSION_MSG,
|
||||||
hostfxrOptions->GetHostFxrLocation()
|
hostfxrOptions.GetHostFxrLocation()
|
||||||
);
|
);
|
||||||
RETURN_IF_FAILED(E_FAIL);
|
RETURN_IF_FAILED(E_FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_LAST_ERROR_IF_NULL(pFnHostFxrSearchDirectories);
|
RETURN_LAST_ERROR_IF_NULL(pFnHostFxrSearchDirectories);
|
||||||
RETURN_IF_FAILED(struNativeSearchPaths.Resize(dwBufferSize));
|
struNativeSearchPaths.resize(dwBufferSize);
|
||||||
|
|
||||||
while (TRUE)
|
while (TRUE)
|
||||||
{
|
{
|
||||||
auto intHostFxrExitCode = pFnHostFxrSearchDirectories(
|
const auto intHostFxrExitCode = pFnHostFxrSearchDirectories(
|
||||||
hostfxrOptions->GetArgc(),
|
hostfxrOptions.GetArgc(),
|
||||||
hostfxrOptions->GetArgv(),
|
hostfxrOptions.GetArgv(),
|
||||||
struNativeSearchPaths.QueryStr(),
|
struNativeSearchPaths.data(),
|
||||||
dwBufferSize,
|
dwBufferSize,
|
||||||
&dwRequiredBufferSize
|
&dwRequiredBufferSize
|
||||||
);
|
);
|
||||||
|
|
@ -251,7 +259,7 @@ HandlerResolver::FindNativeAssemblyFromHostfxr(
|
||||||
{
|
{
|
||||||
dwBufferSize = dwRequiredBufferSize + 1; // for null terminator
|
dwBufferSize = dwRequiredBufferSize + 1; // for null terminator
|
||||||
|
|
||||||
RETURN_IF_FAILED(struNativeSearchPaths.Resize(dwBufferSize));
|
struNativeSearchPaths.resize(dwBufferSize);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -260,26 +268,26 @@ HandlerResolver::FindNativeAssemblyFromHostfxr(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_IF_FAILED(struNativeSearchPaths.SyncWithBuffer());
|
struNativeSearchPaths.resize(struNativeSearchPaths.find(L'\0'));
|
||||||
|
|
||||||
fFound = FALSE;
|
auto fFound = FALSE;
|
||||||
|
|
||||||
// The native search directories are semicolon delimited.
|
// The native search directories are semicolon delimited.
|
||||||
// Split on semicolons, append aspnetcorerh.dll, and check if the file exists.
|
// Split on semicolons, append aspnetcorerh.dll, and check if the file exists.
|
||||||
while ((intIndex = struNativeSearchPaths.IndexOf(L";", intPrevIndex)) != -1)
|
while ((intIndex = struNativeSearchPaths.find(L';', intPrevIndex)) != std::wstring::npos)
|
||||||
{
|
{
|
||||||
RETURN_IF_FAILED(struNativeDllLocation.Copy(&struNativeSearchPaths.QueryStr()[intPrevIndex], intIndex - intPrevIndex));
|
auto path = struNativeSearchPaths.substr(intPrevIndex, intIndex - intPrevIndex);
|
||||||
|
|
||||||
if (!struNativeDllLocation.EndsWith(L"\\"))
|
if (!path.empty() && !(path[path.length() - 1] == L'\\'))
|
||||||
{
|
{
|
||||||
RETURN_IF_FAILED(struNativeDllLocation.Append(L"\\"));
|
path.append(L"\\");
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_IF_FAILED(struNativeDllLocation.Append(libraryName));
|
path.append(libraryName);
|
||||||
|
|
||||||
if (FILE_UTILITY::CheckIfFileExists(struNativeDllLocation.QueryStr()))
|
if (std::filesystem::is_regular_file(path))
|
||||||
{
|
{
|
||||||
RETURN_IF_FAILED(struFilename->Copy(struNativeDllLocation));
|
handlerDllPath = path;
|
||||||
fFound = TRUE;
|
fFound = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,47 +3,35 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "aspnetcore_shim_config.h"
|
#include "aspnetcore_shim_config.h"
|
||||||
#include "hostfxroptions.h"
|
|
||||||
#include <memory>
|
|
||||||
#include "iapplication.h"
|
|
||||||
#include <string>
|
|
||||||
#include "HandleWrapper.h"
|
|
||||||
|
|
||||||
typedef
|
#include <memory>
|
||||||
HRESULT
|
#include <string>
|
||||||
(WINAPI * PFN_ASPNETCORE_CREATE_APPLICATION)(
|
#include "hostfxroptions.h"
|
||||||
_In_ IHttpServer *pServer,
|
#include "HandleWrapper.h"
|
||||||
_In_ IHttpApplication *pHttpApplication,
|
#include "ApplicationFactory.h"
|
||||||
_In_ APPLICATION_PARAMETER *pParameters,
|
|
||||||
_In_ DWORD nParameters,
|
|
||||||
_Out_ IAPPLICATION **pApplication
|
|
||||||
);
|
|
||||||
|
|
||||||
class HandlerResolver
|
class HandlerResolver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HandlerResolver(HMODULE hModule, IHttpServer &pServer);
|
HandlerResolver(HMODULE hModule, IHttpServer &pServer);
|
||||||
HRESULT GetApplicationFactory(IHttpApplication &pApplication, STRU& location, PFN_ASPNETCORE_CREATE_APPLICATION *pfnCreateApplication);
|
HRESULT GetApplicationFactory(IHttpApplication &pApplication, std::unique_ptr<ApplicationFactory>& pApplicationFactory);
|
||||||
|
void ResetHostingModel();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HRESULT LoadRequestHandlerAssembly(IHttpApplication &pApplication,STRU& location, ASPNETCORE_SHIM_CONFIG * pConfiguration);
|
HRESULT LoadRequestHandlerAssembly(IHttpApplication &pApplication, ASPNETCORE_SHIM_CONFIG& pConfiguration, std::unique_ptr<ApplicationFactory>& pApplicationFactory);
|
||||||
HRESULT FindNativeAssemblyFromGlobalLocation(ASPNETCORE_SHIM_CONFIG * pConfiguration, PCWSTR libraryName, STRU* location);
|
HRESULT FindNativeAssemblyFromGlobalLocation(ASPNETCORE_SHIM_CONFIG& pConfiguration, PCWSTR libraryName, std::wstring& handlerDllPath);
|
||||||
HRESULT FindNativeAssemblyFromHostfxr(HOSTFXR_OPTIONS* hostfxrOptions, PCWSTR libraryName, STRU* location);
|
HRESULT FindNativeAssemblyFromHostfxr(HOSTFXR_OPTIONS& hostfxrOptions, PCWSTR libraryName, std::wstring& handlerDllPath);
|
||||||
|
|
||||||
HMODULE m_hModule;
|
HMODULE m_hModule;
|
||||||
IHttpServer &m_pServer;
|
IHttpServer &m_pServer;
|
||||||
|
|
||||||
SRWLOCK m_requestHandlerLoadLock {};
|
SRWLOCK m_requestHandlerLoadLock {};
|
||||||
// S_FALSE - not loaded, S_OK - loaded, everything else - error
|
|
||||||
HRESULT m_fAspnetcoreRHLoadResult;
|
|
||||||
std::wstring m_loadedApplicationId;
|
std::wstring m_loadedApplicationId;
|
||||||
APP_HOSTING_MODEL m_loadedApplicationHostingModel;
|
APP_HOSTING_MODEL m_loadedApplicationHostingModel;
|
||||||
HandleWrapper<ModuleHandleTraits> m_hRequestHandlerDll;
|
|
||||||
HandleWrapper<ModuleHandleTraits> m_hHostFxrDll;
|
HandleWrapper<ModuleHandleTraits> m_hHostFxrDll;
|
||||||
|
|
||||||
PFN_ASPNETCORE_CREATE_APPLICATION m_pfnAspNetCoreCreateApplication;
|
|
||||||
|
|
||||||
static const PCWSTR s_pwzAspnetcoreInProcessRequestHandlerName;
|
static const PCWSTR s_pwzAspnetcoreInProcessRequestHandlerName;
|
||||||
static const PCWSTR s_pwzAspnetcoreOutOfProcessRequestHandlerName;
|
static const PCWSTR s_pwzAspnetcoreOutOfProcessRequestHandlerName;
|
||||||
|
static const DWORD s_initialGetNativeSearchDirectoriesBufferSize = MAX_PATH * 4;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
#include "applicationinfo.h"
|
#include "applicationinfo.h"
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include "proxymodule.h"
|
#include "proxymodule.h"
|
||||||
#include "hostfxr_utility.h"
|
#include "hostfxr_utility.h"
|
||||||
#include "debugutil.h"
|
#include "debugutil.h"
|
||||||
|
|
@ -11,28 +10,14 @@
|
||||||
#include "SRWExclusiveLock.h"
|
#include "SRWExclusiveLock.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "EventLog.h"
|
#include "EventLog.h"
|
||||||
#include "HandleWrapper.h"
|
|
||||||
#include "ServerErrorApplication.h"
|
#include "ServerErrorApplication.h"
|
||||||
#include "AppOfflineApplication.h"
|
#include "AppOfflineApplication.h"
|
||||||
|
|
||||||
APPLICATION_INFO::~APPLICATION_INFO()
|
APPLICATION_INFO::~APPLICATION_INFO()
|
||||||
{
|
{
|
||||||
ShutDownApplication();
|
ShutDownApplication(/* fServerInitiated */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT
|
|
||||||
APPLICATION_INFO::Initialize(
|
|
||||||
_In_ IHttpApplication &pApplication,
|
|
||||||
HandlerResolver * pHandlerResolver
|
|
||||||
)
|
|
||||||
{
|
|
||||||
m_handlerResolver = pHandlerResolver;
|
|
||||||
RETURN_IF_FAILED(m_struConfigPath.Copy(pApplication.GetAppConfigPath()));
|
|
||||||
RETURN_IF_FAILED(m_struInfoKey.Copy(pApplication.GetApplicationId()));
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
APPLICATION_INFO::GetOrCreateApplication(
|
APPLICATION_INFO::GetOrCreateApplication(
|
||||||
IHttpContext *pHttpContext,
|
IHttpContext *pHttpContext,
|
||||||
|
|
@ -54,6 +39,7 @@ APPLICATION_INFO::GetOrCreateApplication(
|
||||||
// Call to wait for application to complete stopping
|
// Call to wait for application to complete stopping
|
||||||
m_pApplication->Stop(/* fServerInitiated */ false);
|
m_pApplication->Stop(/* fServerInitiated */ false);
|
||||||
m_pApplication = nullptr;
|
m_pApplication = nullptr;
|
||||||
|
m_pApplicationFactory = nullptr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -69,20 +55,13 @@ APPLICATION_INFO::GetOrCreateApplication(
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
STRU struExeLocation;
|
FINISHED_IF_FAILED(m_handlerResolver.GetApplicationFactory(httpApplication, m_pApplicationFactory));
|
||||||
PFN_ASPNETCORE_CREATE_APPLICATION pfnAspNetCoreCreateApplication;
|
|
||||||
FINISHED_IF_FAILED(m_handlerResolver->GetApplicationFactory(httpApplication, struExeLocation, &pfnAspNetCoreCreateApplication));
|
|
||||||
std::array<APPLICATION_PARAMETER, 1> parameters {
|
|
||||||
{"InProcessExeLocation", struExeLocation.QueryStr()}
|
|
||||||
};
|
|
||||||
|
|
||||||
LOG_INFO("Creating handler application");
|
LOG_INFO("Creating handler application");
|
||||||
IAPPLICATION * newApplication;
|
IAPPLICATION * newApplication;
|
||||||
FINISHED_IF_FAILED(pfnAspNetCoreCreateApplication(
|
FINISHED_IF_FAILED(m_pApplicationFactory->Execute(
|
||||||
&m_pServer,
|
&m_pServer,
|
||||||
&httpApplication,
|
&httpApplication,
|
||||||
parameters.data(),
|
|
||||||
static_cast<DWORD>(parameters.size()),
|
|
||||||
&newApplication));
|
&newApplication));
|
||||||
|
|
||||||
m_pApplication.reset(newApplication);
|
m_pApplication.reset(newApplication);
|
||||||
|
|
@ -110,50 +89,17 @@ Finished:
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
APPLICATION_INFO::RecycleApplication()
|
APPLICATION_INFO::ShutDownApplication(bool fServerInitiated)
|
||||||
{
|
{
|
||||||
SRWExclusiveLock lock(m_applicationLock);
|
SRWExclusiveLock lock(m_applicationLock);
|
||||||
|
|
||||||
if (m_pApplication)
|
if (m_pApplication)
|
||||||
{
|
{
|
||||||
const auto pApplication = m_pApplication.release();
|
LOG_ERRORF("Stopping application %S", QueryApplicationInfoKey().c_str());
|
||||||
|
m_pApplication ->Stop(fServerInitiated);
|
||||||
HandleWrapper<InvalidHandleTraits> hThread = CreateThread(
|
|
||||||
NULL, // default security attributes
|
|
||||||
0, // default stack size
|
|
||||||
(LPTHREAD_START_ROUTINE)DoRecycleApplication,
|
|
||||||
pApplication, // thread function arguments
|
|
||||||
0, // default creation flags
|
|
||||||
NULL); // receive thread identifier
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DWORD WINAPI
|
|
||||||
APPLICATION_INFO::DoRecycleApplication(
|
|
||||||
LPVOID lpParam)
|
|
||||||
{
|
|
||||||
auto pApplication = std::unique_ptr<IAPPLICATION, IAPPLICATION_DELETER>(static_cast<IAPPLICATION*>(lpParam));
|
|
||||||
|
|
||||||
if (pApplication)
|
|
||||||
{
|
|
||||||
// Recycle will call shutdown for out of process
|
|
||||||
pApplication->Stop(/*fServerInitiated*/ false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
VOID
|
|
||||||
APPLICATION_INFO::ShutDownApplication()
|
|
||||||
{
|
|
||||||
SRWExclusiveLock lock(m_applicationLock);
|
|
||||||
|
|
||||||
if (m_pApplication)
|
|
||||||
{
|
|
||||||
m_pApplication ->Stop(/* fServerInitiated */ true);
|
|
||||||
m_pApplication = nullptr;
|
m_pApplication = nullptr;
|
||||||
|
m_pApplicationFactory = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "hostfxroptions.h"
|
#include "hostfxroptions.h"
|
||||||
#include "hashtable.h"
|
|
||||||
#include "hashfn.h"
|
|
||||||
#include "aspnetcore_shim_config.h"
|
#include "aspnetcore_shim_config.h"
|
||||||
#include "iapplication.h"
|
#include "iapplication.h"
|
||||||
#include "SRWSharedLock.h"
|
#include "SRWSharedLock.h"
|
||||||
|
|
@ -19,61 +17,35 @@ class APPLICATION_INFO
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
APPLICATION_INFO(IHttpServer &pServer) :
|
APPLICATION_INFO(
|
||||||
|
IHttpServer &pServer,
|
||||||
|
IHttpApplication &pApplication,
|
||||||
|
HandlerResolver &pHandlerResolver
|
||||||
|
) :
|
||||||
m_pServer(pServer),
|
m_pServer(pServer),
|
||||||
m_cRefs(1),
|
m_handlerResolver(pHandlerResolver),
|
||||||
m_handlerResolver(nullptr)
|
m_strConfigPath(pApplication.GetAppConfigPath()),
|
||||||
|
m_strInfoKey(pApplication.GetApplicationId())
|
||||||
{
|
{
|
||||||
InitializeSRWLock(&m_applicationLock);
|
InitializeSRWLock(&m_applicationLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
PCWSTR
|
|
||||||
QueryApplicationInfoKey()
|
|
||||||
{
|
|
||||||
return m_struInfoKey.QueryStr();
|
|
||||||
}
|
|
||||||
|
|
||||||
STRU*
|
|
||||||
QueryConfigPath()
|
|
||||||
{
|
|
||||||
return &m_struConfigPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual
|
|
||||||
~APPLICATION_INFO();
|
~APPLICATION_INFO();
|
||||||
|
|
||||||
static
|
std::wstring&
|
||||||
void
|
QueryApplicationInfoKey()
|
||||||
StaticInitialize()
|
|
||||||
{
|
{
|
||||||
|
return m_strInfoKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT
|
std::wstring&
|
||||||
Initialize(
|
QueryConfigPath()
|
||||||
IHttpApplication &pApplication,
|
|
||||||
HandlerResolver *pHandlerResolver
|
|
||||||
);
|
|
||||||
|
|
||||||
VOID
|
|
||||||
ReferenceApplicationInfo() const
|
|
||||||
{
|
{
|
||||||
InterlockedIncrement(&m_cRefs);
|
return m_strConfigPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
DereferenceApplicationInfo() const
|
ShutDownApplication(bool fServerInitiated);
|
||||||
{
|
|
||||||
if (InterlockedDecrement(&m_cRefs) == 0)
|
|
||||||
{
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID
|
|
||||||
RecycleApplication();
|
|
||||||
|
|
||||||
VOID
|
|
||||||
ShutDownApplication();
|
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
GetOrCreateApplication(
|
GetOrCreateApplication(
|
||||||
|
|
@ -81,88 +53,30 @@ public:
|
||||||
std::unique_ptr<IAPPLICATION, IAPPLICATION_DELETER>& pApplication
|
std::unique_ptr<IAPPLICATION, IAPPLICATION_DELETER>& pApplication
|
||||||
);
|
);
|
||||||
|
|
||||||
|
bool ConfigurationPathApplies(const std::wstring& path)
|
||||||
|
{
|
||||||
|
// We need to check that the last character of the config path
|
||||||
|
// is either a null terminator or a slash.
|
||||||
|
// This checks the case where the config path was
|
||||||
|
// MACHINE/WEBROOT/site and your site path is MACHINE/WEBROOT/siteTest
|
||||||
|
auto const changed = m_strConfigPath._Starts_with(path);
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
const auto lastChar = m_strConfigPath[m_strConfigPath.length()];
|
||||||
|
return lastChar == L'\0' || lastChar == L'/';
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static DWORD WINAPI DoRecycleApplication(LPVOID lpParam);
|
|
||||||
|
|
||||||
mutable LONG m_cRefs;
|
|
||||||
STRU m_struConfigPath;
|
|
||||||
STRU m_struInfoKey;
|
|
||||||
SRWLOCK m_applicationLock;
|
|
||||||
IHttpServer &m_pServer;
|
IHttpServer &m_pServer;
|
||||||
HandlerResolver *m_handlerResolver;
|
HandlerResolver &m_handlerResolver;
|
||||||
|
|
||||||
|
std::wstring m_strConfigPath;
|
||||||
|
std::wstring m_strInfoKey;
|
||||||
|
SRWLOCK m_applicationLock {};
|
||||||
|
|
||||||
|
std::unique_ptr<ApplicationFactory> m_pApplicationFactory;
|
||||||
std::unique_ptr<IAPPLICATION, IAPPLICATION_DELETER> m_pApplication;
|
std::unique_ptr<IAPPLICATION, IAPPLICATION_DELETER> m_pApplication;
|
||||||
};
|
};
|
||||||
|
|
||||||
class APPLICATION_INFO_HASH :
|
|
||||||
public HASH_TABLE<APPLICATION_INFO, PCWSTR>
|
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
APPLICATION_INFO_HASH()
|
|
||||||
{}
|
|
||||||
|
|
||||||
PCWSTR
|
|
||||||
ExtractKey(
|
|
||||||
APPLICATION_INFO *pApplicationInfo
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return pApplicationInfo->QueryApplicationInfoKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD
|
|
||||||
CalcKeyHash(
|
|
||||||
PCWSTR pszApplicationId
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return HashStringNoCase(pszApplicationId);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL
|
|
||||||
EqualKeys(
|
|
||||||
PCWSTR pszKey1,
|
|
||||||
PCWSTR pszKey2
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return CompareStringOrdinal(pszKey1,
|
|
||||||
-1,
|
|
||||||
pszKey2,
|
|
||||||
-1,
|
|
||||||
TRUE) == CSTR_EQUAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID
|
|
||||||
ReferenceRecord(
|
|
||||||
APPLICATION_INFO *pApplicationInfo
|
|
||||||
)
|
|
||||||
{
|
|
||||||
pApplicationInfo->ReferenceApplicationInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID
|
|
||||||
DereferenceRecord(
|
|
||||||
APPLICATION_INFO *pApplicationInfo
|
|
||||||
)
|
|
||||||
{
|
|
||||||
pApplicationInfo->DereferenceApplicationInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
VOID
|
|
||||||
ReferenceCopyToTable(
|
|
||||||
APPLICATION_INFO * pEntry,
|
|
||||||
PVOID pvData
|
|
||||||
)
|
|
||||||
{
|
|
||||||
APPLICATION_INFO_HASH *pHash = static_cast<APPLICATION_INFO_HASH *>(pvData);
|
|
||||||
DBG_ASSERT(pHash);
|
|
||||||
pHash->InsertRecord(pEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
APPLICATION_INFO_HASH(const APPLICATION_INFO_HASH &);
|
|
||||||
void operator=(const APPLICATION_INFO_HASH &);
|
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -20,25 +20,16 @@ APPLICATION_MANAGER* APPLICATION_MANAGER::sm_pApplicationManager = NULL;
|
||||||
//
|
//
|
||||||
HRESULT
|
HRESULT
|
||||||
APPLICATION_MANAGER::GetOrCreateApplicationInfo(
|
APPLICATION_MANAGER::GetOrCreateApplicationInfo(
|
||||||
_In_ IHttpContext* pHttpContext,
|
_In_ IHttpContext& pHttpContext,
|
||||||
_Out_ APPLICATION_INFO ** ppApplicationInfo
|
_Out_ std::shared_ptr<APPLICATION_INFO>& ppApplicationInfo
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
|
||||||
APPLICATION_INFO *pApplicationInfo = NULL;
|
|
||||||
PCWSTR pszApplicationId = NULL;
|
|
||||||
|
|
||||||
STACK_STRU ( strEventMsg, 256 );
|
auto &pApplication = *pHttpContext.GetApplication();
|
||||||
|
|
||||||
DBG_ASSERT(pHttpContext);
|
|
||||||
DBG_ASSERT(ppApplicationInfo);
|
|
||||||
|
|
||||||
*ppApplicationInfo = NULL;
|
|
||||||
IHttpApplication &pApplication = *pHttpContext->GetApplication();
|
|
||||||
|
|
||||||
// The configuration path is unique for each application and is used for the
|
// The configuration path is unique for each application and is used for the
|
||||||
// key in the applicationInfoHash.
|
// key in the applicationInfoHash.
|
||||||
pszApplicationId = pApplication.GetApplicationId();
|
std::wstring pszApplicationId = pApplication.GetApplicationId();
|
||||||
|
|
||||||
{
|
{
|
||||||
// When accessing the m_pApplicationInfoHash, we need to acquire the application manager
|
// When accessing the m_pApplicationInfoHash, we need to acquire the application manager
|
||||||
|
|
@ -47,93 +38,41 @@ APPLICATION_MANAGER::GetOrCreateApplicationInfo(
|
||||||
|
|
||||||
if (g_fInShutdown)
|
if (g_fInShutdown)
|
||||||
{
|
{
|
||||||
FINISHED(HRESULT_FROM_WIN32(ERROR_SERVER_SHUTDOWN_IN_PROGRESS));
|
return HRESULT_FROM_WIN32(ERROR_SERVER_SHUTDOWN_IN_PROGRESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pApplicationInfoHash->FindKey(pszApplicationId, ppApplicationInfo);
|
const auto pair = m_pApplicationInfoHash.find(pszApplicationId);
|
||||||
|
if (pair != m_pApplicationInfoHash.end())
|
||||||
|
{
|
||||||
|
ppApplicationInfo = pair->second;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// It's important to release read lock here so exclusive lock
|
// It's important to release read lock here so exclusive lock
|
||||||
// can be reacquired later as SRW lock doesn't allow upgrades
|
// can be reacquired later as SRW lock doesn't allow upgrades
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*ppApplicationInfo == NULL)
|
// Take exclusive lock before creating the application
|
||||||
|
SRWExclusiveLock writeLock(m_srwLock);
|
||||||
|
|
||||||
|
if (!m_fDebugInitialize)
|
||||||
{
|
{
|
||||||
// Take exclusive lock before creating the application
|
DebugInitializeFromConfig(m_pHttpServer, pApplication);
|
||||||
SRWExclusiveLock writeLock(m_srwLock);
|
m_fDebugInitialize = TRUE;
|
||||||
|
|
||||||
if (!m_fDebugInitialize)
|
|
||||||
{
|
|
||||||
DebugInitializeFromConfig(m_pHttpServer, pApplication);
|
|
||||||
m_fDebugInitialize = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if other thread created the application
|
|
||||||
m_pApplicationInfoHash->FindKey(pszApplicationId, ppApplicationInfo);
|
|
||||||
if (*ppApplicationInfo != NULL)
|
|
||||||
{
|
|
||||||
FINISHED(S_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
pApplicationInfo = new APPLICATION_INFO(m_pHttpServer);
|
|
||||||
|
|
||||||
FINISHED_IF_FAILED(pApplicationInfo->Initialize(pApplication, &m_handlerResolver));
|
|
||||||
FINISHED_IF_FAILED(m_pApplicationInfoHash->InsertRecord(pApplicationInfo));
|
|
||||||
|
|
||||||
*ppApplicationInfo = pApplicationInfo;
|
|
||||||
pApplicationInfo = NULL;
|
|
||||||
}
|
|
||||||
Finished:
|
|
||||||
|
|
||||||
if (pApplicationInfo != NULL)
|
|
||||||
{
|
|
||||||
pApplicationInfo->DereferenceApplicationInfo();
|
|
||||||
pApplicationInfo = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return hr;
|
// Check if other thread created the application
|
||||||
}
|
const auto pair = m_pApplicationInfoHash.find(pszApplicationId);
|
||||||
|
if (pair != m_pApplicationInfoHash.end())
|
||||||
|
|
||||||
//
|
|
||||||
// If the application's configuration was changed,
|
|
||||||
// append the configuration path to the config change context.
|
|
||||||
//
|
|
||||||
BOOL
|
|
||||||
APPLICATION_MANAGER::FindConfigChangedApplication(
|
|
||||||
_In_ APPLICATION_INFO * pEntry,
|
|
||||||
_In_ PVOID pvContext)
|
|
||||||
{
|
|
||||||
DBG_ASSERT(pEntry);
|
|
||||||
DBG_ASSERT(pvContext);
|
|
||||||
|
|
||||||
// Config Change context contains the original config path that changed
|
|
||||||
// and a multiStr containing
|
|
||||||
CONFIG_CHANGE_CONTEXT* pContext = static_cast<CONFIG_CHANGE_CONTEXT*>(pvContext);
|
|
||||||
STRU* pstruConfigPath = pEntry->QueryConfigPath();
|
|
||||||
|
|
||||||
// check if the application path contains our app/subapp by seeing if the config path
|
|
||||||
// starts with the notification path.
|
|
||||||
BOOL fChanged = pstruConfigPath->StartsWith(pContext->pstrPath, true);
|
|
||||||
if (fChanged)
|
|
||||||
{
|
{
|
||||||
auto dwLen = wcslen(pContext->pstrPath);
|
ppApplicationInfo = pair->second;
|
||||||
WCHAR wChar = pstruConfigPath->QueryStr()[dwLen];
|
return S_OK;
|
||||||
|
|
||||||
// We need to check that the last character of the config path
|
|
||||||
// is either a null terminator or a slash.
|
|
||||||
// This checks the case where the config path was
|
|
||||||
// MACHINE/WEBROOT/site and your site path is MACHINE/WEBROOT/siteTest
|
|
||||||
if (wChar != L'\0' && wChar != L'/')
|
|
||||||
{
|
|
||||||
// not current app or sub app
|
|
||||||
fChanged = FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pContext->MultiSz.Append(pEntry->QueryApplicationInfoKey());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return fChanged;
|
|
||||||
|
ppApplicationInfo = std::make_shared<APPLICATION_INFO>(m_pHttpServer, pApplication, m_handlerResolver);
|
||||||
|
m_pApplicationInfoHash.emplace(pszApplicationId, ppApplicationInfo);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -148,101 +87,82 @@ APPLICATION_MANAGER::RecycleApplicationFromManager(
|
||||||
_In_ LPCWSTR pszApplicationId
|
_In_ LPCWSTR pszApplicationId
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
try
|
||||||
DWORD dwPreviousCounter = 0;
|
|
||||||
APPLICATION_INFO_HASH* table = NULL;
|
|
||||||
CONFIG_CHANGE_CONTEXT context;
|
|
||||||
|
|
||||||
if (g_fInShutdown)
|
|
||||||
{
|
{
|
||||||
// We are already shutting down, ignore this event as a global configuration change event
|
std::vector<std::shared_ptr<APPLICATION_INFO>> applicationsToRecycle;
|
||||||
// can occur after global stop listening for some reason.
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
SRWExclusiveLock lock(m_srwLock);
|
|
||||||
if (g_fInShutdown)
|
if (g_fInShutdown)
|
||||||
{
|
{
|
||||||
return hr;
|
// We are already shutting down, ignore this event as a global configuration change event
|
||||||
|
// can occur after global stop listening for some reason.
|
||||||
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a shallow copy of existing hashtable as we may need to remove nodes
|
|
||||||
// This will be used for finding differences in which applications are affected by a config change.
|
|
||||||
table = new APPLICATION_INFO_HASH();
|
|
||||||
|
|
||||||
// few application expected, small bucket size for hash table
|
|
||||||
if (FAILED(hr = table->Initialize(17 /*prime*/)))
|
|
||||||
{
|
{
|
||||||
goto Finished;
|
SRWExclusiveLock lock(m_srwLock);
|
||||||
|
if (g_fInShutdown)
|
||||||
|
{
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
const std::wstring configurationPath = pszApplicationId;
|
||||||
|
|
||||||
|
auto itr = m_pApplicationInfoHash.begin();
|
||||||
|
while (itr != m_pApplicationInfoHash.end())
|
||||||
|
{
|
||||||
|
if (itr->second->ConfigurationPathApplies(configurationPath))
|
||||||
|
{
|
||||||
|
applicationsToRecycle.emplace_back(itr->second);
|
||||||
|
itr = m_pApplicationInfoHash.erase(itr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++itr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// All applications were unloaded reset handler resolver validation logic
|
||||||
|
if (m_pApplicationInfoHash.empty())
|
||||||
|
{
|
||||||
|
m_handlerResolver.ResetHostingModel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context.pstrPath = pszApplicationId;
|
// If we receive a request at this point.
|
||||||
|
// OutOfProcess: we will create a new application with new configuration
|
||||||
|
// InProcess: the request would have to be rejected, as we are about to call g_HttpServer->RecycleProcess
|
||||||
|
// on the worker proocess
|
||||||
|
|
||||||
// Keep track of the preview count of applications to know whether there are applications to delete
|
if (!applicationsToRecycle.empty())
|
||||||
dwPreviousCounter = m_pApplicationInfoHash->Count();
|
|
||||||
|
|
||||||
// We don't want to hold the application manager lock for long time as it will block all incoming requests
|
|
||||||
// Don't call application shutdown inside the lock
|
|
||||||
m_pApplicationInfoHash->Apply(APPLICATION_INFO_HASH::ReferenceCopyToTable, static_cast<PVOID>(table));
|
|
||||||
DBG_ASSERT(dwPreviousCounter == table->Count());
|
|
||||||
|
|
||||||
// Removed the applications which are impacted by the configurtion change
|
|
||||||
m_pApplicationInfoHash->DeleteIf(FindConfigChangedApplication, (PVOID)&context);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we receive a request at this point.
|
|
||||||
// OutOfProcess: we will create a new application with new configuration
|
|
||||||
// InProcess: the request would have to be rejected, as we are about to call g_HttpServer->RecycleProcess
|
|
||||||
// on the worker proocess
|
|
||||||
if (!context.MultiSz.IsEmpty())
|
|
||||||
{
|
|
||||||
PCWSTR path = context.MultiSz.First();
|
|
||||||
// Iterate through each of the paths that were shut down,
|
|
||||||
// calling RecycleApplication on each of them.
|
|
||||||
while (path != NULL)
|
|
||||||
{
|
{
|
||||||
APPLICATION_INFO* pRecord;
|
for (auto& application : applicationsToRecycle)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
application->ShutDownApplication(/* fServerInitiated */ false);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
LOG_ERRORF("Failed to stop application %S", application->QueryApplicationInfoKey().c_str());
|
||||||
|
OBSERVE_CAUGHT_EXCEPTION();
|
||||||
|
|
||||||
// Application got recycled. Log an event
|
// Failed to recycle an application. Log an event
|
||||||
EventLog::Info(
|
EventLog::Error(
|
||||||
ASPNETCORE_EVENT_RECYCLE_CONFIGURATION,
|
ASPNETCORE_EVENT_RECYCLE_APP_FAILURE,
|
||||||
ASPNETCORE_EVENT_RECYCLE_CONFIGURATION_MSG,
|
ASPNETCORE_EVENT_RECYCLE_FAILURE_CONFIGURATION_MSG,
|
||||||
path);
|
pszApplicationId);
|
||||||
|
// Need to recycle the process as we cannot recycle the application
|
||||||
table->FindKey(path, &pRecord);
|
if (!g_fRecycleProcessCalled)
|
||||||
DBG_ASSERT(pRecord != NULL);
|
{
|
||||||
|
g_fRecycleProcessCalled = TRUE;
|
||||||
// RecycleApplication is called on a separate thread.
|
m_pHttpServer.RecycleProcess(L"AspNetCore Recycle Process on Demand Due Application Recycle Error");
|
||||||
pRecord->RecycleApplication();
|
}
|
||||||
pRecord->DereferenceApplicationInfo();
|
}
|
||||||
path = context.MultiSz.Next(path);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CATCH_RETURN();
|
||||||
|
|
||||||
Finished:
|
return S_OK;
|
||||||
if (table != NULL)
|
|
||||||
{
|
|
||||||
table->Clear();
|
|
||||||
delete table;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
// Failed to recycle an application. Log an event
|
|
||||||
EventLog::Error(
|
|
||||||
ASPNETCORE_EVENT_RECYCLE_APP_FAILURE,
|
|
||||||
ASPNETCORE_EVENT_RECYCLE_FAILURE_CONFIGURATION_MSG,
|
|
||||||
pszApplicationId);
|
|
||||||
// Need to recycle the process as we cannot recycle the application
|
|
||||||
if (!g_fRecycleProcessCalled)
|
|
||||||
{
|
|
||||||
g_fRecycleProcessCalled = TRUE;
|
|
||||||
m_pHttpServer.RecycleProcess(L"AspNetCore Recycle Process on Demand Due Application Recycle Error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -256,34 +176,12 @@ APPLICATION_MANAGER::ShutDown()
|
||||||
// However, it is possible to receive multiple OnGlobalStopListening events
|
// However, it is possible to receive multiple OnGlobalStopListening events
|
||||||
// Protect against this by checking if we already shut down.
|
// Protect against this by checking if we already shut down.
|
||||||
g_fInShutdown = TRUE;
|
g_fInShutdown = TRUE;
|
||||||
if (m_pApplicationInfoHash != NULL)
|
|
||||||
|
// During shutdown we lock until we delete the application
|
||||||
|
SRWExclusiveLock lock(m_srwLock);
|
||||||
|
for (auto &pair : m_pApplicationInfoHash)
|
||||||
{
|
{
|
||||||
DBG_ASSERT(m_pApplicationInfoHash);
|
pair.second->ShutDownApplication(/* fServerInitiated */ true);
|
||||||
|
pair.second = nullptr;
|
||||||
// During shutdown we lock until we delete the application
|
|
||||||
SRWExclusiveLock lock(m_srwLock);
|
|
||||||
|
|
||||||
// Call shutdown on each application in the application manager
|
|
||||||
m_pApplicationInfoHash->Apply(ShutdownApplication, NULL);
|
|
||||||
m_pApplicationInfoHash->Clear();
|
|
||||||
delete m_pApplicationInfoHash;
|
|
||||||
m_pApplicationInfoHash = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Calls shutdown on each application. ApplicationManager's lock is held for duration of
|
|
||||||
// each shutdown call, guaranteeing another application cannot be created.
|
|
||||||
//
|
|
||||||
// static
|
|
||||||
VOID
|
|
||||||
APPLICATION_MANAGER::ShutdownApplication(
|
|
||||||
_In_ APPLICATION_INFO * pEntry,
|
|
||||||
_In_ PVOID pvContext
|
|
||||||
)
|
|
||||||
{
|
|
||||||
UNREFERENCED_PARAMETER(pvContext);
|
|
||||||
DBG_ASSERT(pEntry != NULL);
|
|
||||||
|
|
||||||
pEntry->ShutDownApplication();
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include "applicationinfo.h"
|
#include "applicationinfo.h"
|
||||||
#include "multisz.h"
|
#include "multisz.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#define DEFAULT_HASH_BUCKETS 17
|
#define DEFAULT_HASH_BUCKETS 17
|
||||||
|
|
||||||
|
|
@ -15,11 +16,6 @@
|
||||||
// Should always call GetInstance to get the object instance
|
// Should always call GetInstance to get the object instance
|
||||||
//
|
//
|
||||||
|
|
||||||
struct CONFIG_CHANGE_CONTEXT
|
|
||||||
{
|
|
||||||
PCWSTR pstrPath;
|
|
||||||
MULTISZ MultiSz;
|
|
||||||
};
|
|
||||||
|
|
||||||
class APPLICATION_MANAGER
|
class APPLICATION_MANAGER
|
||||||
{
|
{
|
||||||
|
|
@ -35,9 +31,7 @@ public:
|
||||||
|
|
||||||
static
|
static
|
||||||
VOID
|
VOID
|
||||||
Cleanup(
|
Cleanup()
|
||||||
VOID
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
if(sm_pApplicationManager != NULL)
|
if(sm_pApplicationManager != NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -46,24 +40,10 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
BOOL
|
|
||||||
FindConfigChangedApplication(
|
|
||||||
_In_ APPLICATION_INFO * pEntry,
|
|
||||||
_In_ PVOID pvContext
|
|
||||||
);
|
|
||||||
|
|
||||||
static
|
|
||||||
VOID
|
|
||||||
ShutdownApplication(
|
|
||||||
_In_ APPLICATION_INFO * pEntry,
|
|
||||||
_In_ PVOID pvContext
|
|
||||||
);
|
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
GetOrCreateApplicationInfo(
|
GetOrCreateApplicationInfo(
|
||||||
_In_ IHttpContext* pHttpContext,
|
_In_ IHttpContext& pHttpContext,
|
||||||
_Out_ APPLICATION_INFO ** ppApplicationInfo
|
_Out_ std::shared_ptr<APPLICATION_INFO>& ppApplicationInfo
|
||||||
);
|
);
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
|
|
@ -74,40 +54,13 @@ public:
|
||||||
VOID
|
VOID
|
||||||
ShutDown();
|
ShutDown();
|
||||||
|
|
||||||
~APPLICATION_MANAGER()
|
|
||||||
{
|
|
||||||
|
|
||||||
if(m_pApplicationInfoHash != NULL)
|
|
||||||
{
|
|
||||||
m_pApplicationInfoHash->Clear();
|
|
||||||
delete m_pApplicationInfoHash;
|
|
||||||
m_pApplicationInfoHash = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static HRESULT StaticInitialize(HMODULE hModule, IHttpServer& pHttpServer)
|
static HRESULT StaticInitialize(HMODULE hModule, IHttpServer& pHttpServer)
|
||||||
{
|
{
|
||||||
assert(!sm_pApplicationManager);
|
assert(!sm_pApplicationManager);
|
||||||
sm_pApplicationManager = new APPLICATION_MANAGER(hModule, pHttpServer);
|
sm_pApplicationManager = new APPLICATION_MANAGER(hModule, pHttpServer);
|
||||||
RETURN_IF_FAILED(sm_pApplicationManager->Initialize());
|
|
||||||
|
|
||||||
APPLICATION_INFO::StaticInitialize();
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT Initialize()
|
|
||||||
{
|
|
||||||
if(m_pApplicationInfoHash == NULL)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_pApplicationInfoHash = new APPLICATION_INFO_HASH();
|
|
||||||
}
|
|
||||||
CATCH_RETURN();
|
|
||||||
RETURN_IF_FAILED(m_pApplicationInfoHash->Initialize(DEFAULT_HASH_BUCKETS));
|
|
||||||
}
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
APPLICATION_MANAGER(HMODULE hModule, IHttpServer& pHttpServer) :
|
APPLICATION_MANAGER(HMODULE hModule, IHttpServer& pHttpServer) :
|
||||||
|
|
@ -119,7 +72,7 @@ private:
|
||||||
InitializeSRWLock(&m_srwLock);
|
InitializeSRWLock(&m_srwLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
APPLICATION_INFO_HASH *m_pApplicationInfoHash;
|
std::unordered_map<std::wstring, std::shared_ptr<APPLICATION_INFO>> m_pApplicationInfoHash;
|
||||||
static APPLICATION_MANAGER *sm_pApplicationManager;
|
static APPLICATION_MANAGER *sm_pApplicationManager;
|
||||||
SRWLOCK m_srwLock {};
|
SRWLOCK m_srwLock {};
|
||||||
BOOL m_fDebugInitialize;
|
BOOL m_fDebugInitialize;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ ASPNETCORE_SHIM_CONFIG::Populate(
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
STACK_STRU(strHostingModel, 12);
|
STACK_STRU(strHostingModel, 12);
|
||||||
STRU strApplicationFullPath;
|
|
||||||
CComPtr<IAppHostElement> pAspNetCoreElement;
|
CComPtr<IAppHostElement> pAspNetCoreElement;
|
||||||
|
|
||||||
IAppHostAdminManager *pAdminManager = pHttpServer->GetAdminManager();
|
IAppHostAdminManager *pAdminManager = pHttpServer->GetAdminManager();
|
||||||
|
|
@ -25,9 +24,11 @@ ASPNETCORE_SHIM_CONFIG::Populate(
|
||||||
applicationConfigPath,
|
applicationConfigPath,
|
||||||
&pAspNetCoreElement));
|
&pAspNetCoreElement));
|
||||||
|
|
||||||
|
CComBSTR struProcessPath;
|
||||||
RETURN_IF_FAILED(GetElementStringProperty(pAspNetCoreElement,
|
RETURN_IF_FAILED(GetElementStringProperty(pAspNetCoreElement,
|
||||||
CS_ASPNETCORE_PROCESS_EXE_PATH,
|
CS_ASPNETCORE_PROCESS_EXE_PATH,
|
||||||
&m_struProcessPath));
|
&struProcessPath));
|
||||||
|
m_strProcessPath = struProcessPath;
|
||||||
|
|
||||||
// Swallow this error for backward compatibility
|
// Swallow this error for backward compatibility
|
||||||
// Use default behavior for empty string
|
// Use default behavior for empty string
|
||||||
|
|
@ -53,13 +54,18 @@ ASPNETCORE_SHIM_CONFIG::Populate(
|
||||||
RETURN_HR(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));
|
RETURN_HR(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CComBSTR struArguments;
|
||||||
RETURN_IF_FAILED(GetElementStringProperty(pAspNetCoreElement,
|
RETURN_IF_FAILED(GetElementStringProperty(pAspNetCoreElement,
|
||||||
CS_ASPNETCORE_PROCESS_ARGUMENTS,
|
CS_ASPNETCORE_PROCESS_ARGUMENTS,
|
||||||
&m_struArguments));
|
&struArguments));
|
||||||
|
|
||||||
|
m_strArguments = struArguments;
|
||||||
|
|
||||||
if (m_hostingModel == HOSTING_OUT_PROCESS)
|
if (m_hostingModel == HOSTING_OUT_PROCESS)
|
||||||
{
|
{
|
||||||
RETURN_IF_FAILED(ConfigUtility::FindHandlerVersion(pAspNetCoreElement, m_struHandlerVersion));
|
STRU struHandlerVersion;
|
||||||
|
RETURN_IF_FAILED(ConfigUtility::FindHandlerVersion(pAspNetCoreElement, struHandlerVersion));
|
||||||
|
m_strHandlerVersion = struHandlerVersion.QueryStr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,10 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <httpserv.h>
|
#include <httpserv.h>
|
||||||
|
|
||||||
#include "stringu.h"
|
|
||||||
|
|
||||||
#define CS_ASPNETCORE_SECTION L"system.webServer/aspNetCore"
|
#define CS_ASPNETCORE_SECTION L"system.webServer/aspNetCore"
|
||||||
#define CS_ASPNETCORE_PROCESS_EXE_PATH L"processPath"
|
#define CS_ASPNETCORE_PROCESS_EXE_PATH L"processPath"
|
||||||
#define CS_ASPNETCORE_PROCESS_ARGUMENTS L"arguments"
|
#define CS_ASPNETCORE_PROCESS_ARGUMENTS L"arguments"
|
||||||
|
|
@ -34,16 +33,16 @@ public:
|
||||||
IHttpApplication *pHttpApplication
|
IHttpApplication *pHttpApplication
|
||||||
);
|
);
|
||||||
|
|
||||||
STRU*
|
std::wstring&
|
||||||
QueryProcessPath()
|
QueryProcessPath()
|
||||||
{
|
{
|
||||||
return &m_struProcessPath;
|
return m_strProcessPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
STRU*
|
std::wstring&
|
||||||
QueryArguments()
|
QueryArguments()
|
||||||
{
|
{
|
||||||
return &m_struArguments;
|
return m_strArguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
APP_HOSTING_MODEL
|
APP_HOSTING_MODEL
|
||||||
|
|
@ -52,10 +51,10 @@ public:
|
||||||
return m_hostingModel;
|
return m_hostingModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
STRU*
|
std::wstring&
|
||||||
QueryHandlerVersion()
|
QueryHandlerVersion()
|
||||||
{
|
{
|
||||||
return &m_struHandlerVersion;
|
return m_strHandlerVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
|
|
@ -77,10 +76,10 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
STRU m_struArguments;
|
std::wstring m_strArguments;
|
||||||
STRU m_struProcessPath;
|
std::wstring m_strProcessPath;
|
||||||
APP_HOSTING_MODEL m_hostingModel;
|
APP_HOSTING_MODEL m_hostingModel;
|
||||||
STRU m_struHandlerVersion;
|
std::wstring m_strHandlerVersion;
|
||||||
BOOL m_fStdoutLogEnabled;
|
BOOL m_fStdoutLogEnabled;
|
||||||
STRU m_struStdoutLogFile;
|
STRU m_struStdoutLogFile;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -51,19 +51,10 @@ Return value:
|
||||||
}
|
}
|
||||||
|
|
||||||
ASPNET_CORE_PROXY_MODULE::ASPNET_CORE_PROXY_MODULE(
|
ASPNET_CORE_PROXY_MODULE::ASPNET_CORE_PROXY_MODULE(
|
||||||
) : m_pApplicationInfo(nullptr), m_pApplication(nullptr), m_pHandler(nullptr)
|
) : m_pApplicationInfo(nullptr), m_pHandler(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ASPNET_CORE_PROXY_MODULE::~ASPNET_CORE_PROXY_MODULE()
|
|
||||||
{
|
|
||||||
if (m_pApplicationInfo != NULL)
|
|
||||||
{
|
|
||||||
m_pApplicationInfo->DereferenceApplicationInfo();
|
|
||||||
m_pApplicationInfo = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__override
|
__override
|
||||||
REQUEST_NOTIFICATION_STATUS
|
REQUEST_NOTIFICATION_STATUS
|
||||||
ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler(
|
ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler(
|
||||||
|
|
@ -72,9 +63,7 @@ ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler(
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
APPLICATION_MANAGER *pApplicationManager = NULL;
|
|
||||||
REQUEST_NOTIFICATION_STATUS retVal = RQ_NOTIFICATION_CONTINUE;
|
REQUEST_NOTIFICATION_STATUS retVal = RQ_NOTIFICATION_CONTINUE;
|
||||||
STRU struExeLocation;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -83,13 +72,11 @@ ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler(
|
||||||
FINISHED(HRESULT_FROM_WIN32(ERROR_SERVER_SHUTDOWN_IN_PROGRESS));
|
FINISHED(HRESULT_FROM_WIN32(ERROR_SERVER_SHUTDOWN_IN_PROGRESS));
|
||||||
}
|
}
|
||||||
|
|
||||||
pApplicationManager = APPLICATION_MANAGER::GetInstance();
|
auto pApplicationManager = APPLICATION_MANAGER::GetInstance();
|
||||||
|
|
||||||
FINISHED_IF_FAILED(pApplicationManager->GetOrCreateApplicationInfo(
|
FINISHED_IF_FAILED(pApplicationManager->GetOrCreateApplicationInfo(
|
||||||
pHttpContext,
|
*pHttpContext,
|
||||||
&m_pApplicationInfo));
|
m_pApplicationInfo));
|
||||||
|
|
||||||
DBG_ASSERT(pHttpContext);
|
|
||||||
|
|
||||||
std::unique_ptr<IAPPLICATION, IAPPLICATION_DELETER> pApplication;
|
std::unique_ptr<IAPPLICATION, IAPPLICATION_DELETER> pApplication;
|
||||||
FINISHED_IF_FAILED(m_pApplicationInfo->GetOrCreateApplication(pHttpContext, pApplication));
|
FINISHED_IF_FAILED(m_pApplicationInfo->GetOrCreateApplication(pHttpContext, pApplication));
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ class ASPNET_CORE_PROXY_MODULE : public CHttpModule
|
||||||
|
|
||||||
ASPNET_CORE_PROXY_MODULE();
|
ASPNET_CORE_PROXY_MODULE();
|
||||||
|
|
||||||
~ASPNET_CORE_PROXY_MODULE();
|
~ASPNET_CORE_PROXY_MODULE() = default;
|
||||||
|
|
||||||
void * operator new(size_t size, IModuleAllocator * pPlacement)
|
void * operator new(size_t size, IModuleAllocator * pPlacement)
|
||||||
{
|
{
|
||||||
|
|
@ -46,9 +46,7 @@ class ASPNET_CORE_PROXY_MODULE : public CHttpModule
|
||||||
);
|
);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::shared_ptr<APPLICATION_INFO> m_pApplicationInfo;
|
||||||
APPLICATION_INFO *m_pApplicationInfo;
|
|
||||||
IAPPLICATION *m_pApplication;
|
|
||||||
std::unique_ptr<IREQUEST_HANDLER, IREQUEST_HANDLER_DELETER> m_pHandler;
|
std::unique_ptr<IREQUEST_HANDLER, IREQUEST_HANDLER_DELETER> m_pHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,13 @@ public:
|
||||||
|
|
||||||
HandleType* operator&() { return &m_handle; }
|
HandleType* operator&() { return &m_handle; }
|
||||||
|
|
||||||
|
HandleType release() noexcept
|
||||||
|
{
|
||||||
|
auto value = m_handle;
|
||||||
|
m_handle = traits::DefaultHandle;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HandleType m_handle;
|
HandleType m_handle;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ void SetDebugFlags(const std::wstring &debugValue)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!debugValue.empty())
|
if (!debugValue.empty() && debugValue.find_first_not_of(L"0123456789") == std::wstring::npos)
|
||||||
{
|
{
|
||||||
const auto value = std::stoi(debugValue);
|
const auto value = std::stoi(debugValue);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -165,34 +165,3 @@ FILE_UTILITY::EnsureDirectoryPathExist(
|
||||||
Finished:
|
Finished:
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL
|
|
||||||
FILE_UTILITY::CheckIfFileExists(
|
|
||||||
_In_ PCWSTR pszFilePath
|
|
||||||
)
|
|
||||||
{
|
|
||||||
HANDLE hFileHandle = INVALID_HANDLE_VALUE;
|
|
||||||
SECURITY_ATTRIBUTES saAttr;
|
|
||||||
BOOL fFileExists = FALSE;
|
|
||||||
|
|
||||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
||||||
saAttr.bInheritHandle = TRUE;
|
|
||||||
saAttr.lpSecurityDescriptor = NULL;
|
|
||||||
|
|
||||||
hFileHandle = CreateFile(pszFilePath,
|
|
||||||
GENERIC_READ,
|
|
||||||
FILE_SHARE_READ,
|
|
||||||
&saAttr,
|
|
||||||
OPEN_EXISTING,
|
|
||||||
FILE_ATTRIBUTE_NORMAL,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
fFileExists = hFileHandle != INVALID_HANDLE_VALUE || GetLastError() == ERROR_SHARING_VIOLATION;
|
|
||||||
|
|
||||||
if (fFileExists)
|
|
||||||
{
|
|
||||||
CloseHandle(hFileHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
return fFileExists;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,6 @@ public:
|
||||||
EnsureDirectoryPathExist(
|
EnsureDirectoryPathExist(
|
||||||
_In_ LPCWSTR pszPath
|
_In_ LPCWSTR pszPath
|
||||||
);
|
);
|
||||||
|
|
||||||
static
|
|
||||||
BOOL
|
|
||||||
CheckIfFileExists(
|
|
||||||
PCWSTR pszFilePath
|
|
||||||
);
|
|
||||||
private:
|
private:
|
||||||
static
|
static
|
||||||
HRESULT
|
HRESULT
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ enum APPLICATION_STATUS
|
||||||
|
|
||||||
struct APPLICATION_PARAMETER
|
struct APPLICATION_PARAMETER
|
||||||
{
|
{
|
||||||
LPCSTR pzName;
|
LPCSTR pzName;
|
||||||
PVOID pValue;
|
const void *pValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IAPPLICATION
|
class IAPPLICATION
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,8 @@ EnsureOutOfProcessInitializtion()
|
||||||
FINISHED(S_OK);
|
FINISHED(S_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_fOutOfProcessInitialize = TRUE;
|
||||||
|
|
||||||
g_hWinHttpModule = GetModuleHandle(TEXT("winhttp.dll"));
|
g_hWinHttpModule = GetModuleHandle(TEXT("winhttp.dll"));
|
||||||
|
|
||||||
g_hAspNetCoreModule = GetModuleHandle(TEXT("aspnetcorev2.dll"));
|
g_hAspNetCoreModule = GetModuleHandle(TEXT("aspnetcorev2.dll"));
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,18 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Sockets;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
|
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
|
||||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||||
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
|
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
|
|
@ -14,6 +20,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
[Collection(PublishedSitesCollection.Name)]
|
[Collection(PublishedSitesCollection.Name)]
|
||||||
public class ConfigurationChangeTests : IISFunctionalTestBase
|
public class ConfigurationChangeTests : IISFunctionalTestBase
|
||||||
{
|
{
|
||||||
|
private static readonly TimeSpan RetryDelay = TimeSpan.FromMilliseconds(100);
|
||||||
private readonly PublishedSitesFixture _fixture;
|
private readonly PublishedSitesFixture _fixture;
|
||||||
|
|
||||||
public ConfigurationChangeTests(PublishedSitesFixture fixture)
|
public ConfigurationChangeTests(PublishedSitesFixture fixture)
|
||||||
|
|
@ -66,13 +73,54 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
await deploymentResult.AssertStarts();
|
await deploymentResult.AssertStarts();
|
||||||
|
|
||||||
deploymentResult.ModifyWebConfig(element => element
|
deploymentResult.ModifyWebConfig(element => element
|
||||||
.GetOrAdd("system.webServer")
|
.Descendants("system.webServer")
|
||||||
|
.Single()
|
||||||
.GetOrAdd("aspNetCore")
|
.GetOrAdd("aspNetCore")
|
||||||
.SetAttributeValue("hostingModel", "inprocess"));
|
.SetAttributeValue("hostingModel", "inprocess"));
|
||||||
|
|
||||||
// Have to retry here to allow ANCM to receive notification and react to it
|
// Have to retry here to allow ANCM to receive notification and react to it
|
||||||
// Verify that worker process gets restarted with new process id
|
// Verify that inprocess application was created and tried to start
|
||||||
await deploymentResult.HttpClient.RetryRequestAsync("/HelloWorld", r => r.StatusCode == HttpStatusCode.InternalServerError);
|
await deploymentResult.HttpClient.RetryRequestAsync("/HelloWorld", r => r.StatusCode == HttpStatusCode.InternalServerError);
|
||||||
|
|
||||||
|
StopServer();
|
||||||
|
EventLogHelpers.VerifyEventLogEvent(deploymentResult, TestSink, "Could not find the assembly 'aspnetcorev2_inprocess.dll'");
|
||||||
|
}
|
||||||
|
|
||||||
|
[ConditionalTheory]
|
||||||
|
[InlineData(HostingModel.InProcess)]
|
||||||
|
[InlineData(HostingModel.OutOfProcess)]
|
||||||
|
public async Task ConfigurationTouchedStress(HostingModel hostingModel)
|
||||||
|
{
|
||||||
|
var deploymentResult = await DeployAsync(_fixture.GetBaseDeploymentParameters(hostingModel, publish: true));
|
||||||
|
|
||||||
|
await deploymentResult.AssertStarts();
|
||||||
|
var load = Helpers.StressLoad(deploymentResult.HttpClient, "/HelloWorld", response => {
|
||||||
|
var statusCode = (int)response.StatusCode;
|
||||||
|
Assert.True(statusCode == 200 || statusCode == 503, "Status code was " + statusCode);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
// ModifyWebConfig might fail if web.config is being read by IIS
|
||||||
|
RetryHelper.RetryOperation(
|
||||||
|
() => deploymentResult.ModifyWebConfig(element => {}),
|
||||||
|
e => Logger.LogError($"Failed to touch web.config : {e.Message}"),
|
||||||
|
retryCount: 3,
|
||||||
|
retryDelayMilliseconds: RetryDelay.Milliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await load;
|
||||||
|
}
|
||||||
|
catch (HttpRequestException ex) when (ex.InnerException is IOException | ex.InnerException is SocketException)
|
||||||
|
{
|
||||||
|
// IOException in InProcess is fine, just means process stopped
|
||||||
|
if (hostingModel != HostingModel.InProcess)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,11 +98,11 @@ TEST(GetAbsolutePathToDotnetFromProgramFiles, BackupWorks)
|
||||||
|
|
||||||
if (is64Bit)
|
if (is64Bit)
|
||||||
{
|
{
|
||||||
fDotnetInProgramFiles = FILE_UTILITY::CheckIfFileExists(L"C:/Program Files/dotnet/dotnet.exe");
|
fDotnetInProgramFiles = std::filesystem::is_regular_file(L"C:/Program Files/dotnet/dotnet.exe");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fDotnetInProgramFiles = FILE_UTILITY::CheckIfFileExists(L"C:/Program Files (x86)/dotnet/dotnet.exe");
|
fDotnetInProgramFiles = std::filesystem::is_regular_file(L"C:/Program Files (x86)/dotnet/dotnet.exe");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto dotnetPath = HOSTFXR_UTILITY::GetAbsolutePathToDotnetFromProgramFiles();
|
auto dotnetPath = HOSTFXR_UTILITY::GetAbsolutePathToDotnetFromProgramFiles();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue