Split handler resolution from application info (#1177)
This commit is contained in:
parent
e6330ab19b
commit
8361b8cfa9
|
|
@ -229,6 +229,7 @@
|
|||
<ClInclude Include="aspnetcore_shim_config.h" />
|
||||
<ClInclude Include="globalmodule.h" />
|
||||
<ClInclude Include="applicationmanager.h" />
|
||||
<ClInclude Include="HandlerResolver.h" />
|
||||
<ClInclude Include="proxymodule.h" />
|
||||
<ClInclude Include="ServerErrorApplication.h" />
|
||||
<ClInclude Include="ServerErrorHandler.h" />
|
||||
|
|
@ -240,6 +241,7 @@
|
|||
<ClCompile Include="aspnetcore_shim_config.cpp" />
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="globalmodule.cpp" />
|
||||
<ClCompile Include="HandlerResolver.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,271 @@
|
|||
// 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 "utility.h"
|
||||
#include "SRWExclusiveLock.h"
|
||||
#include "applicationinfo.h"
|
||||
#include "EventLog.h"
|
||||
#include "hostfxr_utility.h"
|
||||
#include "GlobalVersionUtility.h"
|
||||
#include "HandleWrapper.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_fAspnetcoreRHLoadResult(S_FALSE),
|
||||
m_loadedApplicationHostingModel(HOSTING_UNKNOWN),
|
||||
m_hRequestHandlerDll(nullptr),
|
||||
m_pfnAspNetCoreCreateApplication(nullptr)
|
||||
{
|
||||
InitializeSRWLock(&m_requestHandlerLoadLock);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerResolver::LoadRequestHandlerAssembly(STRU& location, ASPNETCORE_SHIM_CONFIG * pConfiguration)
|
||||
{
|
||||
HRESULT hr;
|
||||
STACK_STRU(struFileName, MAX_PATH);
|
||||
PCWSTR pstrHandlerDllName;
|
||||
if (pConfiguration->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
|
||||
{
|
||||
pstrHandlerDllName = s_pwzAspnetcoreInProcessRequestHandlerName;
|
||||
}
|
||||
else
|
||||
{
|
||||
pstrHandlerDllName = s_pwzAspnetcoreOutOfProcessRequestHandlerName;
|
||||
}
|
||||
|
||||
// Try to see if RH is already loaded, use GetModuleHandleEx to increment ref count
|
||||
if (!GetModuleHandleEx(0, pstrHandlerDllName, &m_hRequestHandlerDll))
|
||||
{
|
||||
if (pConfiguration->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
|
||||
{
|
||||
std::unique_ptr<HOSTFXR_OPTIONS> options;
|
||||
|
||||
RETURN_IF_FAILED(HOSTFXR_OPTIONS::Create(
|
||||
NULL,
|
||||
pConfiguration->QueryProcessPath()->QueryStr(),
|
||||
pConfiguration->QueryApplicationPhysicalPath()->QueryStr(),
|
||||
pConfiguration->QueryArguments()->QueryStr(),
|
||||
g_hEventLog,
|
||||
options));
|
||||
|
||||
RETURN_IF_FAILED(location.Copy(options->GetExeLocation()));
|
||||
|
||||
if (FAILED_LOG(hr = FindNativeAssemblyFromHostfxr(options.get(), pstrHandlerDllName, &struFileName)))
|
||||
{
|
||||
UTILITY::LogEventF(g_hEventLog,
|
||||
EVENTLOG_ERROR_TYPE,
|
||||
ASPNETCORE_EVENT_INPROCESS_RH_MISSING,
|
||||
ASPNETCORE_EVENT_INPROCESS_RH_MISSING_MSG,
|
||||
struFileName.IsEmpty() ? s_pwzAspnetcoreInProcessRequestHandlerName : struFileName.QueryStr());
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FAILED_LOG(hr = FindNativeAssemblyFromGlobalLocation(pConfiguration, pstrHandlerDllName, &struFileName)))
|
||||
{
|
||||
UTILITY::LogEventF(g_hEventLog,
|
||||
EVENTLOG_ERROR_TYPE,
|
||||
ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING,
|
||||
ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG,
|
||||
struFileName.IsEmpty() ? s_pwzAspnetcoreOutOfProcessRequestHandlerName : struFileName.QueryStr());
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFOF("Loading request handler: %S", struFileName.QueryStr());
|
||||
|
||||
m_hRequestHandlerDll = LoadLibraryW(struFileName.QueryStr());
|
||||
RETURN_LAST_ERROR_IF_NULL(m_hRequestHandlerDll);
|
||||
}
|
||||
|
||||
m_pfnAspNetCoreCreateApplication = reinterpret_cast<PFN_ASPNETCORE_CREATE_APPLICATION>(GetProcAddress(m_hRequestHandlerDll, "CreateApplication"));
|
||||
|
||||
RETURN_LAST_ERROR_IF_NULL(m_pfnAspNetCoreCreateApplication);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerResolver::GetApplicationFactory(IHttpApplication &pApplication, STRU& location, PFN_ASPNETCORE_CREATE_APPLICATION * pfnCreateApplication)
|
||||
{
|
||||
ASPNETCORE_SHIM_CONFIG pConfiguration;
|
||||
RETURN_IF_FAILED(pConfiguration.Populate(&m_pServer, &pApplication));
|
||||
|
||||
if (m_fAspnetcoreRHLoadResult == S_FALSE)
|
||||
{
|
||||
SRWExclusiveLock lock(m_requestHandlerLoadLock);
|
||||
if (m_fAspnetcoreRHLoadResult == S_FALSE)
|
||||
{
|
||||
m_loadedApplicationHostingModel = pConfiguration.QueryHostingModel();
|
||||
m_loadedApplicationId = pApplication.GetApplicationId();
|
||||
LOG_IF_FAILED(m_fAspnetcoreRHLoadResult = LoadRequestHandlerAssembly(location, &pConfiguration));
|
||||
}
|
||||
}
|
||||
|
||||
// Mixed hosting models
|
||||
if (m_loadedApplicationHostingModel != pConfiguration.QueryHostingModel())
|
||||
{
|
||||
UTILITY::LogEventF(g_hEventLog,
|
||||
EVENTLOG_ERROR_TYPE,
|
||||
ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR,
|
||||
ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG,
|
||||
pApplication.GetApplicationId(),
|
||||
pConfiguration.QueryHostingModel());
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
// Multiple in-process apps
|
||||
else if (m_loadedApplicationHostingModel == HOSTING_IN_PROCESS && m_loadedApplicationId != pApplication.GetApplicationId())
|
||||
{
|
||||
UTILITY::LogEventF(g_hEventLog,
|
||||
EVENTLOG_ERROR_TYPE,
|
||||
ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP,
|
||||
ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP_MSG,
|
||||
pApplication.GetApplicationId());
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
*pfnCreateApplication = m_pfnAspNetCoreCreateApplication;
|
||||
return m_fAspnetcoreRHLoadResult;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
HandlerResolver::FindNativeAssemblyFromGlobalLocation(
|
||||
ASPNETCORE_SHIM_CONFIG * pConfiguration,
|
||||
PCWSTR pstrHandlerDllName,
|
||||
STRU* struFilename
|
||||
)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::wstring modulePath = GlobalVersionUtility::GetModuleName(m_hModule);
|
||||
|
||||
modulePath = GlobalVersionUtility::RemoveFileNameFromFolderPath(modulePath);
|
||||
|
||||
std::wstring retval = GlobalVersionUtility::GetGlobalRequestHandlerPath(modulePath.c_str(),
|
||||
pConfiguration->QueryHandlerVersion()->QueryStr(),
|
||||
pstrHandlerDllName
|
||||
);
|
||||
|
||||
RETURN_IF_FAILED(struFilename->Copy(retval.c_str()));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
STRU struEvent;
|
||||
if (SUCCEEDED(struEvent.Copy(ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG)))
|
||||
{
|
||||
UTILITY::LogEvent(g_hEventLog,
|
||||
EVENTLOG_INFORMATION_TYPE,
|
||||
ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING,
|
||||
struEvent.QueryStr());
|
||||
}
|
||||
|
||||
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,
|
||||
STRU* struFilename
|
||||
)
|
||||
{
|
||||
STRU struApplicationFullPath;
|
||||
STRU struNativeSearchPaths;
|
||||
STRU struNativeDllLocation;
|
||||
INT intIndex = -1;
|
||||
INT intPrevIndex = 0;
|
||||
BOOL fFound = FALSE;
|
||||
DWORD dwBufferSize = 1024 * 10;
|
||||
DWORD dwRequiredBufferSize = 0;
|
||||
|
||||
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"));
|
||||
|
||||
RETURN_LAST_ERROR_IF_NULL(pFnHostFxrSearchDirectories);
|
||||
RETURN_IF_FAILED(struNativeSearchPaths.Resize(dwBufferSize));
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
auto intHostFxrExitCode = pFnHostFxrSearchDirectories(
|
||||
hostfxrOptions->GetArgc(),
|
||||
hostfxrOptions->GetArgv(),
|
||||
struNativeSearchPaths.QueryStr(),
|
||||
dwBufferSize,
|
||||
&dwRequiredBufferSize
|
||||
);
|
||||
|
||||
if (intHostFxrExitCode == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (dwRequiredBufferSize > dwBufferSize)
|
||||
{
|
||||
dwBufferSize = dwRequiredBufferSize + 1; // for null terminator
|
||||
|
||||
RETURN_IF_FAILED(struNativeSearchPaths.Resize(dwBufferSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Log "Error finding native search directories from aspnetcore application.
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_IF_FAILED(struNativeSearchPaths.SyncWithBuffer());
|
||||
|
||||
fFound = FALSE;
|
||||
|
||||
// The native search directories are semicolon delimited.
|
||||
// Split on semicolons, append aspnetcorerh.dll, and check if the file exists.
|
||||
while ((intIndex = struNativeSearchPaths.IndexOf(L";", intPrevIndex)) != -1)
|
||||
{
|
||||
RETURN_IF_FAILED(struNativeDllLocation.Copy(&struNativeSearchPaths.QueryStr()[intPrevIndex], intIndex - intPrevIndex));
|
||||
|
||||
if (!struNativeDllLocation.EndsWith(L"\\"))
|
||||
{
|
||||
RETURN_IF_FAILED(struNativeDllLocation.Append(L"\\"));
|
||||
}
|
||||
|
||||
RETURN_IF_FAILED(struNativeDllLocation.Append(libraryName));
|
||||
|
||||
if (UTILITY::CheckIfFileExists(struNativeDllLocation.QueryStr()))
|
||||
{
|
||||
RETURN_IF_FAILED(struFilename->Copy(struNativeDllLocation));
|
||||
fFound = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
intPrevIndex = intIndex + 1;
|
||||
}
|
||||
|
||||
if (!fFound)
|
||||
{
|
||||
return HRESULT_FROM_WIN32(ERROR_DLL_NOT_FOUND);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
// 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 "aspnetcore_shim_config.h"
|
||||
#include "hostfxroptions.h"
|
||||
#include <memory>
|
||||
#include "iapplication.h"
|
||||
#include <string>
|
||||
#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 HandlerResolver
|
||||
{
|
||||
public:
|
||||
HandlerResolver(HMODULE hModule, IHttpServer &pServer);
|
||||
HRESULT GetApplicationFactory(IHttpApplication &pApplication, STRU& location, PFN_ASPNETCORE_CREATE_APPLICATION *pfnCreateApplication);
|
||||
|
||||
private:
|
||||
HRESULT LoadRequestHandlerAssembly(STRU& location, ASPNETCORE_SHIM_CONFIG * pConfiguration);
|
||||
HRESULT FindNativeAssemblyFromGlobalLocation(ASPNETCORE_SHIM_CONFIG * pConfiguration, PCWSTR libraryName, STRU* location);
|
||||
HRESULT FindNativeAssemblyFromHostfxr(HOSTFXR_OPTIONS* hostfxrOptions, PCWSTR libraryName, STRU* location);
|
||||
|
||||
HMODULE m_hModule;
|
||||
IHttpServer &m_pServer;
|
||||
|
||||
SRWLOCK m_requestHandlerLoadLock {};
|
||||
// S_FALSE - not loaded, S_OK - loaded, everything else - error
|
||||
HRESULT m_fAspnetcoreRHLoadResult;
|
||||
std::wstring m_loadedApplicationId;
|
||||
APP_HOSTING_MODEL m_loadedApplicationHostingModel;
|
||||
HandleWrapper<ModuleHandleTraits> m_hRequestHandlerDll;
|
||||
HandleWrapper<ModuleHandleTraits> m_hHostFxrDll;
|
||||
|
||||
PFN_ASPNETCORE_CREATE_APPLICATION m_pfnAspNetCoreCreateApplication;
|
||||
|
||||
static const PCWSTR s_pwzAspnetcoreInProcessRequestHandlerName;
|
||||
static const PCWSTR s_pwzAspnetcoreOutOfProcessRequestHandlerName;
|
||||
};
|
||||
|
||||
|
|
@ -17,18 +17,6 @@
|
|||
#include "ServerErrorApplication.h"
|
||||
#include "AppOfflineApplication.h"
|
||||
|
||||
extern HINSTANCE g_hModule;
|
||||
|
||||
const PCWSTR APPLICATION_INFO::s_pwzAspnetcoreInProcessRequestHandlerName = L"aspnetcorev2_inprocess.dll";
|
||||
const PCWSTR APPLICATION_INFO::s_pwzAspnetcoreOutOfProcessRequestHandlerName = L"aspnetcorev2_outofprocess.dll";
|
||||
|
||||
SRWLOCK APPLICATION_INFO::s_requestHandlerLoadLock {};
|
||||
bool APPLICATION_INFO::s_fAspnetcoreRHAssemblyLoaded = false;
|
||||
bool APPLICATION_INFO::s_fAspnetcoreRHLoadedError = false;
|
||||
HMODULE APPLICATION_INFO::s_hAspnetCoreRH = nullptr;
|
||||
|
||||
PFN_ASPNETCORE_CREATE_APPLICATION APPLICATION_INFO::s_pfnAspNetCoreCreateApplication = nullptr;
|
||||
|
||||
APPLICATION_INFO::~APPLICATION_INFO()
|
||||
{
|
||||
ShutDownApplication();
|
||||
|
|
@ -36,13 +24,13 @@ APPLICATION_INFO::~APPLICATION_INFO()
|
|||
|
||||
HRESULT
|
||||
APPLICATION_INFO::Initialize(
|
||||
_In_ IHttpApplication &pApplication
|
||||
_In_ IHttpApplication &pApplication,
|
||||
HandlerResolver * pHandlerResolver
|
||||
)
|
||||
{
|
||||
m_pConfiguration.reset(new ASPNETCORE_SHIM_CONFIG());
|
||||
RETURN_IF_FAILED(m_pConfiguration->Populate(&m_pServer, &pApplication));
|
||||
m_handlerResolver = pHandlerResolver;
|
||||
RETURN_IF_FAILED(m_struConfigPath.Copy(pApplication.GetAppConfigPath()));
|
||||
RETURN_IF_FAILED(m_struInfoKey.Copy(pApplication.GetApplicationId()));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
@ -84,20 +72,15 @@ APPLICATION_INFO::GetOrCreateApplication(
|
|||
else
|
||||
{
|
||||
STRU struExeLocation;
|
||||
FINISHED_IF_FAILED(FindRequestHandlerAssembly(struExeLocation));
|
||||
|
||||
if (m_pfnAspNetCoreCreateApplication == NULL)
|
||||
{
|
||||
FINISHED(HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION));
|
||||
}
|
||||
|
||||
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");
|
||||
IAPPLICATION * newApplication;
|
||||
FINISHED_IF_FAILED(m_pfnAspNetCoreCreateApplication(
|
||||
FINISHED_IF_FAILED(pfnAspNetCoreCreateApplication(
|
||||
&m_pServer,
|
||||
&httpApplication,
|
||||
parameters.data(),
|
||||
|
|
@ -130,266 +113,6 @@ Finished:
|
|||
return hr;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
APPLICATION_INFO::FindRequestHandlerAssembly(STRU& location)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
PCWSTR pstrHandlerDllName;
|
||||
STACK_STRU(struFileName, 256);
|
||||
|
||||
if (s_fAspnetcoreRHLoadedError)
|
||||
{
|
||||
FINISHED(E_APPLICATION_ACTIVATION_EXEC_FAILURE);
|
||||
}
|
||||
else if (!s_fAspnetcoreRHAssemblyLoaded)
|
||||
{
|
||||
SRWExclusiveLock lock(s_requestHandlerLoadLock);
|
||||
if (s_fAspnetcoreRHLoadedError)
|
||||
{
|
||||
FINISHED(E_APPLICATION_ACTIVATION_EXEC_FAILURE);
|
||||
}
|
||||
if (s_fAspnetcoreRHAssemblyLoaded)
|
||||
{
|
||||
FINISHED(S_OK);
|
||||
}
|
||||
|
||||
if (m_pConfiguration->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
|
||||
{
|
||||
pstrHandlerDllName = s_pwzAspnetcoreInProcessRequestHandlerName;
|
||||
}
|
||||
else
|
||||
{
|
||||
pstrHandlerDllName = s_pwzAspnetcoreOutOfProcessRequestHandlerName;
|
||||
}
|
||||
|
||||
// Try to see if RH is already loaded
|
||||
s_hAspnetCoreRH = GetModuleHandle(pstrHandlerDllName);
|
||||
|
||||
if (s_hAspnetCoreRH == NULL)
|
||||
{
|
||||
if (m_pConfiguration->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
|
||||
{
|
||||
std::unique_ptr<HOSTFXR_OPTIONS> options;
|
||||
|
||||
FINISHED_IF_FAILED(HOSTFXR_OPTIONS::Create(
|
||||
NULL,
|
||||
m_pConfiguration->QueryProcessPath()->QueryStr(),
|
||||
m_pConfiguration->QueryApplicationPhysicalPath()->QueryStr(),
|
||||
m_pConfiguration->QueryArguments()->QueryStr(),
|
||||
g_hEventLog,
|
||||
options));
|
||||
|
||||
FINISHED_IF_FAILED(location.Copy(options->GetExeLocation()));
|
||||
|
||||
if (FAILED_LOG(hr = FindNativeAssemblyFromHostfxr(options.get(), pstrHandlerDllName, &struFileName)))
|
||||
{
|
||||
UTILITY::LogEventF(g_hEventLog,
|
||||
EVENTLOG_ERROR_TYPE,
|
||||
ASPNETCORE_EVENT_INPROCESS_RH_MISSING,
|
||||
ASPNETCORE_EVENT_INPROCESS_RH_MISSING_MSG,
|
||||
struFileName.IsEmpty() ? s_pwzAspnetcoreInProcessRequestHandlerName : struFileName.QueryStr());
|
||||
|
||||
FINISHED(hr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FAILED_LOG(hr = FindNativeAssemblyFromGlobalLocation(pstrHandlerDllName, &struFileName)))
|
||||
{
|
||||
UTILITY::LogEventF(g_hEventLog,
|
||||
EVENTLOG_ERROR_TYPE,
|
||||
ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING,
|
||||
ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG,
|
||||
struFileName.IsEmpty() ? s_pwzAspnetcoreOutOfProcessRequestHandlerName : struFileName.QueryStr());
|
||||
|
||||
FINISHED(hr);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFOF("Loading request handler: %S", struFileName.QueryStr());
|
||||
|
||||
s_hAspnetCoreRH = LoadLibraryW(struFileName.QueryStr());
|
||||
|
||||
if (s_hAspnetCoreRH == NULL)
|
||||
{
|
||||
FINISHED(HRESULT_FROM_WIN32(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
s_pfnAspNetCoreCreateApplication = (PFN_ASPNETCORE_CREATE_APPLICATION)
|
||||
GetProcAddress(s_hAspnetCoreRH, "CreateApplication");
|
||||
if (s_pfnAspNetCoreCreateApplication == NULL)
|
||||
{
|
||||
FINISHED(HRESULT_FROM_WIN32(GetLastError()));
|
||||
}
|
||||
|
||||
s_fAspnetcoreRHAssemblyLoaded = TRUE;
|
||||
}
|
||||
|
||||
Finished:
|
||||
//
|
||||
// Question: we remember the load failure so that we will not try again.
|
||||
// User needs to check whether the fuction pointer is NULL
|
||||
//
|
||||
m_pfnAspNetCoreCreateApplication = s_pfnAspNetCoreCreateApplication;
|
||||
|
||||
if (!s_fAspnetcoreRHLoadedError && FAILED(hr))
|
||||
{
|
||||
s_fAspnetcoreRHLoadedError = TRUE;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
APPLICATION_INFO::FindNativeAssemblyFromGlobalLocation(
|
||||
PCWSTR pstrHandlerDllName,
|
||||
STRU* struFilename
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
try
|
||||
{
|
||||
std::wstring modulePath = GlobalVersionUtility::GetModuleName(g_hModule);
|
||||
|
||||
modulePath = GlobalVersionUtility::RemoveFileNameFromFolderPath(modulePath);
|
||||
|
||||
std::wstring retval = GlobalVersionUtility::GetGlobalRequestHandlerPath(modulePath.c_str(),
|
||||
m_pConfiguration->QueryHandlerVersion()->QueryStr(),
|
||||
pstrHandlerDllName
|
||||
);
|
||||
|
||||
RETURN_IF_FAILED(struFilename->Copy(retval.c_str()));
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
STRU struEvent;
|
||||
if (SUCCEEDED(struEvent.Copy(ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG))
|
||||
&& SUCCEEDED(struEvent.AppendA(e.what())))
|
||||
{
|
||||
UTILITY::LogEvent(g_hEventLog,
|
||||
EVENTLOG_INFORMATION_TYPE,
|
||||
ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING,
|
||||
struEvent.QueryStr());
|
||||
}
|
||||
|
||||
hr = E_FAIL;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
hr = E_FAIL;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
//
|
||||
// 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
|
||||
APPLICATION_INFO::FindNativeAssemblyFromHostfxr(
|
||||
HOSTFXR_OPTIONS* hostfxrOptions,
|
||||
PCWSTR libraryName,
|
||||
STRU* struFilename
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
STRU struApplicationFullPath;
|
||||
STRU struNativeSearchPaths;
|
||||
STRU struNativeDllLocation;
|
||||
HMODULE hmHostFxrDll = NULL;
|
||||
INT intHostFxrExitCode = 0;
|
||||
INT intIndex = -1;
|
||||
INT intPrevIndex = 0;
|
||||
BOOL fFound = FALSE;
|
||||
DWORD dwBufferSize = 1024 * 10;
|
||||
DWORD dwRequiredBufferSize = 0;
|
||||
|
||||
DBG_ASSERT(struFilename != NULL);
|
||||
|
||||
FINISHED_LAST_ERROR_IF_NULL(hmHostFxrDll = LoadLibraryW(hostfxrOptions->GetHostFxrLocation()));
|
||||
|
||||
hostfxr_get_native_search_directories_fn pFnHostFxrSearchDirectories = (hostfxr_get_native_search_directories_fn)
|
||||
GetProcAddress(hmHostFxrDll, "hostfxr_get_native_search_directories");
|
||||
|
||||
if (pFnHostFxrSearchDirectories == NULL)
|
||||
{
|
||||
// Host fxr version is incorrect (need a higher version).
|
||||
// TODO log error
|
||||
FINISHED(E_FAIL);
|
||||
}
|
||||
|
||||
FINISHED_IF_FAILED(hr = struNativeSearchPaths.Resize(dwBufferSize));
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
intHostFxrExitCode = pFnHostFxrSearchDirectories(
|
||||
hostfxrOptions->GetArgc(),
|
||||
hostfxrOptions->GetArgv(),
|
||||
struNativeSearchPaths.QueryStr(),
|
||||
dwBufferSize,
|
||||
&dwRequiredBufferSize
|
||||
);
|
||||
|
||||
if (intHostFxrExitCode == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (dwRequiredBufferSize > dwBufferSize)
|
||||
{
|
||||
dwBufferSize = dwRequiredBufferSize + 1; // for null terminator
|
||||
|
||||
FINISHED_IF_FAILED(struNativeSearchPaths.Resize(dwBufferSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Log "Error finding native search directories from aspnetcore application.
|
||||
FINISHED(E_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
FINISHED_IF_FAILED(struNativeSearchPaths.SyncWithBuffer());
|
||||
|
||||
fFound = FALSE;
|
||||
|
||||
// The native search directories are semicolon delimited.
|
||||
// Split on semicolons, append aspnetcorerh.dll, and check if the file exists.
|
||||
while ((intIndex = struNativeSearchPaths.IndexOf(L";", intPrevIndex)) != -1)
|
||||
{
|
||||
FINISHED_IF_FAILED(struNativeDllLocation.Copy(&struNativeSearchPaths.QueryStr()[intPrevIndex], intIndex - intPrevIndex));
|
||||
|
||||
if (!struNativeDllLocation.EndsWith(L"\\"))
|
||||
{
|
||||
FINISHED_IF_FAILED(struNativeDllLocation.Append(L"\\"));
|
||||
}
|
||||
|
||||
FINISHED_IF_FAILED(struNativeDllLocation.Append(libraryName));
|
||||
|
||||
if (UTILITY::CheckIfFileExists(struNativeDllLocation.QueryStr()))
|
||||
{
|
||||
FINISHED_IF_FAILED(struFilename->Copy(struNativeDllLocation));
|
||||
fFound = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
intPrevIndex = intIndex + 1;
|
||||
}
|
||||
|
||||
if (!fFound)
|
||||
{
|
||||
FINISHED(E_FAIL);
|
||||
}
|
||||
|
||||
Finished:
|
||||
if (FAILED(hr) && hmHostFxrDll != NULL)
|
||||
{
|
||||
FreeLibrary(hmHostFxrDll);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
VOID
|
||||
APPLICATION_INFO::RecycleApplication()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,31 +9,20 @@
|
|||
#include "aspnetcore_shim_config.h"
|
||||
#include "iapplication.h"
|
||||
#include "SRWSharedLock.h"
|
||||
#include "HandlerResolver.h"
|
||||
|
||||
#define API_BUFFER_TOO_SMALL 0x80008098
|
||||
|
||||
typedef
|
||||
HRESULT
|
||||
(WINAPI * PFN_ASPNETCORE_CREATE_APPLICATION)(
|
||||
_In_ IHttpServer *pServer,
|
||||
_In_ IHttpApplication *pHttpApplication,
|
||||
_In_ APPLICATION_PARAMETER *pParameters,
|
||||
_In_ DWORD nParameters,
|
||||
_Out_ IAPPLICATION **pApplication
|
||||
);
|
||||
|
||||
extern BOOL g_fRecycleProcessCalled;
|
||||
|
||||
class APPLICATION_INFO
|
||||
{
|
||||
public:
|
||||
|
||||
APPLICATION_INFO(_In_ IHttpServer &pServer) :
|
||||
APPLICATION_INFO(IHttpServer &pServer) :
|
||||
m_pServer(pServer),
|
||||
m_cRefs(1),
|
||||
m_fValid(FALSE),
|
||||
m_pConfiguration(nullptr),
|
||||
m_pfnAspNetCoreCreateApplication(NULL)
|
||||
m_handlerResolver(nullptr)
|
||||
{
|
||||
InitializeSRWLock(&m_applicationLock);
|
||||
}
|
||||
|
|
@ -44,19 +33,25 @@ public:
|
|||
return m_struInfoKey.QueryStr();
|
||||
}
|
||||
|
||||
STRU*
|
||||
QueryConfigPath()
|
||||
{
|
||||
return &m_struConfigPath;
|
||||
}
|
||||
|
||||
virtual
|
||||
~APPLICATION_INFO();
|
||||
|
||||
static
|
||||
|
||||
static
|
||||
void
|
||||
StaticInitialize()
|
||||
{
|
||||
InitializeSRWLock(&s_requestHandlerLoadLock);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Initialize(
|
||||
_In_ IHttpApplication &pApplication
|
||||
IHttpApplication &pApplication,
|
||||
HandlerResolver *pHandlerResolver
|
||||
);
|
||||
|
||||
VOID
|
||||
|
|
@ -74,24 +69,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
BOOL
|
||||
IsValid()
|
||||
{
|
||||
return m_fValid;
|
||||
}
|
||||
|
||||
VOID
|
||||
MarkValid()
|
||||
{
|
||||
m_fValid = TRUE;
|
||||
}
|
||||
|
||||
ASPNETCORE_SHIM_CONFIG*
|
||||
QueryConfig()
|
||||
{
|
||||
return m_pConfiguration.get();
|
||||
}
|
||||
|
||||
VOID
|
||||
RecycleApplication();
|
||||
|
||||
|
|
@ -105,31 +82,17 @@ public:
|
|||
);
|
||||
|
||||
private:
|
||||
HRESULT FindRequestHandlerAssembly(STRU& location);
|
||||
HRESULT FindNativeAssemblyFromGlobalLocation(PCWSTR libraryName, STRU* location);
|
||||
HRESULT FindNativeAssemblyFromHostfxr(HOSTFXR_OPTIONS* hostfxrOptions, PCWSTR libraryName, STRU* location);
|
||||
|
||||
static DWORD WINAPI DoRecycleApplication(LPVOID lpParam);
|
||||
|
||||
mutable LONG m_cRefs;
|
||||
STRU m_struConfigPath;
|
||||
STRU m_struInfoKey;
|
||||
BOOL m_fValid;
|
||||
SRWLOCK m_applicationLock;
|
||||
IHttpServer &m_pServer;
|
||||
PFN_ASPNETCORE_CREATE_APPLICATION m_pfnAspNetCoreCreateApplication;
|
||||
|
||||
std::unique_ptr<ASPNETCORE_SHIM_CONFIG> m_pConfiguration;
|
||||
HandlerResolver *m_handlerResolver;
|
||||
|
||||
std::unique_ptr<IAPPLICATION, IAPPLICATION_DELETER> m_pApplication;
|
||||
|
||||
|
||||
static const PCWSTR s_pwzAspnetcoreInProcessRequestHandlerName;
|
||||
static const PCWSTR s_pwzAspnetcoreOutOfProcessRequestHandlerName;
|
||||
|
||||
static SRWLOCK s_requestHandlerLoadLock;
|
||||
static bool s_fAspnetcoreRHAssemblyLoaded;
|
||||
static bool s_fAspnetcoreRHLoadedError;
|
||||
static HMODULE s_hAspnetCoreRH;
|
||||
static PFN_ASPNETCORE_CREATE_APPLICATION s_pfnAspNetCoreCreateApplication;
|
||||
};
|
||||
|
||||
class APPLICATION_INFO_HASH :
|
||||
|
|
|
|||
|
|
@ -27,10 +27,7 @@ APPLICATION_MANAGER::GetOrCreateApplicationInfo(
|
|||
{
|
||||
HRESULT hr = S_OK;
|
||||
APPLICATION_INFO *pApplicationInfo = NULL;
|
||||
BOOL fMixedHostingModelError = FALSE;
|
||||
BOOL fDuplicatedInProcessApp = FALSE;
|
||||
PCWSTR pszApplicationId = NULL;
|
||||
APP_HOSTING_MODEL hostingModel = HOSTING_UNKNOWN;
|
||||
|
||||
STACK_STRU ( strEventMsg, 256 );
|
||||
|
||||
|
|
@ -80,34 +77,7 @@ APPLICATION_MANAGER::GetOrCreateApplicationInfo(
|
|||
|
||||
pApplicationInfo = new APPLICATION_INFO(m_pHttpServer);
|
||||
|
||||
FINISHED_IF_FAILED(pApplicationInfo->Initialize(pApplication));
|
||||
|
||||
hostingModel = pApplicationInfo->QueryConfig()->QueryHostingModel();
|
||||
|
||||
if (m_pApplicationInfoHash->Count() == 0)
|
||||
{
|
||||
m_hostingModel = hostingModel;
|
||||
pApplicationInfo->MarkValid();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hostingModel == HOSTING_OUT_PROCESS && hostingModel == m_hostingModel)
|
||||
{
|
||||
pApplicationInfo->MarkValid();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hostingModel != m_hostingModel)
|
||||
{
|
||||
fMixedHostingModelError = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
fDuplicatedInProcessApp = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FINISHED_IF_FAILED(pApplicationInfo->Initialize(pApplication, &m_handlerResolver));
|
||||
FINISHED_IF_FAILED(m_pApplicationInfoHash->InsertRecord(pApplicationInfo));
|
||||
|
||||
*ppApplicationInfo = pApplicationInfo;
|
||||
|
|
@ -115,26 +85,6 @@ APPLICATION_MANAGER::GetOrCreateApplicationInfo(
|
|||
}
|
||||
Finished:
|
||||
|
||||
// log the error
|
||||
if (fDuplicatedInProcessApp)
|
||||
{
|
||||
UTILITY::LogEventF(g_hEventLog,
|
||||
EVENTLOG_ERROR_TYPE,
|
||||
ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP,
|
||||
ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP_MSG,
|
||||
pszApplicationId);
|
||||
|
||||
}
|
||||
else if (fMixedHostingModelError)
|
||||
{
|
||||
UTILITY::LogEventF(g_hEventLog,
|
||||
EVENTLOG_ERROR_TYPE,
|
||||
ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR,
|
||||
ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG,
|
||||
pszApplicationId,
|
||||
hostingModel);
|
||||
}
|
||||
|
||||
if (pApplicationInfo != NULL)
|
||||
{
|
||||
pApplicationInfo->DereferenceApplicationInfo();
|
||||
|
|
@ -160,7 +110,7 @@ APPLICATION_MANAGER::FindConfigChangedApplication(
|
|||
// 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->QueryConfig()->QueryConfigPath();
|
||||
STRU* pstruConfigPath = pEntry->QueryConfigPath();
|
||||
|
||||
// check if the application path contains our app/subapp by seeing if the config path
|
||||
// starts with the notification path.
|
||||
|
|
|
|||
|
|
@ -85,10 +85,10 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
static HRESULT StaticInitialize(IHttpServer& pHttpServer)
|
||||
static HRESULT StaticInitialize(HMODULE hModule, IHttpServer& pHttpServer)
|
||||
{
|
||||
assert(!sm_pApplicationManager);
|
||||
sm_pApplicationManager = new APPLICATION_MANAGER(pHttpServer);
|
||||
sm_pApplicationManager = new APPLICATION_MANAGER(hModule, pHttpServer);
|
||||
RETURN_IF_FAILED(sm_pApplicationManager->Initialize());
|
||||
|
||||
APPLICATION_INFO::StaticInitialize();
|
||||
|
|
@ -110,19 +110,21 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
APPLICATION_MANAGER(IHttpServer& pHttpServer) :
|
||||
APPLICATION_MANAGER(HMODULE hModule, IHttpServer& pHttpServer) :
|
||||
m_pApplicationInfoHash(NULL),
|
||||
m_hostingModel(HOSTING_UNKNOWN),
|
||||
m_fDebugInitialize(FALSE),
|
||||
m_pHttpServer(pHttpServer)
|
||||
m_pHttpServer(pHttpServer),
|
||||
m_handlerResolver(hModule, pHttpServer)
|
||||
{
|
||||
InitializeSRWLock(&m_srwLock);
|
||||
}
|
||||
|
||||
APPLICATION_INFO_HASH *m_pApplicationInfoHash;
|
||||
static APPLICATION_MANAGER *sm_pApplicationManager;
|
||||
SRWLOCK m_srwLock;
|
||||
SRWLOCK m_srwLock {};
|
||||
APP_HOSTING_MODEL m_hostingModel;
|
||||
BOOL m_fDebugInitialize;
|
||||
IHttpServer &m_pHttpServer;
|
||||
HandlerResolver m_handlerResolver;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,13 +20,14 @@ ASPNETCORE_SHIM_CONFIG::Populate(
|
|||
CComPtr<IAppHostElement> pAspNetCoreElement;
|
||||
|
||||
pAdminManager = pHttpServer->GetAdminManager();
|
||||
RETURN_IF_FAILED(m_struConfigPath.Copy(pHttpApplication->GetAppConfigPath()));
|
||||
RETURN_IF_FAILED(m_struApplicationPhysicalPath.Copy(pHttpApplication->GetApplicationPhysicalPath()));
|
||||
|
||||
const CComBSTR bstrAspNetCoreSection = CS_ASPNETCORE_SECTION;
|
||||
|
||||
const CComBSTR applicationConfigPath = pHttpApplication->GetAppConfigPath();
|
||||
|
||||
RETURN_IF_FAILED(pAdminManager->GetAdminSection(bstrAspNetCoreSection,
|
||||
m_struConfigPath.QueryStr(),
|
||||
applicationConfigPath,
|
||||
&pAspNetCoreElement));
|
||||
|
||||
RETURN_IF_FAILED(GetElementStringProperty(pAspNetCoreElement,
|
||||
|
|
|
|||
|
|
@ -38,12 +38,6 @@ public:
|
|||
return &m_struApplicationPhysicalPath;
|
||||
}
|
||||
|
||||
STRU*
|
||||
QueryConfigPath()
|
||||
{
|
||||
return &m_struConfigPath;
|
||||
}
|
||||
|
||||
STRU*
|
||||
QueryProcessPath()
|
||||
{
|
||||
|
|
@ -78,7 +72,6 @@ private:
|
|||
STRU m_struArguments;
|
||||
STRU m_struProcessPath;
|
||||
STRU m_struApplicationPhysicalPath;
|
||||
STRU m_struConfigPath;
|
||||
APP_HOSTING_MODEL m_hostingModel;
|
||||
STRU m_struHostFxrLocation;
|
||||
STRU m_struHandlerVersion;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ DECLARE_DEBUG_PRINT_OBJECT("aspnetcorev2.dll");
|
|||
HANDLE g_hEventLog = NULL;
|
||||
BOOL g_fRecycleProcessCalled = FALSE;
|
||||
BOOL g_fInShutdown = FALSE;
|
||||
HINSTANCE g_hServerModule;
|
||||
|
||||
VOID
|
||||
StaticCleanup()
|
||||
|
|
@ -40,6 +41,7 @@ BOOL WINAPI DllMain(HMODULE hModule,
|
|||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
g_hServerModule = hModule;
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
DebugInitialize(hModule);
|
||||
break;
|
||||
|
|
@ -157,7 +159,7 @@ HRESULT
|
|||
|
||||
pFactory = NULL;
|
||||
|
||||
FINISHED_IF_FAILED(APPLICATION_MANAGER::StaticInitialize(*pHttpServer));
|
||||
FINISHED_IF_FAILED(APPLICATION_MANAGER::StaticInitialize(g_hServerModule, *pHttpServer));
|
||||
|
||||
pGlobalModule = NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -89,13 +89,6 @@ ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler(
|
|||
pHttpContext,
|
||||
&m_pApplicationInfo));
|
||||
|
||||
if (!m_pApplicationInfo->IsValid())
|
||||
{
|
||||
// Application cannot be started due to wrong hosting mode
|
||||
// the error should already been logged to window event log for the first request
|
||||
FINISHED(E_APPLICATION_ACTIVATION_EXEC_FAILURE);
|
||||
}
|
||||
|
||||
DBG_ASSERT(pHttpContext);
|
||||
|
||||
std::unique_ptr<IAPPLICATION, IAPPLICATION_DELETER> pApplication;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,13 @@ struct NullHandleTraits
|
|||
static void Close(HANDLE handle) { CloseHandle(handle); }
|
||||
};
|
||||
|
||||
struct ModuleHandleTraits
|
||||
{
|
||||
using HandleType = HMODULE;
|
||||
static constexpr HMODULE DefaultHandle = NULL;
|
||||
static void Close(HMODULE handle) { FreeModule(handle); }
|
||||
};
|
||||
|
||||
template<typename traits>
|
||||
class HandleWrapper
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ using System.Xml.Linq;
|
|||
|
||||
namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
|
||||
{
|
||||
internal static class XElementExtensions
|
||||
public static class XElementExtensions
|
||||
{
|
||||
public static XElement RequiredElement(this XElement element, string name)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,141 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
[Collection(PublishedSitesCollection.Name)]
|
||||
public class MultiApplicationTests : IISFunctionalTestBase
|
||||
{
|
||||
private readonly PublishedSitesFixture _fixture;
|
||||
|
||||
private PublishedApplication _publishedApplication;
|
||||
private PublishedApplication _rootApplication;
|
||||
|
||||
public MultiApplicationTests(PublishedSitesFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task RunsTwoOutOfProcessApps()
|
||||
{
|
||||
var parameters = _fixture.GetBaseDeploymentParameters(HostingModel.OutOfProcess, publish: true);
|
||||
parameters.ServerConfigActionList.Add(DuplicateApplication);
|
||||
var result = await DeployAsync(parameters);
|
||||
var id1 = await result.HttpClient.GetStringAsync("/app1/ProcessId");
|
||||
var id2 = await result.HttpClient.GetStringAsync("/app2/ProcessId");
|
||||
Assert.NotEqual(id2, id1);
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task FailsAndLogsWhenRunningTwoInProcessApps()
|
||||
{
|
||||
var parameters = _fixture.GetBaseDeploymentParameters(HostingModel.InProcess, publish: true);
|
||||
parameters.ServerConfigActionList.Add(DuplicateApplication);
|
||||
var result = await DeployAsync(parameters);
|
||||
var result1 = await result.HttpClient.GetAsync("/app1/HelloWorld");
|
||||
var result2 = await result.HttpClient.GetAsync("/app2/HelloWorld");
|
||||
Assert.Equal(200, (int)result1.StatusCode);
|
||||
Assert.Equal(500, (int)result2.StatusCode);
|
||||
StopServer();
|
||||
EventLogHelpers.VerifyEventLogEvent(TestSink, "Only one inprocess application is allowed per IIS application pool");
|
||||
}
|
||||
|
||||
[ConditionalTheory]
|
||||
[InlineData(HostingModel.OutOfProcess)]
|
||||
[InlineData(HostingModel.InProcess)]
|
||||
public async Task FailsAndLogsEventLogForMixedHostingModel(HostingModel firstApp)
|
||||
{
|
||||
var parameters = _fixture.GetBaseDeploymentParameters(firstApp, publish: true);
|
||||
parameters.ServerConfigActionList.Add(DuplicateApplication);
|
||||
var result = await DeployAsync(parameters);
|
||||
|
||||
// Modify hosting model of other app to be the opposite
|
||||
var otherApp = firstApp == HostingModel.InProcess ? HostingModel.OutOfProcess : HostingModel.InProcess;
|
||||
SetHostingModel(_publishedApplication.Path, otherApp);
|
||||
|
||||
var result1 = await result.HttpClient.GetAsync("/app1/HelloWorld");
|
||||
var result2 = await result.HttpClient.GetAsync("/app2/HelloWorld");
|
||||
Assert.Equal(200, (int)result1.StatusCode);
|
||||
Assert.Equal(500, (int)result2.StatusCode);
|
||||
StopServer();
|
||||
EventLogHelpers.VerifyEventLogEvent(TestSink, "Mixed hosting model is not supported.");
|
||||
}
|
||||
|
||||
private void SetHostingModel(string directory, HostingModel model)
|
||||
{
|
||||
var webConfigLocation = GetWebConfigLocation(directory);
|
||||
XDocument webConfig = XDocument.Load(webConfigLocation);
|
||||
webConfig.Root
|
||||
.GetOrAdd("system.webServer")
|
||||
.GetOrAdd("aspNetCore")
|
||||
.SetAttributeValue("hostingModel", model.ToString());
|
||||
webConfig.Save(webConfigLocation);
|
||||
}
|
||||
|
||||
private void DuplicateApplication(XElement config, string contentRoot)
|
||||
{
|
||||
var siteElement = config
|
||||
.RequiredElement("system.applicationHost")
|
||||
.RequiredElement("sites")
|
||||
.RequiredElement("site");
|
||||
|
||||
var application = siteElement
|
||||
.RequiredElement("application");
|
||||
|
||||
application.SetAttributeValue("path", "/app1");
|
||||
|
||||
var source = new DirectoryInfo(contentRoot);
|
||||
|
||||
var destination = new DirectoryInfo(contentRoot + "anotherApp");
|
||||
destination.Create();
|
||||
Helpers.CopyFiles(source, destination, Logger);
|
||||
|
||||
_publishedApplication = new PublishedApplication(destination.FullName, Logger);
|
||||
|
||||
var newApplication = new XElement(application);
|
||||
newApplication.SetAttributeValue("path", "/app2");
|
||||
newApplication.RequiredElement("virtualDirectory")
|
||||
.SetAttributeValue("physicalPath", destination.FullName);
|
||||
|
||||
siteElement.Add(newApplication);
|
||||
|
||||
// IIS Express requires root application to exist
|
||||
var rootApplicationDirectory = new DirectoryInfo(contentRoot + "rootApp");
|
||||
rootApplicationDirectory.Create();
|
||||
|
||||
_rootApplication = new PublishedApplication(rootApplicationDirectory.FullName, Logger);
|
||||
File.WriteAllText(GetWebConfigLocation(rootApplicationDirectory.FullName), "<configuration></configuration>");
|
||||
|
||||
var rootApplication = new XElement(application);
|
||||
rootApplication.SetAttributeValue("path", "/");
|
||||
rootApplication.RequiredElement("virtualDirectory")
|
||||
.SetAttributeValue("physicalPath", rootApplicationDirectory.FullName);
|
||||
|
||||
siteElement.Add(rootApplication);
|
||||
}
|
||||
|
||||
private static string GetWebConfigLocation(string siteRoot)
|
||||
{
|
||||
return Path.Combine(siteRoot, "web.config");
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
_rootApplication.Dispose();
|
||||
_publishedApplication.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,16 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
public static void VerifyEventLogEvent(ITestSink testSink, string expectedRegexMatchString)
|
||||
{
|
||||
var eventLogRegex = new Regex($"Event Log: {expectedRegexMatchString}");
|
||||
Assert.Contains(testSink.Writes, context => eventLogRegex.IsMatch(context.Message));
|
||||
|
||||
int count = 0;
|
||||
foreach (var context in testSink.Writes)
|
||||
{
|
||||
if (eventLogRegex.IsMatch(context.Message))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
Assert.Equal(1, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ using System.Xml.Linq;
|
|||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
|
|
@ -25,7 +26,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
public static string GetInProcessTestSitesPath() => GetTestWebSitePath("InProcessWebSite");
|
||||
|
||||
public static string GetOutOfProcessTestSitesPath() => GetTestWebSitePath("OutOfProcessWebSite");
|
||||
|
||||
|
||||
|
||||
public static async Task AssertStarts(IISDeploymentResult deploymentResult, string path = "/HelloWorld")
|
||||
{
|
||||
|
|
@ -57,5 +58,20 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
|
||||
public static void CopyFiles(DirectoryInfo source, DirectoryInfo target, ILogger logger)
|
||||
{
|
||||
foreach (DirectoryInfo directoryInfo in source.GetDirectories())
|
||||
{
|
||||
CopyFiles(directoryInfo, target.CreateSubdirectory(directoryInfo.Name), logger);
|
||||
}
|
||||
logger.LogDebug($"Processing {target.FullName}");
|
||||
foreach (FileInfo fileInfo in source.GetFiles())
|
||||
{
|
||||
logger.LogDebug($" Copying {fileInfo.Name}");
|
||||
var destFileName = Path.Combine(target.FullName, fileInfo.Name);
|
||||
fileInfo.CopyTo(destFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
|
@ -109,10 +110,15 @@ namespace TestSites
|
|||
private async Task HostingEnvironment(HttpContext context)
|
||||
{
|
||||
var hostingEnv = context.RequestServices.GetService<IHostingEnvironment>();
|
||||
|
||||
|
||||
await context.Response.WriteAsync("ContentRootPath "+hostingEnv.ContentRootPath + Environment.NewLine);
|
||||
await context.Response.WriteAsync("WebRootPath "+hostingEnv.WebRootPath + Environment.NewLine);
|
||||
await context.Response.WriteAsync("CurrentDirectory "+Environment.CurrentDirectory);
|
||||
}
|
||||
|
||||
private async Task ProcessId(HttpContext context)
|
||||
{
|
||||
await context.Response.WriteAsync(Process.GetCurrentProcess().Id.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue