Split handler resolution from application info (#1177)

This commit is contained in:
Pavel Krymets 2018-08-09 11:32:51 -07:00 committed by GitHub
parent e6330ab19b
commit 8361b8cfa9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 543 additions and 415 deletions

View File

@ -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>

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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()
{

View File

@ -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 :

View File

@ -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.

View File

@ -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;
};

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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
{

View File

@ -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)
{

View File

@ -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();
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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());
}
}
}