Merge branch 'merge/release/2.2-to-master'

This commit is contained in:
Justin Kotalik 2018-09-06 12:06:07 -07:00
commit f4f6e50b22
116 changed files with 2355 additions and 1268 deletions

View File

@ -1,5 +1,11 @@
init:
- git config --global core.autocrlf true
# Reset dynamic port range from AppVeyor setting (1025-65535) to Windows default (49152-65535),
# to prevent conflicts with ANCM random ports (1025-48000).
- netsh int ipv4 show dynamicport tcp
- netsh int ipv4 set dynamic tcp start=49152 num=16384
- netsh int ipv4 show dynamicport tcp
- git config --global core.autocrlf true
branches:
only:
- master

View File

@ -10,6 +10,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{04B1EDB6-E96
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0EF45656-B25D-40D8-959C-726EAF185E60}"
ProjectSection(SolutionItems) = preProject
.appveyor.yml = .appveyor.yml
.editorconfig = .editorconfig
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets

View File

@ -20,6 +20,11 @@
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CodeAnalysisRuleSet>..\DefaultRules.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>false</RunCodeAnalysis>
<!-- Do not enable code analysis on old compiler versions -->
<RunCodeAnalysis Condition="'$(VCToolsRedistVersion)' != '' AND '$(VCToolsRedistVersion)' >= 14.15.26706">true</RunCodeAnalysis>
<EnablePREfast>$(RunCodeAnalysis)</EnablePREfast>
</PropertyGroup>
<ItemDefinitionGroup>

View File

@ -8,6 +8,7 @@
<MicrosoftAspNetCoreAllPackageVersion>3.0.0-alpha1-10400</MicrosoftAspNetCoreAllPackageVersion>
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>3.0.0-alpha1-10400</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>3.0.0-alpha1-10400</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
<MicrosoftAspNetCoreConnectionsAbstractionsPackageVersion>3.0.0-alpha1-10400</MicrosoftAspNetCoreConnectionsAbstractionsPackageVersion>
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>3.0.0-alpha1-10400</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
<MicrosoftAspNetCoreHostingPackageVersion>3.0.0-alpha1-10400</MicrosoftAspNetCoreHostingPackageVersion>
<MicrosoftAspNetCoreHttpExtensionsPackageVersion>3.0.0-alpha1-10400</MicrosoftAspNetCoreHttpExtensionsPackageVersion>

View File

@ -1,3 +1,6 @@
// 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.Linq;
using Microsoft.AspNetCore.Authentication;

View File

@ -3,7 +3,7 @@
#include <windows.h>
#include "version.h"
#include "resource.h"
#include "Aspnetcore_msg.rc"
#include "aspnetcore_msg.rc"
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources

View File

@ -11,7 +11,8 @@ HRESULT AppOfflineApplication::CreateHandler(IHttpContext* pHttpContext, IREQUES
{
try
{
*pRequestHandler = new AppOfflineHandler(pHttpContext, m_strAppOfflineContent);
auto handler = std::make_unique<AppOfflineHandler>(*pHttpContext, m_strAppOfflineContent);
*pRequestHandler = handler.release();
}
CATCH_RETURN();
@ -44,9 +45,9 @@ HRESULT AppOfflineApplication::OnAppOfflineFound()
if (li.LowPart > 0)
{
DWORD bytesRead = 0;
std::string pszBuff(li.LowPart + 1, '\0');
std::string pszBuff(static_cast<size_t>(li.LowPart) + 1, '\0');
RETURN_LAST_ERROR_IF(!ReadFile(handle, pszBuff.data(), li.LowPart, &bytesRead, NULL));
RETURN_LAST_ERROR_IF(!ReadFile(handle, pszBuff.data(), li.LowPart, &bytesRead, nullptr));
pszBuff.resize(bytesRead);
m_strAppOfflineContent = pszBuff;
@ -55,7 +56,7 @@ HRESULT AppOfflineApplication::OnAppOfflineFound()
return S_OK;
}
bool AppOfflineApplication::ShouldBeStarted(IHttpApplication& pApplication)
bool AppOfflineApplication::ShouldBeStarted(const IHttpApplication& pApplication)
{
return FileExists(GetAppOfflineLocation(pApplication));
}

View File

@ -20,7 +20,7 @@ public:
HRESULT OnAppOfflineFound() override;
static bool ShouldBeStarted(IHttpApplication& pApplication);
static bool ShouldBeStarted(const IHttpApplication& pApplication);
private:
std::string m_strAppOfflineContent;

View File

@ -7,8 +7,8 @@
REQUEST_NOTIFICATION_STATUS AppOfflineHandler::OnExecuteRequestHandler()
{
HTTP_DATA_CHUNK DataChunk;
IHttpResponse* pResponse = m_pContext->GetResponse();
HTTP_DATA_CHUNK DataChunk {};
auto pResponse = m_pContext.GetResponse();
DBG_ASSERT(pResponse);

View File

@ -9,7 +9,7 @@
class AppOfflineHandler: public REQUEST_HANDLER
{
public:
AppOfflineHandler(IHttpContext* pContext, const std::string appOfflineContent)
AppOfflineHandler(IHttpContext& pContext, const std::string appOfflineContent)
: m_pContext(pContext),
m_strAppOfflineContent(appOfflineContent)
{
@ -18,6 +18,6 @@ public:
REQUEST_NOTIFICATION_STATUS OnExecuteRequestHandler() override;
private:
IHttpContext* m_pContext;
IHttpContext& m_pContext;
std::string m_strAppOfflineContent;
};

View File

@ -5,6 +5,7 @@
#include <array>
#include <string>
#include <utility>
#include "iapplication.h"
#include "HandleWrapper.h"
@ -21,9 +22,9 @@ HRESULT
class ApplicationFactory
{
public:
ApplicationFactory(HMODULE hRequestHandlerDll, std::wstring location, PFN_ASPNETCORE_CREATE_APPLICATION pfnAspNetCoreCreateApplication):
ApplicationFactory(HMODULE hRequestHandlerDll, std::wstring location, PFN_ASPNETCORE_CREATE_APPLICATION pfnAspNetCoreCreateApplication) noexcept:
m_pfnAspNetCoreCreateApplication(pfnAspNetCoreCreateApplication),
m_location(location),
m_location(std::move(location)),
m_hRequestHandlerDll(hRequestHandlerDll)
{
}
@ -31,10 +32,10 @@ public:
HRESULT Execute(
_In_ IHttpServer *pServer,
_In_ IHttpApplication *pHttpApplication,
_Out_ IAPPLICATION **pApplication) const
_Outptr_ IAPPLICATION **pApplication) const noexcept
{
std::array<APPLICATION_PARAMETER, 1> parameters {
{"InProcessExeLocation", reinterpret_cast<const void*>(m_location.data())}
{"InProcessExeLocation", m_location.data()}
};
return m_pfnAspNetCoreCreateApplication(pServer, pHttpApplication, parameters.data(), static_cast<DWORD>(parameters.size()), pApplication);
}

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\Build\Build.Settings" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@ -56,6 +55,7 @@
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="..\..\..\Build\Build.Settings" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

View File

@ -14,11 +14,12 @@
#include "resources.h"
#include "ConfigurationLoadException.h"
#include "WebConfigConfigurationSource.h"
#include "ModuleHelpers.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)
HandlerResolver::HandlerResolver(HMODULE hModule, const IHttpServer &pServer)
: m_hModule(hModule),
m_pServer(pServer),
m_loadedApplicationHostingModel(HOSTING_UNKNOWN)
@ -27,11 +28,11 @@ HandlerResolver::HandlerResolver(HMODULE hModule, IHttpServer &pServer)
}
HRESULT
HandlerResolver::LoadRequestHandlerAssembly(IHttpApplication &pApplication, ShimOptions& pConfiguration, std::unique_ptr<ApplicationFactory>& pApplicationFactory)
HandlerResolver::LoadRequestHandlerAssembly(const IHttpApplication &pApplication, const ShimOptions& pConfiguration, std::unique_ptr<ApplicationFactory>& pApplicationFactory)
{
HRESULT hr;
PCWSTR pstrHandlerDllName;
bool preventUnload;
HRESULT hr = S_OK;
PCWSTR pstrHandlerDllName = nullptr;
bool preventUnload = false;
if (pConfiguration.QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
{
preventUnload = false;
@ -56,10 +57,10 @@ HandlerResolver::LoadRequestHandlerAssembly(IHttpApplication &pApplication, Shim
std::unique_ptr<IOutputManager> outputManager;
RETURN_IF_FAILED(HOSTFXR_OPTIONS::Create(
NULL,
pConfiguration.QueryProcessPath().c_str(),
L"",
pConfiguration.QueryProcessPath(),
pApplication.GetApplicationPhysicalPath(),
pConfiguration.QueryArguments().c_str(),
pConfiguration.QueryArguments(),
options));
location = options->GetDotnetExeLocation();
@ -76,7 +77,7 @@ HandlerResolver::LoadRequestHandlerAssembly(IHttpApplication &pApplication, Shim
hr = FindNativeAssemblyFromHostfxr(*options.get(), pstrHandlerDllName, handlerDllPath);
outputManager->Stop();
if (FAILED(hr) && m_hHostFxrDll != NULL)
if (FAILED(hr) && m_hHostFxrDll != nullptr)
{
STRA content;
STRU struStdMsg;
@ -119,7 +120,7 @@ HandlerResolver::LoadRequestHandlerAssembly(IHttpApplication &pApplication, Shim
RETURN_LAST_ERROR_IF_NULL(hRequestHandlerDll);
}
auto pfnAspNetCoreCreateApplication = reinterpret_cast<PFN_ASPNETCORE_CREATE_APPLICATION>(GetProcAddress(hRequestHandlerDll, "CreateApplication"));
auto pfnAspNetCoreCreateApplication = ModuleHelpers::GetKnownProcAddress<PFN_ASPNETCORE_CREATE_APPLICATION>(hRequestHandlerDll, "CreateApplication");
RETURN_LAST_ERROR_IF_NULL(pfnAspNetCoreCreateApplication);
pApplicationFactory = std::make_unique<ApplicationFactory>(hRequestHandlerDll.release(), location, pfnAspNetCoreCreateApplication);
@ -127,7 +128,7 @@ HandlerResolver::LoadRequestHandlerAssembly(IHttpApplication &pApplication, Shim
}
HRESULT
HandlerResolver::GetApplicationFactory(IHttpApplication &pApplication, std::unique_ptr<ApplicationFactory>& pApplicationFactory)
HandlerResolver::GetApplicationFactory(const IHttpApplication &pApplication, std::unique_ptr<ApplicationFactory>& pApplicationFactory)
{
try
{
@ -189,7 +190,7 @@ void HandlerResolver::ResetHostingModel()
HRESULT
HandlerResolver::FindNativeAssemblyFromGlobalLocation(
ShimOptions& pConfiguration,
const ShimOptions& pConfiguration,
PCWSTR pstrHandlerDllName,
std::wstring& handlerDllPath
)
@ -225,20 +226,20 @@ HandlerResolver::FindNativeAssemblyFromGlobalLocation(
//
HRESULT
HandlerResolver::FindNativeAssemblyFromHostfxr(
HOSTFXR_OPTIONS& hostfxrOptions,
const HOSTFXR_OPTIONS& hostfxrOptions,
PCWSTR libraryName,
std::wstring& handlerDllPath
)
{
std::wstring struNativeSearchPaths;
size_t intIndex;
size_t intIndex = 0;
size_t intPrevIndex = 0;
DWORD dwBufferSize = s_initialGetNativeSearchDirectoriesBufferSize;
DWORD dwRequiredBufferSize = 0;
RETURN_LAST_ERROR_IF_NULL(m_hHostFxrDll = LoadLibraryW(hostfxrOptions.GetHostFxrLocation().c_str()));
auto pFnHostFxrSearchDirectories = reinterpret_cast<hostfxr_get_native_search_directories_fn>(GetProcAddress(m_hHostFxrDll, "hostfxr_get_native_search_directories"));
const auto pFnHostFxrSearchDirectories = ModuleHelpers::GetKnownProcAddress<hostfxr_get_native_search_directories_fn>(m_hHostFxrDll, "hostfxr_get_native_search_directories");
if (pFnHostFxrSearchDirectories == nullptr)
{
EventLog::Error(

View File

@ -13,17 +13,17 @@
class HandlerResolver
{
public:
HandlerResolver(HMODULE hModule, IHttpServer &pServer);
HRESULT GetApplicationFactory(IHttpApplication &pApplication, std::unique_ptr<ApplicationFactory>& pApplicationFactory);
HandlerResolver(HMODULE hModule, const IHttpServer &pServer);
HRESULT GetApplicationFactory(const IHttpApplication &pApplication, std::unique_ptr<ApplicationFactory>& pApplicationFactory);
void ResetHostingModel();
private:
HRESULT LoadRequestHandlerAssembly(IHttpApplication &pApplication, ShimOptions& pConfiguration, std::unique_ptr<ApplicationFactory>& pApplicationFactory);
HRESULT FindNativeAssemblyFromGlobalLocation(ShimOptions& pConfiguration, PCWSTR libraryName, std::wstring& handlerDllPath);
HRESULT FindNativeAssemblyFromHostfxr(HOSTFXR_OPTIONS& hostfxrOptions, PCWSTR libraryName, std::wstring& handlerDllPath);
HRESULT LoadRequestHandlerAssembly(const IHttpApplication &pApplication, const ShimOptions& pConfiguration, std::unique_ptr<ApplicationFactory>& pApplicationFactory);
HRESULT FindNativeAssemblyFromGlobalLocation(const ShimOptions& pConfiguration, PCWSTR libraryName, std::wstring& handlerDllPath);
HRESULT FindNativeAssemblyFromHostfxr(const HOSTFXR_OPTIONS& hostfxrOptions, PCWSTR libraryName, std::wstring& handlerDllPath);
HMODULE m_hModule;
IHttpServer &m_pServer;
const IHttpServer &m_pServer;
SRWLOCK m_requestHandlerLoadLock {};
std::wstring m_loadedApplicationId;

View File

@ -44,12 +44,12 @@ PollingAppOfflineApplication::CheckAppOffline()
}
std::filesystem::path PollingAppOfflineApplication::GetAppOfflineLocation(IHttpApplication& pApplication)
std::filesystem::path PollingAppOfflineApplication::GetAppOfflineLocation(const IHttpApplication& pApplication)
{
return std::filesystem::path(pApplication.GetApplicationPhysicalPath()) / "app_offline.htm";
}
bool PollingAppOfflineApplication::FileExists(const std::filesystem::path& path)
bool PollingAppOfflineApplication::FileExists(const std::filesystem::path& path) noexcept
{
std::error_code ec;
return is_regular_file(path, ec) || ec.value() == ERROR_SHARING_VIOLATION;

View File

@ -31,8 +31,8 @@ public:
protected:
std::filesystem::path m_appOfflineLocation;
static std::filesystem::path GetAppOfflineLocation(IHttpApplication& pApplication);
static bool FileExists(const std::filesystem::path& path);
static std::filesystem::path GetAppOfflineLocation(const IHttpApplication& pApplication);
static bool FileExists(const std::filesystem::path& path) noexcept;
private:
static const int c_appOfflineRefreshIntervalMS = 200;
std::string m_strAppOfflineContent;

View File

@ -17,13 +17,14 @@ public:
~ServerErrorApplication() = default;
HRESULT CreateHandler(IHttpContext * pHttpContext, IREQUEST_HANDLER ** pRequestHandler) override
HRESULT CreateHandler(IHttpContext *pHttpContext, IREQUEST_HANDLER ** pRequestHandler) override
{
*pRequestHandler = new ServerErrorHandler(pHttpContext, m_HR);
auto handler = std::make_unique<ServerErrorHandler>(*pHttpContext, m_HR);
*pRequestHandler = handler.release();
return S_OK;
}
HRESULT OnAppOfflineFound() override { return S_OK; }
HRESULT OnAppOfflineFound() noexcept override { return S_OK; }
private:
HRESULT m_HR;
};

View File

@ -7,17 +7,17 @@
class ServerErrorHandler : public REQUEST_HANDLER
{
public:
ServerErrorHandler(IHttpContext* pContext, HRESULT hr) : m_pContext(pContext), m_HR(hr)
ServerErrorHandler(IHttpContext &pContext, HRESULT hr) : m_pContext(pContext), m_HR(hr)
{
}
REQUEST_NOTIFICATION_STATUS OnExecuteRequestHandler() override
{
m_pContext->GetResponse()->SetStatus(500, "Internal Server Error", 0, m_HR);
m_pContext.GetResponse()->SetStatus(500, "Internal Server Error", 0, m_HR);
return RQ_NOTIFICATION_FINISH_REQUEST;
}
private:
IHttpContext * m_pContext;
IHttpContext &m_pContext;
HRESULT m_HR;
};

View File

@ -18,37 +18,37 @@ class ShimOptions: NonCopyable
{
public:
const std::wstring&
QueryProcessPath() const
QueryProcessPath() const noexcept
{
return m_strProcessPath;
}
const std::wstring&
QueryArguments() const
QueryArguments() const noexcept
{
return m_strArguments;
}
APP_HOSTING_MODEL
QueryHostingModel() const
QueryHostingModel() const noexcept
{
return m_hostingModel;
}
const std::wstring&
QueryHandlerVersion() const
QueryHandlerVersion() const noexcept
{
return m_strHandlerVersion;
}
BOOL
QueryStdoutLogEnabled() const
QueryStdoutLogEnabled() const noexcept
{
return m_fStdoutLogEnabled;
}
const std::wstring&
QueryStdoutLogFile() const
QueryStdoutLogFile() const noexcept
{
return m_struStdoutLogFile;
}

View File

@ -13,14 +13,9 @@
#include "ServerErrorApplication.h"
#include "AppOfflineApplication.h"
APPLICATION_INFO::~APPLICATION_INFO()
{
ShutDownApplication(/* fServerInitiated */ false);
}
HRESULT
APPLICATION_INFO::GetOrCreateApplication(
IHttpContext *pHttpContext,
IHttpContext& pHttpContext,
std::unique_ptr<IAPPLICATION, IAPPLICATION_DELETER>& pApplication
)
{
@ -28,7 +23,7 @@ APPLICATION_INFO::GetOrCreateApplication(
SRWExclusiveLock lock(m_applicationLock);
auto& httpApplication = *pHttpContext->GetApplication();
auto& httpApplication = *pHttpContext.GetApplication();
if (m_pApplication != nullptr)
{
@ -51,7 +46,10 @@ APPLICATION_INFO::GetOrCreateApplication(
if (AppOfflineApplication::ShouldBeStarted(httpApplication))
{
LOG_INFO(L"Detected app_offline file, creating polling application");
#pragma warning( push )
#pragma warning ( disable : 26409 ) // Disable "Avoid using new", using custom deleter here
m_pApplication.reset(new AppOfflineApplication(httpApplication));
#pragma warning( pop )
}
else
{
@ -77,8 +75,11 @@ Finished:
ASPNETCORE_EVENT_ADD_APPLICATION_ERROR_MSG,
httpApplication.GetApplicationId(),
hr);
#pragma warning( push )
#pragma warning ( disable : 26409 ) // Disable "Avoid using new", using custom deleter here
m_pApplication.reset(new ServerErrorApplication(httpApplication, hr));
#pragma warning( pop )
}
if (m_pApplication)
@ -97,7 +98,7 @@ APPLICATION_INFO::ShutDownApplication(bool fServerInitiated)
if (m_pApplication)
{
LOG_ERRORF(L"Stopping application '%ls'", QueryApplicationInfoKey().c_str());
LOG_INFOF(L"Stopping application '%ls'", QueryApplicationInfoKey().c_str());
m_pApplication ->Stop(fServerInitiated);
m_pApplication = nullptr;
m_pApplicationFactory = nullptr;

View File

@ -12,7 +12,7 @@
extern BOOL g_fRecycleProcessCalled;
class APPLICATION_INFO
class APPLICATION_INFO: NonCopyable
{
public:
@ -29,16 +29,16 @@ public:
InitializeSRWLock(&m_applicationLock);
}
~APPLICATION_INFO();
~APPLICATION_INFO() = default;
std::wstring&
QueryApplicationInfoKey()
const std::wstring&
QueryApplicationInfoKey() const noexcept
{
return m_strInfoKey;
}
std::wstring&
QueryConfigPath()
const std::wstring&
QueryConfigPath() const noexcept
{
return m_strConfigPath;
}
@ -48,7 +48,7 @@ public:
HRESULT
GetOrCreateApplication(
IHttpContext *pHttpContext,
IHttpContext& pHttpContext,
std::unique_ptr<IAPPLICATION, IAPPLICATION_DELETER>& pApplication
);

View File

@ -11,9 +11,6 @@
extern BOOL g_fInShutdown;
// The application manager is a singleton across ANCM.
APPLICATION_MANAGER* APPLICATION_MANAGER::sm_pApplicationManager = NULL;
//
// Retrieves the application info from the application manager
// Will create the application info if it isn't initalized

View File

@ -8,8 +8,6 @@
#include "exceptions.h"
#include <unordered_map>
#define DEFAULT_HASH_BUCKETS 17
//
// This class will manage the lifecycle of all Asp.Net Core applciation
// It should be global singleton.
@ -21,25 +19,6 @@ class APPLICATION_MANAGER
{
public:
static
APPLICATION_MANAGER*
GetInstance()
{
assert(sm_pApplicationManager);
return sm_pApplicationManager;
}
static
VOID
Cleanup()
{
if(sm_pApplicationManager != NULL)
{
delete sm_pApplicationManager;
sm_pApplicationManager = NULL;
}
}
HRESULT
GetOrCreateApplicationInfo(
_In_ IHttpContext& pHttpContext,
@ -53,16 +32,7 @@ public:
VOID
ShutDown();
static HRESULT StaticInitialize(HMODULE hModule, IHttpServer& pHttpServer)
{
assert(!sm_pApplicationManager);
sm_pApplicationManager = new APPLICATION_MANAGER(hModule, pHttpServer);
return S_OK;
}
private:
APPLICATION_MANAGER(HMODULE hModule, IHttpServer& pHttpServer) :
m_pApplicationInfoHash(NULL),
m_fDebugInitialize(FALSE),
@ -72,8 +42,9 @@ private:
InitializeSRWLock(&m_srwLock);
}
private:
std::unordered_map<std::wstring, std::shared_ptr<APPLICATION_INFO>> m_pApplicationInfoHash;
static APPLICATION_MANAGER *sm_pApplicationManager;
SRWLOCK m_srwLock {};
BOOL m_fDebugInitialize;
IHttpServer &m_pHttpServer;

View File

@ -13,7 +13,7 @@
DECLARE_DEBUG_PRINT_OBJECT("aspnetcorev2.dll");
HANDLE g_hEventLog = NULL;
HANDLE g_hEventLog = nullptr;
BOOL g_fRecycleProcessCalled = FALSE;
BOOL g_fInShutdown = FALSE;
HINSTANCE g_hServerModule;
@ -21,14 +21,14 @@ HINSTANCE g_hServerModule;
VOID
StaticCleanup()
{
APPLICATION_MANAGER::Cleanup();
if (g_hEventLog != NULL)
if (g_hEventLog != nullptr)
{
DeregisterEventSource(g_hEventLog);
g_hEventLog = NULL;
g_hEventLog = nullptr;
}
DebugStop();
ALLOC_CACHE_HANDLER::StaticTerminate();
}
BOOL WINAPI DllMain(HMODULE hModule,
@ -41,11 +41,14 @@ BOOL WINAPI DllMain(HMODULE hModule,
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
ALLOC_CACHE_HANDLER::StaticInitialize();
g_hServerModule = hModule;
DisableThreadLibraryCalls(hModule);
DebugInitialize(hModule);
break;
case DLL_PROCESS_DETACH:
// IIS can cause dll detach to occur before we receive global notifications
// For example, when we switch the bitness of the worker process,
// this is a bug in IIS. To try to avoid AVs, we will set a global flag
@ -85,21 +88,18 @@ HRESULT
--*/
{
HRESULT hr = S_OK;
HKEY hKey;
HKEY hKey {};
BOOL fDisableANCM = FALSE;
ASPNET_CORE_PROXY_MODULE_FACTORY * pFactory = NULL;
ASPNET_CORE_GLOBAL_MODULE * pGlobalModule = NULL;
UNREFERENCED_PARAMETER(dwServerVersion);
if (pHttpServer->IsCommandLineLaunch())
{
g_hEventLog = RegisterEventSource(NULL, ASPNETCORE_IISEXPRESS_EVENT_PROVIDER);
g_hEventLog = RegisterEventSource(nullptr, ASPNETCORE_IISEXPRESS_EVENT_PROVIDER);
}
else
{
g_hEventLog = RegisterEventSource(NULL, ASPNETCORE_EVENT_PROVIDER);
g_hEventLog = RegisterEventSource(nullptr, ASPNETCORE_EVENT_PROVIDER);
}
// check whether the feature is disabled due to security reason
@ -109,14 +109,14 @@ HRESULT
KEY_READ,
&hKey) == NO_ERROR)
{
DWORD dwType;
DWORD dwData;
DWORD dwType = 0;
DWORD dwData = 0;
DWORD cbData;
cbData = sizeof(dwData);
if ((RegQueryValueEx(hKey,
L"DisableANCM",
NULL,
nullptr,
&dwType,
(LPBYTE)&dwData,
&cbData) == NO_ERROR) &&
@ -136,7 +136,7 @@ HRESULT
ASPNETCORE_EVENT_MODULE_DISABLED_MSG);
// this will return 500 error to client
// as we did not register the module
goto Finished;
return S_OK;
}
//
@ -144,43 +144,22 @@ HRESULT
// The ASPNET_CORE_PROXY_MODULE_FACTORY::Terminate method will clean any
// static object initialized.
//
pFactory = new ASPNET_CORE_PROXY_MODULE_FACTORY;
auto applicationManager = std::make_shared<APPLICATION_MANAGER>(g_hServerModule, *pHttpServer);
auto moduleFactory = std::make_unique<ASPNET_CORE_PROXY_MODULE_FACTORY>(applicationManager);
FINISHED_IF_FAILED(pModuleInfo->SetRequestNotifications(
pFactory,
RETURN_IF_FAILED(pModuleInfo->SetRequestNotifications(
moduleFactory.release(),
RQ_EXECUTE_REQUEST_HANDLER,
0));
;
auto pGlobalModule = std::make_unique<ASPNET_CORE_GLOBAL_MODULE>(std::move(applicationManager));
pFactory = NULL;
FINISHED_IF_FAILED(APPLICATION_MANAGER::StaticInitialize(g_hServerModule, *pHttpServer));
pGlobalModule = NULL;
pGlobalModule = new ASPNET_CORE_GLOBAL_MODULE(APPLICATION_MANAGER::GetInstance());
FINISHED_IF_FAILED(pModuleInfo->SetGlobalNotifications(
pGlobalModule,
RETURN_IF_FAILED(pModuleInfo->SetGlobalNotifications(
pGlobalModule.release(),
GL_CONFIGURATION_CHANGE | // Configuration change trigers IIS application stop
GL_STOP_LISTENING)); // worker process stop or recycle
pGlobalModule = NULL;
FINISHED_IF_FAILED(ALLOC_CACHE_HANDLER::StaticInitialize());
Finished:
if (pGlobalModule != NULL)
{
delete pGlobalModule;
pGlobalModule = NULL;
}
if (pFactory != NULL)
{
pFactory->Terminate();
pFactory = NULL;
}
return hr;
return S_OK;
}
CATCH_RETURN()

View File

@ -5,10 +5,9 @@
extern BOOL g_fInShutdown;
ASPNET_CORE_GLOBAL_MODULE::ASPNET_CORE_GLOBAL_MODULE(
APPLICATION_MANAGER* pApplicationManager)
ASPNET_CORE_GLOBAL_MODULE::ASPNET_CORE_GLOBAL_MODULE(std::shared_ptr<APPLICATION_MANAGER> pApplicationManager) noexcept
:m_pApplicationManager(std::move(pApplicationManager))
{
m_pApplicationManager = pApplicationManager;
}
//
@ -30,11 +29,8 @@ ASPNET_CORE_GLOBAL_MODULE::OnGlobalStopListening(
return GL_NOTIFICATION_CONTINUE;
}
DBG_ASSERT(m_pApplicationManager);
// we should let application manager to shutdown all allication
// and dereference it as some requests may still reference to application manager
m_pApplicationManager->ShutDown();
m_pApplicationManager = NULL;
m_pApplicationManager = nullptr;
// Return processing to the pipeline.
return GL_NOTIFICATION_CONTINUE;
@ -59,13 +55,13 @@ ASPNET_CORE_GLOBAL_MODULE::OnGlobalConfigurationChange(
LOG_INFOF(L"ASPNET_CORE_GLOBAL_MODULE::OnGlobalConfigurationChange '%ls'", pwszChangePath);
// Test for an error.
if (NULL != pwszChangePath &&
if (nullptr != pwszChangePath &&
_wcsicmp(pwszChangePath, L"MACHINE") != 0 &&
_wcsicmp(pwszChangePath, L"MACHINE/WEBROOT") != 0)
{
if (m_pApplicationManager != NULL)
if (m_pApplicationManager)
{
m_pApplicationManager->RecycleApplicationFromManager(pwszChangePath);
m_pApplicationManager->RecycleApplicationFromManager(pwszChangePath);
}
}

View File

@ -5,20 +5,18 @@
#include "applicationmanager.h"
class ASPNET_CORE_GLOBAL_MODULE : public CGlobalModule
class ASPNET_CORE_GLOBAL_MODULE : NonCopyable, public CGlobalModule
{
public:
ASPNET_CORE_GLOBAL_MODULE(
APPLICATION_MANAGER* pApplicationManager
);
std::shared_ptr<APPLICATION_MANAGER> pApplicationManager
) noexcept;
~ASPNET_CORE_GLOBAL_MODULE()
{
}
virtual ~ASPNET_CORE_GLOBAL_MODULE() = default;
VOID Terminate()
VOID Terminate() override
{
LOG_INFO(L"ASPNET_CORE_GLOBAL_MODULE::Terminate");
// Remove the class from memory.
@ -28,13 +26,13 @@ public:
GLOBAL_NOTIFICATION_STATUS
OnGlobalStopListening(
_In_ IGlobalStopListeningProvider * pProvider
);
) override;
GLOBAL_NOTIFICATION_STATUS
OnGlobalConfigurationChange(
_In_ IGlobalConfigurationChangeProvider * pProvider
);
) override;
private:
APPLICATION_MANAGER * m_pApplicationManager;
std::shared_ptr<APPLICATION_MANAGER> m_pApplicationManager;
};

View File

@ -5,31 +5,40 @@
#include "applicationmanager.h"
#include "applicationinfo.h"
#include "acache.h"
#include "exceptions.h"
extern BOOL g_fInShutdown;
__override
ASPNET_CORE_PROXY_MODULE_FACTORY::ASPNET_CORE_PROXY_MODULE_FACTORY(std::shared_ptr<APPLICATION_MANAGER> applicationManager) noexcept
:m_pApplicationManager(std::move(applicationManager))
{
}
HRESULT
ASPNET_CORE_PROXY_MODULE_FACTORY::GetHttpModule(
CHttpModule ** ppModule,
IModuleAllocator * pAllocator
)
{
try
#pragma warning( push )
#pragma warning ( disable : 26409 ) // Disable "Avoid using new"
*ppModule = new (pAllocator) ASPNET_CORE_PROXY_MODULE(m_pApplicationManager);
#pragma warning( push )
if (*ppModule == nullptr)
{
*ppModule = THROW_IF_NULL_ALLOC(new (pAllocator) ASPNET_CORE_PROXY_MODULE());;
return S_OK;
return E_OUTOFMEMORY;
}
CATCH_RETURN();
return S_OK;
}
__override
VOID
ASPNET_CORE_PROXY_MODULE_FACTORY::Terminate(
VOID
)
) noexcept
/*++
Routine description:
@ -46,12 +55,13 @@ Return value:
--*/
{
ALLOC_CACHE_HANDLER::StaticTerminate();
delete this;
}
ASPNET_CORE_PROXY_MODULE::ASPNET_CORE_PROXY_MODULE(
) : m_pApplicationInfo(nullptr), m_pHandler(nullptr)
ASPNET_CORE_PROXY_MODULE::ASPNET_CORE_PROXY_MODULE(std::shared_ptr<APPLICATION_MANAGER> applicationManager) noexcept
: m_pApplicationManager(std::move(applicationManager)),
m_pApplicationInfo(nullptr),
m_pHandler(nullptr)
{
}
@ -64,6 +74,7 @@ ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler(
{
HRESULT hr = S_OK;
REQUEST_NOTIFICATION_STATUS retVal = RQ_NOTIFICATION_CONTINUE;
try
{
@ -72,14 +83,12 @@ ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler(
FINISHED(HRESULT_FROM_WIN32(ERROR_SERVER_SHUTDOWN_IN_PROGRESS));
}
auto pApplicationManager = APPLICATION_MANAGER::GetInstance();
FINISHED_IF_FAILED(pApplicationManager->GetOrCreateApplicationInfo(
FINISHED_IF_FAILED(m_pApplicationManager->GetOrCreateApplicationInfo(
*pHttpContext,
m_pApplicationInfo));
std::unique_ptr<IAPPLICATION, IAPPLICATION_DELETER> pApplication;
FINISHED_IF_FAILED(m_pApplicationInfo->GetOrCreateApplication(pHttpContext, pApplication));
FINISHED_IF_FAILED(m_pApplicationInfo->GetOrCreateApplication(*pHttpContext, pApplication));
IREQUEST_HANDLER* pHandler;
// Create RequestHandler and process the request
@ -94,7 +103,7 @@ ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler(
}
Finished:
if (LOG_IF_FAILED(hr))
if (FAILED(LOG_IF_FAILED(hr)))
{
retVal = RQ_NOTIFICATION_FINISH_REQUEST;
if (hr == HRESULT_FROM_WIN32(ERROR_SERVER_SHUTDOWN_IN_PROGRESS))

View File

@ -6,14 +6,15 @@
#include <memory>
#include "applicationinfo.h"
#include "irequesthandler.h"
#include "applicationmanager.h"
extern HTTP_MODULE_ID g_pModuleId;
class ASPNET_CORE_PROXY_MODULE : public CHttpModule
class ASPNET_CORE_PROXY_MODULE : NonCopyable, public CHttpModule
{
public:
ASPNET_CORE_PROXY_MODULE();
ASPNET_CORE_PROXY_MODULE(std::shared_ptr<APPLICATION_MANAGER> applicationManager) noexcept;
~ASPNET_CORE_PROXY_MODULE() = default;
@ -33,7 +34,7 @@ class ASPNET_CORE_PROXY_MODULE : public CHttpModule
OnExecuteRequestHandler(
IHttpContext * pHttpContext,
IHttpEventProvider * pProvider
);
) override;
__override
REQUEST_NOTIFICATION_STATUS
@ -43,22 +44,29 @@ class ASPNET_CORE_PROXY_MODULE : public CHttpModule
BOOL fPostNotification,
IHttpEventProvider * pProvider,
IHttpCompletionInfo * pCompletionInfo
);
) override;
private:
std::shared_ptr<APPLICATION_MANAGER> m_pApplicationManager;
std::shared_ptr<APPLICATION_INFO> m_pApplicationInfo;
std::unique_ptr<IREQUEST_HANDLER, IREQUEST_HANDLER_DELETER> m_pHandler;
std::unique_ptr<IREQUEST_HANDLER, IREQUEST_HANDLER_DELETER> m_pHandler;
};
class ASPNET_CORE_PROXY_MODULE_FACTORY : public IHttpModuleFactory
class ASPNET_CORE_PROXY_MODULE_FACTORY : NonCopyable, public IHttpModuleFactory
{
public:
ASPNET_CORE_PROXY_MODULE_FACTORY(std::shared_ptr<APPLICATION_MANAGER> applicationManager) noexcept;
virtual ~ASPNET_CORE_PROXY_MODULE_FACTORY() = default;
HRESULT
GetHttpModule(
CHttpModule ** ppModule,
IModuleAllocator * pAllocator
);
) override;
VOID
Terminate();
Terminate() noexcept override;
private:
std::shared_ptr<APPLICATION_MANAGER> m_pApplicationManager;
};

View File

@ -72,16 +72,20 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>C:\AspNetCoreModule\src\IISLib;$(IncludePath)</IncludePath>
<OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
@ -195,7 +199,6 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="application.h" />
<ClInclude Include="ConfigurationLoadException.h" />
<ClInclude Include="ConfigurationSection.h" />
<ClInclude Include="ConfigurationSource.h" />
<ClInclude Include="config_utility.h" />
@ -211,9 +214,11 @@
<ClInclude Include="hostfxr_utility.h" />
<ClInclude Include="iapplication.h" />
<ClInclude Include="debugutil.h" />
<ClInclude Include="InvalidOperationException.h" />
<ClInclude Include="IOutputManager.h" />
<ClInclude Include="irequesthandler.h" />
<ClInclude Include="LoggingHelpers.h" />
<ClInclude Include="ModuleHelpers.h" />
<ClInclude Include="NonCopyable.h" />
<ClInclude Include="NullOutputManager.h" />
<ClInclude Include="PipeOutputManager.h" />

View File

@ -26,6 +26,16 @@ bool ConfigurationSection::GetRequiredBool(const std::wstring& name) const
return result.value();
}
DWORD ConfigurationSection::GetRequiredLong(const std::wstring& name) const
{
auto result = GetLong(name);
if (!result.has_value())
{
ThrowRequiredException(name);
}
return result.value();
}
DWORD ConfigurationSection::GetRequiredTimespan(const std::wstring& name) const
{
auto result = GetTimespan(name);

View File

@ -17,6 +17,8 @@
#define CS_ASPNETCORE_PROCESS_EXE_PATH L"processPath"
#define CS_ASPNETCORE_PROCESS_ARGUMENTS L"arguments"
#define CS_ASPNETCORE_PROCESS_ARGUMENTS_DEFAULT L""
#define CS_ASPNETCORE_PROCESS_STARTUP_TIME_LIMIT L"startupTimeLimit"
#define CS_ASPNETCORE_PROCESS_SHUTDOWN_TIME_LIMIT L"shutdownTimeLimit"
#define CS_ASPNETCORE_HOSTING_MODEL_OUTOFPROCESS L"outofprocess"
#define CS_ASPNETCORE_HOSTING_MODEL_INPROCESS L"inprocess"
#define CS_ASPNETCORE_HOSTING_MODEL L"hostingModel"
@ -31,10 +33,12 @@ public:
virtual ~ConfigurationSection() = default;
virtual std::optional<std::wstring> GetString(const std::wstring& name) const = 0;
virtual std::optional<bool> GetBool(const std::wstring& name) const = 0;
virtual std::optional<DWORD> GetLong(const std::wstring& name) const = 0;
virtual std::optional<DWORD> GetTimespan(const std::wstring& name) const = 0;
std::wstring GetRequiredString(const std::wstring& name) const;
bool GetRequiredBool(const std::wstring& name) const;
DWORD GetRequiredLong(const std::wstring& name) const;
DWORD GetRequiredTimespan(const std::wstring& name) const;
virtual std::vector<std::pair<std::wstring, std::wstring>> GetKeyValuePairs(const std::wstring& name) const = 0;

View File

@ -4,10 +4,46 @@
#include <array>
#include "EventLog.h"
#include "debugutil.h"
#include "StringHelpers.h"
#include "exceptions.h"
extern HANDLE g_hEventLog;
bool
EventLog::LogEventNoTrace(
_In_ WORD dwEventInfoType,
_In_ DWORD dwEventId,
_In_ LPCWSTR pstrMsg
)
{
if (g_hEventLog == nullptr)
{
return true;
}
// Static locals to avoid getting the process ID and string multiple times.
// Effectively have the same semantics as global variables, except initialized
// on first occurence.
static const auto processIdString = GetProcessIdString();
static const auto versionInfoString = GetVersionInfoString();
std::array<LPCWSTR, 3> eventLogDataStrings
{
pstrMsg,
processIdString.c_str(),
versionInfoString.c_str()
};
return ReportEventW(g_hEventLog,
dwEventInfoType,
0, // wCategory
dwEventId,
NULL, // lpUserSid
static_cast<WORD>(eventLogDataStrings.size()), // wNumStrings
0, // dwDataSize,
eventLogDataStrings.data(),
NULL // lpRawData
);
}
VOID
EventLog::LogEvent(
_In_ WORD dwEventInfoType,
@ -15,32 +51,7 @@ EventLog::LogEvent(
_In_ LPCWSTR pstrMsg
)
{
// Static locals to avoid getting the process ID and string multiple times.
// Effectively have the same semantics as global variables, except initialized
// on first occurence.
static const auto processIdString = GetProcessIdString();
static const auto versionInfoString = GetVersionInfoString();
std::array<LPCWSTR, 3> eventLogDataStrings
{
pstrMsg,
processIdString.c_str(),
versionInfoString.c_str()
};
if (g_hEventLog != NULL)
{
ReportEventW(g_hEventLog,
dwEventInfoType,
0, // wCategory
dwEventId,
NULL, // lpUserSid
3, // wNumStrings
0, // dwDataSize,
eventLogDataStrings.data(),
NULL // lpRawData
);
}
LOG_LAST_ERROR_IF(!LogEventNoTrace(dwEventInfoType, dwEventId, pstrMsg));
DebugPrintfW(dwEventInfoType == EVENTLOG_ERROR_TYPE ? ASPNETCORE_DEBUG_FLAG_ERROR : ASPNETCORE_DEBUG_FLAG_INFO, L"Event Log: '%ls' \r\nEnd Event Log Message.", pstrMsg);
}
@ -50,7 +61,7 @@ EventLog::LogEventF(
_In_ WORD dwEventInfoType,
_In_ DWORD dwEventId,
_In_ LPCWSTR pstrMsg,
va_list argsList
_In_ va_list argsList
)
{
STACK_STRU ( strEventMsg, 256 );

View File

@ -5,6 +5,18 @@
#include "resources.h"
#define _va_start(ap, x) \
__pragma(warning(push)) \
__pragma(warning(disable:26481 26492)) /*Don't use pointer arithmetic. Don't use const_cast to cast away const.*/ \
va_start(ap, x) \
__pragma(warning(pop))
#define _va_end(args) \
__pragma(warning(push)) \
__pragma(warning(disable:26477)) /*Use 'nullptr' rather than 0 or NULL*/ \
va_end(args) \
__pragma(warning(pop))
class EventLog
{
public:
@ -16,9 +28,9 @@ public:
...)
{
va_list args;
va_start(args, pstrMsg);
_va_start(args, pstrMsg);
LogEventF(EVENTLOG_ERROR_TYPE, dwEventId, pstrMsg, args);
va_end(args);
_va_end(args);
}
static
@ -29,9 +41,9 @@ public:
...)
{
va_list args;
va_start(args, pstrMsg);
_va_start(args, pstrMsg);
LogEventF(EVENTLOG_INFORMATION_TYPE, dwEventId, pstrMsg, args);
va_end(args);
_va_end(args);
}
static
@ -42,11 +54,18 @@ public:
...)
{
va_list args;
va_start(args, pstrMsg);
_va_start(args, pstrMsg);
LogEventF(EVENTLOG_WARNING_TYPE, dwEventId, pstrMsg, args);
va_end(args);
_va_end(args);
}
static
bool
LogEventNoTrace(
_In_ WORD dwEventInfoType,
_In_ DWORD dwEventId,
_In_ LPCWSTR pstrMsg);
private:
static
VOID

View File

@ -49,6 +49,17 @@ FileOutputManager::Start()
STRU struPath;
FILETIME processCreationTime;
FILETIME dummyFileTime;
// To make Console.* functions work, allocate a console
// in the current process.
if (!AllocConsole())
{
// ERROR_ACCESS_DENIED means there is a console already present.
if (GetLastError() != ERROR_ACCESS_DENIED)
{
RETURN_LAST_ERROR();
}
}
// Concatenate the log file name and application path
RETURN_IF_FAILED(FILE_UTILITY::ConvertPathToFullPath(
@ -163,7 +174,7 @@ FileOutputManager::Stop()
if (li.LowPart == 0 || li.HighPart > 0)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
RETURN_HR(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
}
dwFilePointer = SetFilePointer(m_hLogFileHandle, 0, NULL, FILE_BEGIN);

View File

@ -10,37 +10,41 @@ struct InvalidHandleTraits
{
using HandleType = HANDLE;
static const HANDLE DefaultHandle;
static void Close(HANDLE handle) { CloseHandle(handle); }
static void Close(HANDLE handle) noexcept { CloseHandle(handle); }
};
struct NullHandleTraits
{
using HandleType = HANDLE;
static constexpr HANDLE DefaultHandle = NULL;
static void Close(HANDLE handle) { CloseHandle(handle); }
static constexpr HANDLE DefaultHandle = nullptr;
static void Close(HANDLE handle) noexcept { CloseHandle(handle); }
};
struct FindFileHandleTraits
{
using HandleType = HANDLE;
static const HANDLE DefaultHandle;
static void Close(HANDLE handle) { FindClose(handle); }
static void Close(HANDLE handle) noexcept { FindClose(handle); }
};
struct ModuleHandleTraits
{
using HandleType = HMODULE;
static constexpr HMODULE DefaultHandle = NULL;
static void Close(HMODULE handle) { FreeModule(handle); }
static constexpr HMODULE DefaultHandle = nullptr;
static void Close(HMODULE handle) noexcept { FreeModule(handle); }
};
// Code analysis doesn't like nullptr usages via traits
#pragma warning( push )
#pragma warning ( disable : 26477 ) // disable Use 'nullptr' rather than 0 or NULL (es.47).
template<typename traits>
class HandleWrapper
{
public:
using HandleType = typename traits::HandleType;
HandleWrapper(HandleType handle = traits::DefaultHandle) : m_handle(handle) { }
HandleWrapper(HandleType handle = traits::DefaultHandle) noexcept : m_handle(handle) { }
~HandleWrapper()
{
if (m_handle != traits::DefaultHandle)
@ -49,15 +53,15 @@ public:
}
}
operator HandleType() { return m_handle; }
HandleWrapper& operator =(HandleType value)
operator HandleType() noexcept { return m_handle; }
HandleWrapper& operator =(HandleType value) noexcept
{
DBG_ASSERT(m_handle == traits::DefaultHandle);
m_handle = value;
return *this;
}
HandleType* operator&() { return &m_handle; }
HandleType* operator&() noexcept { return &m_handle; }
HandleType release() noexcept
{
@ -69,3 +73,5 @@ public:
private:
HandleType m_handle;
};
#pragma warning( pop )

View File

@ -14,7 +14,7 @@ public:
Start() = 0;
virtual
~IOutputManager() {};
~IOutputManager() = default;
virtual
bool

View File

@ -0,0 +1,22 @@
// 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 <string>
class InvalidOperationException: public std::runtime_error
{
public:
InvalidOperationException(std::wstring msg)
: runtime_error("InvalidOperationException"), message(std::move(msg))
{
}
std::wstring as_wstring() const
{
return message;
}
private:
std::wstring message;
};

View File

@ -27,13 +27,18 @@ LoggingHelpers::CreateLoggingProvider(
try
{
// Check if there is an existing active console window before redirecting
// Window == IISExpress with active console window, don't redirect to a pipe
// if true.
CONSOLE_SCREEN_BUFFER_INFO dummy;
if (fIsLoggingEnabled)
{
auto manager = std::make_unique<FileOutputManager>(fEnableNativeLogging);
hr = manager->Initialize(pwzStdOutFileName, pwzApplicationPath);
outputManager = std::move(manager);
}
else if (!GetConsoleWindow())
else if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &dummy))
{
outputManager = std::make_unique<PipeOutputManager>(fEnableNativeLogging);
}

View File

@ -0,0 +1,39 @@
// 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 "HandleWrapper.h"
#include "exceptions.h"
extern HMODULE g_hModule;
class ModuleHelpers
{
public:
static
void IncrementCurrentModuleRefCount(HandleWrapper<ModuleHandleTraits> &handle)
{
WCHAR path[MAX_PATH];
#pragma warning( push )
#pragma warning ( disable : 26485 ) // Calling WinAPI causes expected array to pointer decay
THROW_LAST_ERROR_IF(!GetModuleFileName(g_hModule, path, MAX_PATH));
THROW_LAST_ERROR_IF(!GetModuleHandleEx(0, path, &handle));
#pragma warning( pop )
}
template<typename Func>
static
Func GetKnownProcAddress(HMODULE hModule, LPCSTR lpProcName) {
#pragma warning( push )
#pragma warning ( disable : 26490 ) // Disable Don't use reinterpret_cast
auto proc = reinterpret_cast<Func>(GetProcAddress(hModule, lpProcName));
#pragma warning( pop )
THROW_LAST_ERROR_IF (!proc);
return proc;
}
};

View File

@ -6,6 +6,6 @@
class NonCopyable {
public:
NonCopyable() = default;
NonCopyable(const NonCopyable&) = default;
NonCopyable& operator=(const NonCopyable&) = default;
NonCopyable(const NonCopyable&) = delete;
NonCopyable& operator=(const NonCopyable&) = delete;
};

View File

@ -43,6 +43,17 @@ HRESULT PipeOutputManager::Start()
HANDLE hStdErrReadPipe;
HANDLE hStdErrWritePipe;
// To make Console.* functions work, allocate a console
// in the current process.
if (!AllocConsole())
{
// ERROR_ACCESS_DENIED means there is a console already present.
if (GetLastError() != ERROR_ACCESS_DENIED)
{
RETURN_LAST_ERROR();
}
}
RETURN_LAST_ERROR_IF(!CreatePipe(&hStdErrReadPipe, &hStdErrWritePipe, &saAttr, 0 /*nSize*/));
m_hErrReadPipe = hStdErrReadPipe;

View File

@ -0,0 +1,19 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
#pragma once
class ResultException: public std::runtime_error
{
public:
ResultException(HRESULT hr, LOCATION_ARGUMENTS_ONLY) :
runtime_error(format("HRESULT 0x%x returned at " LOCATION_FORMAT, hr, LOCATION_CALL_ONLY)),
m_hr(hr)
{
}
HRESULT GetResult() const noexcept { return m_hr; }
private:
HRESULT m_hr;
};

View File

@ -78,14 +78,14 @@ StdWrapper::StartRedirection()
if (fileDescriptor == -1)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
RETURN_HR(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
}
m_redirectedFile = _fdopen(fileDescriptor, "w");
if (m_redirectedFile == nullptr)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
RETURN_HR(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
}
// Set stdout/stderr to the newly created file.
@ -93,13 +93,13 @@ StdWrapper::StartRedirection()
if (dup2Result != 0)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
RETURN_HR(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
}
// Removes buffering from the output
if (setvbuf(m_stdStream, nullptr, _IONBF, 0) != 0)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
RETURN_HR(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
}
return S_OK;
@ -117,7 +117,7 @@ StdWrapper::StopRedirection() const
FILE * file = _fdopen(m_previousFileDescriptor, "w");
if (file == nullptr)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
RETURN_HR(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
}
RETURN_LAST_ERROR_IF(!SetStdHandle(m_stdHandleNumber, reinterpret_cast<HANDLE>(_get_osfhandle(m_previousFileDescriptor))));
@ -131,17 +131,17 @@ StdWrapper::StopRedirection() const
const auto dup2Result = _dup2(_fileno(file), _fileno(m_stdStream));
if (dup2Result != 0)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
RETURN_HR(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
}
if (setvbuf(m_stdStream, nullptr, _IONBF, 0) != 0)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
RETURN_HR(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
}
if (fclose(m_redirectedFile) != 0)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
RETURN_HR(HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
}
return S_OK;

View File

@ -15,19 +15,33 @@ template<typename ... Args>
[[nodiscard]]
std::wstring format(const std::wstring& format, Args ... args)
{
const size_t size = swprintf(nullptr, 0, format.c_str(), args ...) + 1; // Extra char for '\0'
std::unique_ptr<wchar_t[]> formattedBuffer(new wchar_t[size]);
swprintf(formattedBuffer.get(), size, format.c_str(), args ... );
return std::wstring(formattedBuffer.get(), formattedBuffer.get() + size - 1);
std::wstring result;
if (!format.empty())
{
const size_t size = swprintf(nullptr, 0, format.c_str(), args ...); // Extra char for '\0'
result.resize(size + 1);
if (swprintf(result.data(), result.size(), format.c_str(), args ... ) == -1)
{
throw std::system_error(std::error_code(errno, std::system_category()));
}
}
return result;
}
template<typename ... Args>
[[nodiscard]]
std::string format(const std::string& format, Args ... args)
{
const size_t size = snprintf(nullptr, 0, format.c_str(), args ...) + 1; // Extra char for '\0'
std::unique_ptr<char[]> formattedBuffer(new char[size]);
snprintf(formattedBuffer.get(), size, format.c_str(), args ... );
return std::string(formattedBuffer.get(), formattedBuffer.get() + size - 1);
std::string result;
if (!format.empty())
{
const size_t size = snprintf(nullptr, 0, format.c_str(), args ...); // Extra char for '\0'
result.resize(size + 1);
if (snprintf(result.data(), result.size(), format.c_str(), args ... ) == -1)
{
throw std::system_error(std::error_code(errno, std::system_category()));
}
}
return result;
}

View File

@ -28,6 +28,17 @@ std::optional<bool> WebConfigConfigurationSection::GetBool(const std::wstring& n
return std::make_optional(result);
}
std::optional<DWORD> WebConfigConfigurationSection::GetLong(const std::wstring& name) const
{
DWORD result;
if (FAILED_LOG(GetElementDWORDProperty(m_element, name.c_str(), &result)))
{
return std::nullopt;
}
return std::make_optional(result);
}
std::optional<DWORD> WebConfigConfigurationSection::GetTimespan(const std::wstring& name) const
{
ULONGLONG result;

View File

@ -17,6 +17,7 @@ public:
std::optional<std::wstring> GetString(const std::wstring& name) const override;
std::optional<bool> GetBool(const std::wstring& name) const override;
std::optional<DWORD> GetLong(const std::wstring& name) const override;
std::optional<DWORD> GetTimespan(const std::wstring& name) const override;
std::vector<std::pair<std::wstring, std::wstring>> GetKeyValuePairs(const std::wstring& name) const override;

View File

@ -9,7 +9,7 @@
class WebConfigConfigurationSource: public ConfigurationSource
{
public:
WebConfigConfigurationSource(IAppHostAdminManager *pAdminManager, IHttpApplication &pHttpApplication)
WebConfigConfigurationSource(IAppHostAdminManager *pAdminManager, const IHttpApplication &pHttpApplication) noexcept
: m_manager(pAdminManager),
m_application(pHttpApplication)
{
@ -19,5 +19,5 @@ public:
private:
CComPtr<IAppHostAdminManager> m_manager;
IHttpApplication &m_application;
const IHttpApplication &m_application;
};

View File

@ -7,6 +7,7 @@
#include "iapplication.h"
#include "ntassert.h"
#include "SRWExclusiveLock.h"
#include "SRWSharedLock.h"
class APPLICATION : public IAPPLICATION
{
@ -15,11 +16,6 @@ public:
APPLICATION(const APPLICATION&) = delete;
const APPLICATION& operator=(const APPLICATION&) = delete;
APPLICATION_STATUS
QueryStatus() override
{
return m_fStopCalled ? APPLICATION_STATUS::RECYCLED : APPLICATION_STATUS::RUNNING;
}
APPLICATION(const IHttpApplication& pHttpApplication)
: m_fStopCalled(false),
@ -32,6 +28,12 @@ public:
m_applicationVirtualPath = ToVirtualPath(m_applicationConfigPath);
}
APPLICATION_STATUS
QueryStatus() override
{
SRWSharedLock stateLock(m_stateLock);
return m_fStopCalled ? APPLICATION_STATUS::RECYCLED : APPLICATION_STATUS::RUNNING;
}
VOID
Stop(bool fServerInitiated) override
@ -56,7 +58,7 @@ public:
}
VOID
ReferenceApplication() override
ReferenceApplication() noexcept override
{
DBG_ASSERT(m_cRefs > 0);
@ -64,7 +66,7 @@ public:
}
VOID
DereferenceApplication() override
DereferenceApplication() noexcept override
{
DBG_ASSERT(m_cRefs > 0);
@ -75,25 +77,25 @@ public:
}
const std::wstring&
QueryApplicationId() const
QueryApplicationId() const noexcept
{
return m_applicationId;
}
const std::wstring&
QueryApplicationPhysicalPath() const
QueryApplicationPhysicalPath() const noexcept
{
return m_applicationPhysicalPath;
}
const std::wstring&
QueryApplicationVirtualPath() const
QueryApplicationVirtualPath() const noexcept
{
return m_applicationVirtualPath;
}
const std::wstring&
QueryConfigPath() const
QueryConfigPath() const noexcept
{
return m_applicationConfigPath;
}

View File

@ -201,6 +201,12 @@ Language=English
%1
.
Messageid=1036
SymbolicName=ASPNETCORE_EVENT_DEBUG_LOG
Language=English
%1
.
;
;#endif // _ASPNETCORE_MODULE_MSG_H_

View File

@ -1,2 +0,0 @@
LANGUAGE 0x9,0x1
1 11 "MSG00001.bin"

View File

@ -3,17 +3,19 @@
#include "debugutil.h"
#include <array>
#include <string>
#include "dbgutil.h"
#include "stringu.h"
#include "stringa.h"
#include "dbgutil.h"
#include "Environment.h"
#include "SRWExclusiveLock.h"
#include "exceptions.h"
#include "atlbase.h"
#include "config_utility.h"
#include "StringHelpers.h"
#include "aspnetcore_msg.h"
#include "EventLog.h"
inline HANDLE g_logFile = INVALID_HANDLE_VALUE;
inline HMODULE g_hModule;
@ -23,7 +25,7 @@ HRESULT
PrintDebugHeader()
{
// Major, minor are stored in dwFileVersionMS field and patch, build in dwFileVersionLS field as pair of 32 bit numbers
DebugPrintfW(ASPNETCORE_DEBUG_FLAG_INFO, L"Initializing logs for '%ls'. %ls. %ls.",
LOG_INFOF(L"Initializing logs for '%ls'. %ls. %ls.",
GetModuleName().c_str(),
GetProcessIdString().c_str(),
GetVersionInfoString().c_str()
@ -92,26 +94,6 @@ GetModuleName()
void SetDebugFlags(const std::wstring &debugValue)
{
try
{
if (!debugValue.empty() && debugValue.find_first_not_of(L"0123456789") == std::wstring::npos)
{
const auto value = std::stoi(debugValue);
if (value >= 1) DEBUG_FLAGS_VAR |= ASPNETCORE_DEBUG_FLAG_ERROR;
if (value >= 2) DEBUG_FLAGS_VAR |= ASPNETCORE_DEBUG_FLAG_WARNING;
if (value >= 3) DEBUG_FLAGS_VAR |= ASPNETCORE_DEBUG_FLAG_INFO;
if (value >= 4) DEBUG_FLAGS_VAR |= ASPNETCORE_DEBUG_FLAG_CONSOLE;
if (value >= 5) DEBUG_FLAGS_VAR |= ASPNETCORE_DEBUG_FLAG_FILE;
return;
}
}
catch (...)
{
// ignore
}
try
{
std::wstringstream stringStream(debugValue);
@ -122,14 +104,16 @@ void SetDebugFlags(const std::wstring &debugValue)
if (_wcsnicmp(flag.c_str(), L"error", wcslen(L"error")) == 0) DEBUG_FLAGS_VAR |= DEBUG_FLAGS_ERROR;
if (_wcsnicmp(flag.c_str(), L"warning", wcslen(L"warning")) == 0) DEBUG_FLAGS_VAR |= DEBUG_FLAGS_WARN;
if (_wcsnicmp(flag.c_str(), L"info", wcslen(L"info")) == 0) DEBUG_FLAGS_VAR |= DEBUG_FLAGS_INFO;
if (_wcsnicmp(flag.c_str(), L"trace", wcslen(L"trace")) == 0) DEBUG_FLAGS_VAR |= DEBUG_FLAGS_TRACE;
if (_wcsnicmp(flag.c_str(), L"console", wcslen(L"console")) == 0) DEBUG_FLAGS_VAR |= ASPNETCORE_DEBUG_FLAG_CONSOLE;
if (_wcsnicmp(flag.c_str(), L"file", wcslen(L"file")) == 0) DEBUG_FLAGS_VAR |= ASPNETCORE_DEBUG_FLAG_FILE;
if (_wcsnicmp(flag.c_str(), L"eventlog", wcslen(L"eventlog")) == 0) DEBUG_FLAGS_VAR |= ASPNETCORE_DEBUG_FLAG_EVENTLOG;
}
// If file or console is enabled but level is not set, enable all levels
// If file or console is enabled but level is not set, enable levels up to info
if (DEBUG_FLAGS_VAR != 0 && (DEBUG_FLAGS_VAR & DEBUG_FLAGS_ANY) == 0)
{
DEBUG_FLAGS_VAR |= DEBUG_FLAGS_ANY;
DEBUG_FLAGS_VAR |= DEBUG_FLAGS_INFO;
}
}
catch (...)
@ -209,7 +193,7 @@ DebugInitialize(HMODULE hModule)
try
{
SetDebugFlags(Environment::GetEnvironmentVariableValue(L"ASPNETCORE_MODULE_DEBUG").value_or(L"0"));
SetDebugFlags(Environment::GetEnvironmentVariableValue(L"ASPNETCORE_MODULE_DEBUG").value_or(L""));
}
catch (...)
{
@ -344,6 +328,24 @@ DebugPrintW(
FlushFileBuffers(g_logFile);
}
}
if (IsEnabled(ASPNETCORE_DEBUG_FLAG_EVENTLOG))
{
WORD eventType;
switch (dwFlag)
{
case ASPNETCORE_DEBUG_FLAG_ERROR:
eventType = EVENTLOG_ERROR_TYPE;
break;
case ASPNETCORE_DEBUG_FLAG_WARNING:
eventType = EVENTLOG_WARNING_TYPE;
break;
default:
eventType = EVENTLOG_INFORMATION_TYPE;
break;
}
EventLog::LogEventNoTrace(eventType, ASPNETCORE_EVENT_DEBUG_LOG, strOutput.QueryStr());
}
}
}

View File

@ -8,11 +8,16 @@
#include <Windows.h>
#include "dbgutil.h"
#define ASPNETCORE_DEBUG_FLAG_TRACE DEBUG_FLAG_TRACE
#define ASPNETCORE_DEBUG_FLAG_INFO DEBUG_FLAG_INFO
#define ASPNETCORE_DEBUG_FLAG_WARNING DEBUG_FLAG_WARN
#define ASPNETCORE_DEBUG_FLAG_ERROR DEBUG_FLAG_ERROR
#define ASPNETCORE_DEBUG_FLAG_CONSOLE 0x00000008
#define ASPNETCORE_DEBUG_FLAG_FILE 0x00000010
#define ASPNETCORE_DEBUG_FLAG_CONSOLE 0x00000010
#define ASPNETCORE_DEBUG_FLAG_FILE 0x00000020
#define ASPNETCORE_DEBUG_FLAG_EVENTLOG 0x00000040
#define LOG_TRACE(...) DebugPrintW(ASPNETCORE_DEBUG_FLAG_TRACE, __VA_ARGS__)
#define LOG_TRACEF(...) DebugPrintfW(ASPNETCORE_DEBUG_FLAG_TRACE, __VA_ARGS__)
#define LOG_INFO(...) DebugPrintW(ASPNETCORE_DEBUG_FLAG_INFO, __VA_ARGS__)
#define LOG_INFOF(...) DebugPrintfW(ASPNETCORE_DEBUG_FLAG_INFO, __VA_ARGS__)

View File

@ -3,10 +3,12 @@
#pragma once
#include <exception>
#include <system_error>
#include "debugutil.h"
#include "StringHelpers.h"
#include "InvalidOperationException.h"
#define LOCATION_INFO_ENABLED TRUE
@ -29,22 +31,38 @@
#define OBSERVE_CAUGHT_EXCEPTION() CaughtExceptionHResult(LOCATION_INFO);
#define RETURN_CAUGHT_EXCEPTION() return CaughtExceptionHResult(LOCATION_INFO);
#define RETURN_HR(hr) do { HRESULT __hrRet = hr; if (FAILED(__hrRet)) { LogHResultFailed(LOCATION_INFO, __hrRet); } return __hrRet; } while (0, 0)
#define _CHECK_FAILED(expr) __pragma(warning(push)) \
__pragma(warning(disable:4127)) /*disable condition is const warning*/ \
FAILED(expr) \
__pragma(warning(pop))
#define _HR_RET(hr) __pragma(warning(push)) \
__pragma(warning(disable:26498)) /*disable constexpr warning */ \
const HRESULT __hrRet = hr; \
__pragma(warning(pop))
#define RETURN_HR(hr) do { _HR_RET(hr); if (_CHECK_FAILED(__hrRet)) { LogHResultFailed(LOCATION_INFO, __hrRet); } return __hrRet; } while (0, 0)
#define RETURN_LAST_ERROR() do { return LogLastError(LOCATION_INFO); } while (0, 0)
#define RETURN_IF_FAILED(hr) do { HRESULT __hrRet = hr; if (FAILED(__hrRet)) { LogHResultFailed(LOCATION_INFO, __hrRet); return __hrRet; }} while (0, 0)
#define RETURN_IF_FAILED(hr) do { _HR_RET(hr); if (FAILED(__hrRet)) { LogHResultFailed(LOCATION_INFO, __hrRet); return __hrRet; }} while (0, 0)
#define RETURN_LAST_ERROR_IF(condition) do { if (condition) { return LogLastError(LOCATION_INFO); }} while (0, 0)
#define RETURN_LAST_ERROR_IF_NULL(ptr) do { if ((ptr) == nullptr) { return LogLastError(LOCATION_INFO); }} while (0, 0)
#define FINISHED(hrr) do { HRESULT __hrRet = hrr; LogHResultFailed(LOCATION_INFO, __hrRet); hr = __hrRet; goto Finished; } while (0, 0)
#define FINISHED_IF_FAILED(hrr) do { HRESULT __hrRet = hrr; if (FAILED(__hrRet)) { LogHResultFailed(LOCATION_INFO, __hrRet); hr = __hrRet; goto Finished; }} while (0, 0)
#define FINISHED_IF_NULL_ALLOC(ptr) do { if ((ptr) == nullptr) { hr = LogHResultFailed(LOCATION_INFO, E_OUTOFMEMORY); goto Finished; }} while (0, 0)
#define FINISHED_LAST_ERROR_IF(condition) do { if (condition) { hr = LogLastError(LOCATION_INFO); goto Finished; }} while (0, 0)
#define FINISHED_LAST_ERROR_IF_NULL(ptr) do { if ((ptr) == nullptr) { hr = LogLastError(LOCATION_INFO); goto Finished; }} while (0, 0)
#define _GOTO_FINISHED() __pragma(warning(push)) \
__pragma(warning(disable:26438)) /*disable avoid goto warning*/ \
goto Finished \
__pragma(warning(pop))
#define THROW_LAST_ERROR() do { ThrowResultException(LogLastError(LOCATION_INFO)); } while (0, 0)
#define THROW_IF_FAILED(hr) do { HRESULT __hrRet = hr; if (FAILED(__hrRet)) { ThrowResultException(LOCATION_INFO, __hrRet); }} while (0, 0)
#define THROW_LAST_ERROR_IF(condition) do { if (condition) { ThrowResultException(LogLastError(LOCATION_INFO)); }} while (0, 0)
#define THROW_LAST_ERROR_IF_NULL(ptr) do { if ((ptr) == nullptr) { ThrowResultException(LogLastError(LOCATION_INFO)); }} while (0, 0)
#define FINISHED(hrr) do { _HR_RET(hrr); if (_CHECK_FAILED(__hrRet)) { LogHResultFailed(LOCATION_INFO, __hrRet); } hr = __hrRet; _GOTO_FINISHED(); } while (0, 0)
#define FINISHED_IF_FAILED(hrr) do { _HR_RET(hrr); if (FAILED(__hrRet)) { LogHResultFailed(LOCATION_INFO, __hrRet); hr = __hrRet; _GOTO_FINISHED(); }} while (0, 0)
#define FINISHED_IF_NULL_ALLOC(ptr) do { if ((ptr) == nullptr) { hr = LogHResultFailed(LOCATION_INFO, E_OUTOFMEMORY); _GOTO_FINISHED(); }} while (0, 0)
#define FINISHED_LAST_ERROR_IF(condition) do { if (condition) { hr = LogLastError(LOCATION_INFO); _GOTO_FINISHED(); }} while (0, 0)
#define FINISHED_LAST_ERROR_IF_NULL(ptr) do { if ((ptr) == nullptr) { hr = LogLastError(LOCATION_INFO); _GOTO_FINISHED(); }} while (0, 0)
#define THROW_LAST_ERROR() do { ThrowResultException(LOCATION_INFO, LogLastError(LOCATION_INFO)); } while (0, 0)
#define THROW_IF_FAILED(hr) do { _HR_RET(hr); if (FAILED(__hrRet)) { ThrowResultException(LOCATION_INFO, __hrRet); }} while (0, 0)
#define THROW_LAST_ERROR_IF(condition) do { if (condition) { ThrowResultException(LOCATION_INFO, LogLastError(LOCATION_INFO)); }} while (0, 0)
#define THROW_LAST_ERROR_IF_NULL(ptr) do { if ((ptr) == nullptr) { ThrowResultException(LOCATION_INFO, LogLastError(LOCATION_INFO)); }} while (0, 0)
#define THROW_IF_NULL_ALLOC(ptr) Throw_IfNullAlloc(ptr)
@ -55,21 +73,24 @@
#define SUCCEEDED_LOG(hr) SUCCEEDED(LOG_IF_FAILED(hr))
#define FAILED_LOG(hr) FAILED(LOG_IF_FAILED(hr))
class ResultException: public std::runtime_error
{
public:
explicit ResultException(HRESULT hr, LOCATION_ARGUMENTS_ONLY) :
ResultException(HRESULT hr, LOCATION_ARGUMENTS_ONLY) :
runtime_error(format("HRESULT 0x%x returned at " LOCATION_FORMAT, hr, LOCATION_CALL_ONLY)),
m_hr(hr)
{
}
HRESULT GetResult() const { return m_hr; }
HRESULT GetResult() const noexcept { return m_hr; }
private:
HRESULT m_hr;
#pragma warning( push )
#pragma warning ( disable : 26495 ) // bug in CA: m_hr is reported as uninitialized
const HRESULT m_hr = S_OK;
};
#pragma warning( pop )
__declspec(noinline) inline VOID ReportUntypedException(LOCATION_ARGUMENTS_ONLY)
{
@ -96,7 +117,7 @@ private:
return condition;
}
__declspec(noinline) inline VOID ReportException(LOCATION_ARGUMENTS std::exception& exception)
__declspec(noinline) inline VOID ReportException(LOCATION_ARGUMENTS const std::exception& exception)
{
DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR, "Exception '%s' caught at " LOCATION_FORMAT, exception.what(), LOCATION_CALL_ONLY);
}
@ -120,12 +141,12 @@ __declspec(noinline) inline HRESULT CaughtExceptionHResult(LOCATION_ARGUMENTS_ON
{
return E_OUTOFMEMORY;
}
catch (ResultException& exception)
catch (const ResultException& exception)
{
ReportException(LOCATION_CALL exception);
return exception.GetResult();
}
catch (std::exception& exception)
catch (const std::exception& exception)
{
ReportException(LOCATION_CALL exception);
return HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION);
@ -152,3 +173,7 @@ template <typename PointerT> auto Throw_IfNullAlloc(PointerT pointer)
}
return pointer;
}
__declspec(noinline) inline std::wstring GetUnexpectedExceptionMessage(const std::runtime_error& ex)
{
return format(L"Unexpected exception: %S", ex.what());
}

View File

@ -13,15 +13,15 @@ struct fx_ver_t
fx_ver_t(int major, int minor, int patch, const std::wstring& pre);
fx_ver_t(int major, int minor, int patch, const std::wstring& pre, const std::wstring& build);
int get_major() const { return m_major; }
int get_minor() const { return m_minor; }
int get_patch() const { return m_patch; }
int get_major() const noexcept { return m_major; }
int get_minor() const noexcept { return m_minor; }
int get_patch() const noexcept { return m_patch; }
void set_major(int m) { m_major = m; }
void set_minor(int m) { m_minor = m; }
void set_patch(int p) { m_patch = p; }
void set_major(int m) noexcept { m_major = m; }
void set_minor(int m) noexcept { m_minor = m; }
void set_patch(int p) noexcept { m_patch = p; }
bool is_prerelease() const { return !m_pre.empty(); }
bool is_prerelease() const noexcept { return !m_pre.empty(); }
std::wstring as_str() const;

View File

@ -41,7 +41,7 @@ HOSTFXR_UTILITY::GetHostFxrParameters(
}
else if (!ends_with(expandedProcessPath, L".exe", true))
{
throw StartupParametersResolutionException(format(L"Process path '%s' doesn't have '.exe' extension.", expandedProcessPath.c_str()));
throw InvalidOperationException(format(L"Process path '%s' doesn't have '.exe' extension.", expandedProcessPath.c_str()));
}
// Check if the absolute path is to dotnet or not.
@ -51,7 +51,7 @@ HOSTFXR_UTILITY::GetHostFxrParameters(
if (applicationArguments.empty())
{
throw StartupParametersResolutionException(L"Application arguments are empty.");
throw InvalidOperationException(L"Application arguments are empty.");
}
if (dotnetExePath.empty())
@ -92,7 +92,7 @@ HOSTFXR_UTILITY::GetHostFxrParameters(
LOG_INFOF(L"Checking application.dll at '%ls'", applicationDllPath.c_str());
if (!is_regular_file(applicationDllPath))
{
throw StartupParametersResolutionException(format(L"Application .dll was not found at %s", applicationDllPath.c_str()));
throw InvalidOperationException(format(L"Application .dll was not found at %s", applicationDllPath.c_str()));
}
hostFxrDllPath = executablePath.parent_path() / "hostfxr.dll";
@ -131,7 +131,7 @@ HOSTFXR_UTILITY::GetHostFxrParameters(
// If the processPath file does not exist and it doesn't include dotnet.exe or dotnet
// then it is an invalid argument.
//
throw StartupParametersResolutionException(format(L"Executable was not found at '%s'", executablePath.c_str()));
throw InvalidOperationException(format(L"Executable was not found at '%s'", executablePath.c_str()));
}
}
}
@ -185,7 +185,7 @@ HOSTFXR_UTILITY::AppendArguments(
auto pwzArgs = std::unique_ptr<LPWSTR[], LocalFreeDeleter>(CommandLineToArgvW(applicationArguments.c_str(), &argc));
if (!pwzArgs)
{
throw StartupParametersResolutionException(format(L"Unable parse command line arguments '%s'", applicationArguments.c_str()));
throw InvalidOperationException(format(L"Unable parse command line arguments '%s'", applicationArguments.c_str()));
}
for (int intArgsProcessed = 0; intArgsProcessed < argc; intArgsProcessed++)
@ -246,7 +246,7 @@ HOSTFXR_UTILITY::GetAbsolutePathToDotnet(
{
LOG_INFOF(L"Absolute path to dotnet.exe was not found at '%ls'", requestedPath.c_str());
throw StartupParametersResolutionException(format(L"Could not find dotnet.exe at '%s'", processPath.c_str()));
throw InvalidOperationException(format(L"Could not find dotnet.exe at '%s'", processPath.c_str()));
}
const auto dotnetViaWhere = InvokeWhereToFindDotnet();
@ -266,7 +266,7 @@ HOSTFXR_UTILITY::GetAbsolutePathToDotnet(
}
LOG_INFOF(L"dotnet.exe not found");
throw StartupParametersResolutionException(format(
throw InvalidOperationException(format(
L"Could not find dotnet.exe at '%s' or using the system PATH environment variable."
" Check that a valid path to dotnet is on the PATH and the bitness of dotnet matches the bitness of the IIS worker process.",
processPath.c_str()));
@ -284,14 +284,14 @@ HOSTFXR_UTILITY::GetAbsolutePathToHostFxr(
if (!is_directory(hostFxrBase))
{
throw StartupParametersResolutionException(format(L"Unable to find hostfxr directory at %s", hostFxrBase.c_str()));
throw InvalidOperationException(format(L"Unable to find hostfxr directory at %s", hostFxrBase.c_str()));
}
FindDotNetFolders(hostFxrBase, versionFolders);
if (versionFolders.empty())
{
throw StartupParametersResolutionException(format(L"Hostfxr directory '%s' doesn't contain any version subdirectories", hostFxrBase.c_str()));
throw InvalidOperationException(format(L"Hostfxr directory '%s' doesn't contain any version subdirectories", hostFxrBase.c_str()));
}
const auto highestVersion = FindHighestDotNetVersion(versionFolders);
@ -299,7 +299,7 @@ HOSTFXR_UTILITY::GetAbsolutePathToHostFxr(
if (!is_regular_file(hostFxrPath))
{
throw StartupParametersResolutionException(format(L"hostfxr.dll not found at '%s'", hostFxrPath.c_str()));
throw InvalidOperationException(format(L"hostfxr.dll not found at '%s'", hostFxrPath.c_str()));
}
LOG_INFOF(L"hostfxr.dll located at '%ls'", hostFxrPath.c_str());

View File

@ -29,20 +29,6 @@ public:
std::vector<std::wstring> &arguments
);
class StartupParametersResolutionException: public std::runtime_error
{
public:
StartupParametersResolutionException(std::wstring msg)
: runtime_error("Startup parameter resulution error occured"), message(std::move(msg))
{
}
std::wstring get_message() const { return message; }
private:
std::wstring message;
};
static
void
AppendArguments(
@ -96,7 +82,7 @@ private:
struct LocalFreeDeleter
{
void operator ()(LPWSTR* ptr) const
void operator ()(_In_ LPWSTR* ptr) const
{
LocalFree(ptr);
}

View File

@ -9,18 +9,19 @@
#include "EventLog.h"
HRESULT HOSTFXR_OPTIONS::Create(
_In_ PCWSTR pcwzDotnetExePath,
_In_ PCWSTR pcwzProcessPath,
_In_ PCWSTR pcwzApplicationPhysicalPath,
_In_ PCWSTR pcwzArguments,
_In_ const std::wstring& pcwzDotnetExePath,
_In_ const std::wstring& pcwzProcessPath,
_In_ const std::wstring& pcwzApplicationPhysicalPath,
_In_ const std::wstring& pcwzArguments,
_Out_ std::unique_ptr<HOSTFXR_OPTIONS>& ppWrapper)
{
std::filesystem::path knownDotnetLocation;
if (pcwzDotnetExePath != nullptr)
if (!pcwzDotnetExePath.empty())
{
knownDotnetLocation = pcwzDotnetExePath;
}
try
{
std::filesystem::path hostFxrDllPath;
@ -40,17 +41,25 @@ HRESULT HOSTFXR_OPTIONS::Create(
}
ppWrapper = std::make_unique<HOSTFXR_OPTIONS>(knownDotnetLocation, hostFxrDllPath, arguments);
}
catch (HOSTFXR_UTILITY::StartupParametersResolutionException &resolutionException)
catch (InvalidOperationException &ex)
{
OBSERVE_CAUGHT_EXCEPTION();
EventLog::Error(
ASPNETCORE_EVENT_INPROCESS_START_ERROR,
ASPNETCORE_EVENT_INPROCESS_START_ERROR_MSG,
pcwzApplicationPhysicalPath,
resolutionException.get_message().c_str());
pcwzApplicationPhysicalPath.c_str(),
ex.as_wstring().c_str());
return E_FAIL;
RETURN_CAUGHT_EXCEPTION();
}
catch (std::runtime_error &ex)
{
EventLog::Error(
ASPNETCORE_EVENT_INPROCESS_START_ERROR,
ASPNETCORE_EVENT_INPROCESS_START_ERROR_MSG,
pcwzApplicationPhysicalPath.c_str(),
GetUnexpectedExceptionMessage(ex).c_str());
RETURN_CAUGHT_EXCEPTION();
}
CATCH_RETURN();

View File

@ -17,7 +17,7 @@ public:
std::filesystem::path dotnetExeLocation,
std::filesystem::path hostFxrLocation,
std::vector<std::wstring> arguments
)
) noexcept
: m_dotnetExeLocation(std::move(dotnetExeLocation)),
m_hostFxrLocation(std::move(hostFxrLocation)),
m_arguments(std::move(arguments))
@ -27,7 +27,7 @@ public:
GetArguments(DWORD &hostfxrArgc, std::unique_ptr<PCWSTR[]> &hostfxrArgv) const
{
hostfxrArgc = static_cast<DWORD>(m_arguments.size());
hostfxrArgv = std::unique_ptr<PCWSTR[]>(new PCWSTR[hostfxrArgc]);
hostfxrArgv = std::make_unique<PCWSTR[]>(hostfxrArgc);
for (DWORD i = 0; i < hostfxrArgc; ++i)
{
hostfxrArgv[i] = m_arguments[i].c_str();
@ -35,23 +35,23 @@ public:
}
const std::filesystem::path&
GetHostFxrLocation() const
GetHostFxrLocation() const noexcept
{
return m_hostFxrLocation;
}
const std::filesystem::path&
GetDotnetExeLocation() const
GetDotnetExeLocation() const noexcept
{
return m_dotnetExeLocation;
}
static
HRESULT Create(
_In_ PCWSTR pcwzExeLocation,
_In_ PCWSTR pcwzProcessPath,
_In_ PCWSTR pcwzApplicationPhysicalPath,
_In_ PCWSTR pcwzArguments,
_In_ const std::wstring& pcwzExeLocation,
_In_ const std::wstring& pcwzProcessPath,
_In_ const std::wstring& pcwzApplicationPhysicalPath,
_In_ const std::wstring& pcwzArguments,
_Out_ std::unique_ptr<HOSTFXR_OPTIONS>& ppWrapper);
private:

View File

@ -44,7 +44,7 @@ public:
HRESULT
CreateHandler(
_In_ IHttpContext *pHttpContext,
_Out_ IREQUEST_HANDLER **pRequestHandler) = 0;
_Outptr_ IREQUEST_HANDLER **pRequestHandler) = 0;
};
struct IAPPLICATION_DELETER

View File

@ -14,13 +14,13 @@ class REQUEST_HANDLER: public virtual IREQUEST_HANDLER
public:
VOID
ReferenceRequestHandler() override
ReferenceRequestHandler() noexcept override
{
InterlockedIncrement(&m_cRefs);
}
VOID
DereferenceRequestHandler() override
DereferenceRequestHandler() noexcept override
{
DBG_ASSERT(m_cRefs != 0);

View File

@ -24,14 +24,14 @@
#define ASPNETCORE_EVENT_GRACEFUL_SHUTDOWN_FAILURE_MSG L"Failed to gracefully shutdown process '%d'."
#define ASPNETCORE_EVENT_SENT_SHUTDOWN_HTTP_REQUEST_MSG L"Sent shutdown HTTP message to process '%d' and received http status '%d'."
#define ASPNETCORE_EVENT_APP_SHUTDOWN_FAILURE_MSG L"Failed to gracefully shutdown application '%s'."
#define ASPNETCORE_EVENT_LOAD_CLR_FALIURE_MSG L"Application '%s' with physical root '%s' failed to load clr and managed application, ErrorCode = '0x%x."
#define ASPNETCORE_EVENT_LOAD_CLR_FALIURE_MSG L"Application '%s' with physical root '%s' failed to load clr and managed application. %s"
#define ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL_MSG L"Application '%s' has shutdown."
#define ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP_MSG L"Only one inprocess application is allowed per IIS application pool. Please assign the application '%s' to a different IIS application pool."
#define ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG L"Mixed hosting model is not supported. Application '%s' configured with different hostingModel value '%d' other than the one of running application(s)."
#define ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG L"Configuration load error. %s"
#define ASPNETCORE_EVENT_ADD_APPLICATION_ERROR_MSG L"Failed to start application '%s', ErrorCode '0x%x'."
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT_MSG L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, ErrorCode = '0x%x'. Last 4KB characters of captured stdout and stderr logs:\r\n%s"
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_MSG L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, ErrorCode = '0x%x'. Please check the stderr logs for more information."
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT_MSG L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, exit code = '%d'. Last 4KB characters of captured stdout and stderr logs:\r\n%s"
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_MSG L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, exit code = '%d'. Please check the stderr logs for more information."
#define ASPNETCORE_EVENT_APP_IN_SHUTDOWN_MSG L"Application shutting down."
#define ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_MSG L"Application '%s' was recycled after detecting the app_offline file."
#define ASPNETCORE_EVENT_MONITOR_APPOFFLINE_ERROR_MSG L"Monitoring app_offline.htm failed for application '%s', ErrorCode '0x%x'. "
@ -39,7 +39,8 @@
#define ASPNETCORE_EVENT_RECYCLE_FAILURE_CONFIGURATION_MSG L"Failed to recycle application due to a configuration change at '%s'. Recycling worker process."
#define ASPNETCORE_EVENT_MODULE_DISABLED_MSG L"AspNetCore Module is disabled"
#define ASPNETCORE_EVENT_HOSTFXR_DLL_INVALID_VERSION_MSG L"Hostfxr version used does not support 'hostfxr_get_native_search_directories', update the version of hostfxr to a higher version. Path to hostfxr: '%s'."
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION_MSG L"Application '%s' with physical root '%s' hit unexpected managed exception, ErrorCode = '0x%x. Please check the stderr logs for more information."
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION_MSG L"Application '%s' with physical root '%s' hit unexpected managed exception, exception code = '0x%x. Please check the stderr logs for more information."
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION_STDOUT_MSG L"Application '%s' with physical root '%s' hit unexpected managed exception, exception code = '0x%x. Last 4KB characters of captured stdout and stderr logs:\r\n%s"
#define ASPNETCORE_EVENT_INPROCESS_RH_ERROR_MSG L"Could not find the assembly '%s' for in-process application. Please confirm the Microsoft.AspNetCore.Server.IIS package is referenced in your application. Captured output: %s"
#define ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG L"Could not find the assembly '%s' for out-of-process application. Please confirm the assembly is installed correctly for IIS or IISExpress."
#define ASPNETCORE_EVENT_INPROCESS_START_SUCCESS_MSG L"Application '%s' started the coreclr in-process successfully."

View File

@ -0,0 +1,432 @@
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="DefaultRules" ToolsVersion="15.0">
<Include Path="allrules.ruleset" Action="Default" />
<Rules AnalyzerId="Microsoft.Analyzers.NativeCodeAnalysis" RuleNamespace="Microsoft.Rules.Native">
<Rule Id="C26100" Action="Error" />
<Rule Id="C26101" Action="Error" />
<Rule Id="C26105" Action="Error" />
<Rule Id="C26110" Action="Error" />
<Rule Id="C26111" Action="Error" />
<Rule Id="C26112" Action="Error" />
<Rule Id="C26115" Action="Error" />
<Rule Id="C26116" Action="Error" />
<Rule Id="C26117" Action="Error" />
<Rule Id="C26130" Action="Error" />
<Rule Id="C26135" Action="Error" />
<Rule Id="C26140" Action="Error" />
<Rule Id="C26160" Action="Error" />
<Rule Id="C26165" Action="Error" />
<Rule Id="C26166" Action="Error" />
<Rule Id="C26167" Action="Error" />
<Rule Id="C26400" Action="Error" />
<Rule Id="C26401" Action="Error" />
<Rule Id="C26402" Action="Error" />
<Rule Id="C26403" Action="Error" />
<Rule Id="C26404" Action="Error" />
<Rule Id="C26405" Action="Error" />
<Rule Id="C26406" Action="Error" />
<Rule Id="C26407" Action="Error" />
<Rule Id="C26408" Action="Error" />
<Rule Id="C26409" Action="Error" />
<Rule Id="C26410" Action="Error" />
<Rule Id="C26411" Action="Error" />
<Rule Id="C26414" Action="Error" />
<Rule Id="C26415" Action="Error" />
<Rule Id="C26416" Action="Error" />
<Rule Id="C26417" Action="Error" />
<Rule Id="C26418" Action="Error" />
<Rule Id="C26426" Action="Error" />
<Rule Id="C26427" Action="Error" />
<Rule Id="C26429" Action="None" />
<Rule Id="C26430" Action="Error" />
<Rule Id="C26431" Action="Error" />
<Rule Id="C26432" Action="None" />
<Rule Id="C26433" Action="Error" />
<Rule Id="C26434" Action="Error" />
<Rule Id="C26435" Action="Error" />
<Rule Id="C26436" Action="Error" />
<Rule Id="C26437" Action="Error" />
<Rule Id="C26438" Action="Error" />
<Rule Id="C26439" Action="Error" />
<Rule Id="C26440" Action="Error" />
<Rule Id="C26441" Action="Error" />
<Rule Id="C26443" Action="Error" />
<Rule Id="C26444" Action="Error" />
<Rule Id="C26445" Action="Error" />
<Rule Id="C26446" Action="None" />
<Rule Id="C26447" Action="Error" />
<Rule Id="C26448" Action="None" />
<Rule Id="C26449" Action="Error" />
<Rule Id="C26450" Action="Error" />
<Rule Id="C26451" Action="Error" />
<Rule Id="C26452" Action="Error" />
<Rule Id="C26453" Action="Error" />
<Rule Id="C26454" Action="Error" />
<Rule Id="C26459" Action="Error" />
<Rule Id="C26460" Action="Error" />
<Rule Id="C26461" Action="Error" />
<Rule Id="C26462" Action="Error" />
<Rule Id="C26463" Action="Error" />
<Rule Id="C26464" Action="Error" />
<Rule Id="C26465" Action="Error" />
<Rule Id="C26466" Action="Error" />
<Rule Id="C26471" Action="Error" />
<Rule Id="C26472" Action="None" />
<Rule Id="C26473" Action="Error" />
<Rule Id="C26474" Action="Error" />
<Rule Id="C26475" Action="Error" />
<Rule Id="C26476" Action="Error" />
<Rule Id="C26477" Action="Error" />
<Rule Id="C26481" Action="Error" />
<Rule Id="C26482" Action="Error" />
<Rule Id="C26483" Action="Error" />
<Rule Id="C26485" Action="Error" />
<Rule Id="C26486" Action="None" />
<Rule Id="C26487" Action="Error" />
<Rule Id="C26489" Action="None" />
<Rule Id="C26490" Action="Error" />
<Rule Id="C26491" Action="Error" />
<Rule Id="C26492" Action="Error" />
<Rule Id="C26493" Action="Error" />
<Rule Id="C26494" Action="Error" />
<Rule Id="C26495" Action="Error" />
<Rule Id="C26496" Action="Error" />
<Rule Id="C26497" Action="Error" />
<Rule Id="C26498" Action="Error" />
<Rule Id="C28020" Action="Error" />
<Rule Id="C28021" Action="Error" />
<Rule Id="C28022" Action="Error" />
<Rule Id="C28023" Action="Error" />
<Rule Id="C28024" Action="Error" />
<Rule Id="C28039" Action="Error" />
<Rule Id="C28101" Action="Error" />
<Rule Id="C28103" Action="Error" />
<Rule Id="C28104" Action="Error" />
<Rule Id="C28105" Action="Error" />
<Rule Id="C28106" Action="Error" />
<Rule Id="C28107" Action="Error" />
<Rule Id="C28108" Action="Error" />
<Rule Id="C28109" Action="Error" />
<Rule Id="C28110" Action="Error" />
<Rule Id="C28111" Action="Error" />
<Rule Id="C28112" Action="Error" />
<Rule Id="C28113" Action="Error" />
<Rule Id="C28114" Action="Error" />
<Rule Id="C28120" Action="Error" />
<Rule Id="C28121" Action="Error" />
<Rule Id="C28122" Action="Error" />
<Rule Id="C28123" Action="Error" />
<Rule Id="C28124" Action="Error" />
<Rule Id="C28125" Action="Error" />
<Rule Id="C28126" Action="Error" />
<Rule Id="C28127" Action="Error" />
<Rule Id="C28128" Action="Error" />
<Rule Id="C28129" Action="Error" />
<Rule Id="C28131" Action="Error" />
<Rule Id="C28132" Action="Error" />
<Rule Id="C28133" Action="Error" />
<Rule Id="C28134" Action="Error" />
<Rule Id="C28135" Action="Error" />
<Rule Id="C28137" Action="Error" />
<Rule Id="C28138" Action="Error" />
<Rule Id="C28141" Action="Error" />
<Rule Id="C28143" Action="Error" />
<Rule Id="C28144" Action="Error" />
<Rule Id="C28145" Action="Error" />
<Rule Id="C28146" Action="Error" />
<Rule Id="C28147" Action="Error" />
<Rule Id="C28150" Action="Error" />
<Rule Id="C28151" Action="Error" />
<Rule Id="C28152" Action="Error" />
<Rule Id="C28153" Action="Error" />
<Rule Id="C28156" Action="Error" />
<Rule Id="C28157" Action="Error" />
<Rule Id="C28158" Action="Error" />
<Rule Id="C28159" Action="Error" />
<Rule Id="C28160" Action="Error" />
<Rule Id="C28161" Action="Error" />
<Rule Id="C28162" Action="Error" />
<Rule Id="C28163" Action="Error" />
<Rule Id="C28164" Action="Error" />
<Rule Id="C28165" Action="Error" />
<Rule Id="C28166" Action="Error" />
<Rule Id="C28167" Action="Error" />
<Rule Id="C28168" Action="Error" />
<Rule Id="C28169" Action="Error" />
<Rule Id="C28170" Action="Error" />
<Rule Id="C28171" Action="Error" />
<Rule Id="C28172" Action="Error" />
<Rule Id="C28173" Action="Error" />
<Rule Id="C28175" Action="Error" />
<Rule Id="C28176" Action="Error" />
<Rule Id="C28182" Action="Error" />
<Rule Id="C28183" Action="Error" />
<Rule Id="C28193" Action="Error" />
<Rule Id="C28194" Action="Error" />
<Rule Id="C28195" Action="Error" />
<Rule Id="C28196" Action="Error" />
<Rule Id="C28197" Action="Error" />
<Rule Id="C28198" Action="Error" />
<Rule Id="C28199" Action="Error" />
<Rule Id="C28202" Action="Error" />
<Rule Id="C28203" Action="Error" />
<Rule Id="C28204" Action="Error" />
<Rule Id="C28205" Action="Error" />
<Rule Id="C28206" Action="Error" />
<Rule Id="C28207" Action="Error" />
<Rule Id="C28208" Action="Error" />
<Rule Id="C28209" Action="Error" />
<Rule Id="C28210" Action="Error" />
<Rule Id="C28211" Action="Error" />
<Rule Id="C28212" Action="Error" />
<Rule Id="C28213" Action="Error" />
<Rule Id="C28214" Action="Error" />
<Rule Id="C28215" Action="Error" />
<Rule Id="C28216" Action="Error" />
<Rule Id="C28217" Action="Error" />
<Rule Id="C28218" Action="Error" />
<Rule Id="C28219" Action="Error" />
<Rule Id="C28220" Action="Error" />
<Rule Id="C28221" Action="Error" />
<Rule Id="C28222" Action="Error" />
<Rule Id="C28223" Action="Error" />
<Rule Id="C28224" Action="Error" />
<Rule Id="C28225" Action="Error" />
<Rule Id="C28226" Action="Error" />
<Rule Id="C28227" Action="Error" />
<Rule Id="C28228" Action="Error" />
<Rule Id="C28229" Action="Error" />
<Rule Id="C28230" Action="Error" />
<Rule Id="C28231" Action="Error" />
<Rule Id="C28232" Action="Error" />
<Rule Id="C28233" Action="Error" />
<Rule Id="C28234" Action="Error" />
<Rule Id="C28235" Action="Error" />
<Rule Id="C28236" Action="Error" />
<Rule Id="C28237" Action="Error" />
<Rule Id="C28238" Action="Error" />
<Rule Id="C28239" Action="Error" />
<Rule Id="C28240" Action="Error" />
<Rule Id="C28241" Action="Error" />
<Rule Id="C28243" Action="Error" />
<Rule Id="C28244" Action="Error" />
<Rule Id="C28245" Action="Error" />
<Rule Id="C28246" Action="Error" />
<Rule Id="C28250" Action="Error" />
<Rule Id="C28251" Action="Error" />
<Rule Id="C28252" Action="Error" />
<Rule Id="C28253" Action="Error" />
<Rule Id="C28254" Action="Error" />
<Rule Id="C28260" Action="Error" />
<Rule Id="C28262" Action="Error" />
<Rule Id="C28263" Action="Error" />
<Rule Id="C28266" Action="Error" />
<Rule Id="C28267" Action="Error" />
<Rule Id="C28272" Action="Error" />
<Rule Id="C28273" Action="Error" />
<Rule Id="C28275" Action="Error" />
<Rule Id="C28278" Action="Error" />
<Rule Id="C28279" Action="Error" />
<Rule Id="C28280" Action="Error" />
<Rule Id="C28282" Action="Error" />
<Rule Id="C28283" Action="Error" />
<Rule Id="C28284" Action="Error" />
<Rule Id="C28285" Action="Error" />
<Rule Id="C28286" Action="Error" />
<Rule Id="C28287" Action="Error" />
<Rule Id="C28288" Action="Error" />
<Rule Id="C28289" Action="Error" />
<Rule Id="C28290" Action="Error" />
<Rule Id="C28291" Action="Error" />
<Rule Id="C28300" Action="Error" />
<Rule Id="C28301" Action="Error" />
<Rule Id="C28302" Action="Error" />
<Rule Id="C28303" Action="Error" />
<Rule Id="C28304" Action="Error" />
<Rule Id="C28305" Action="Error" />
<Rule Id="C28306" Action="Error" />
<Rule Id="C28307" Action="Error" />
<Rule Id="C28308" Action="Error" />
<Rule Id="C28309" Action="Error" />
<Rule Id="C28350" Action="Error" />
<Rule Id="C28351" Action="Error" />
<Rule Id="C28601" Action="Error" />
<Rule Id="C28602" Action="Error" />
<Rule Id="C28604" Action="Error" />
<Rule Id="C28615" Action="Error" />
<Rule Id="C28616" Action="Error" />
<Rule Id="C28617" Action="Error" />
<Rule Id="C28623" Action="Error" />
<Rule Id="C28624" Action="Error" />
<Rule Id="C28625" Action="Error" />
<Rule Id="C28636" Action="Error" />
<Rule Id="C28637" Action="Error" />
<Rule Id="C28638" Action="Error" />
<Rule Id="C28639" Action="Error" />
<Rule Id="C28640" Action="Error" />
<Rule Id="C28645" Action="Error" />
<Rule Id="C28648" Action="Error" />
<Rule Id="C28649" Action="Error" />
<Rule Id="C28650" Action="Error" />
<Rule Id="C28714" Action="Error" />
<Rule Id="C28715" Action="Error" />
<Rule Id="C28716" Action="Error" />
<Rule Id="C28717" Action="Error" />
<Rule Id="C28719" Action="Error" />
<Rule Id="C28720" Action="Error" />
<Rule Id="C28721" Action="Error" />
<Rule Id="C28726" Action="Error" />
<Rule Id="C28727" Action="Error" />
<Rule Id="C28730" Action="Error" />
<Rule Id="C28735" Action="Error" />
<Rule Id="C28736" Action="Error" />
<Rule Id="C28750" Action="Error" />
<Rule Id="C28751" Action="Error" />
<Rule Id="C6001" Action="Error" />
<Rule Id="C6011" Action="Error" />
<Rule Id="C6014" Action="Error" />
<Rule Id="C6029" Action="Error" />
<Rule Id="C6031" Action="Error" />
<Rule Id="C6053" Action="Error" />
<Rule Id="C6054" Action="Error" />
<Rule Id="C6059" Action="Error" />
<Rule Id="C6063" Action="Error" />
<Rule Id="C6064" Action="Error" />
<Rule Id="C6066" Action="Error" />
<Rule Id="C6067" Action="Error" />
<Rule Id="C6101" Action="Error" />
<Rule Id="C6200" Action="Error" />
<Rule Id="C6201" Action="Error" />
<Rule Id="C6211" Action="Error" />
<Rule Id="C6214" Action="Error" />
<Rule Id="C6215" Action="Error" />
<Rule Id="C6216" Action="Error" />
<Rule Id="C6217" Action="Error" />
<Rule Id="C6219" Action="Error" />
<Rule Id="C6220" Action="Error" />
<Rule Id="C6221" Action="Error" />
<Rule Id="C6225" Action="Error" />
<Rule Id="C6226" Action="Error" />
<Rule Id="C6230" Action="Error" />
<Rule Id="C6235" Action="Error" />
<Rule Id="C6236" Action="Error" />
<Rule Id="C6237" Action="Error" />
<Rule Id="C6239" Action="Error" />
<Rule Id="C6240" Action="Error" />
<Rule Id="C6242" Action="Error" />
<Rule Id="C6244" Action="Error" />
<Rule Id="C6246" Action="Error" />
<Rule Id="C6248" Action="Error" />
<Rule Id="C6250" Action="Error" />
<Rule Id="C6255" Action="Error" />
<Rule Id="C6258" Action="Error" />
<Rule Id="C6259" Action="Error" />
<Rule Id="C6260" Action="Error" />
<Rule Id="C6262" Action="Error" />
<Rule Id="C6263" Action="Error" />
<Rule Id="C6268" Action="Error" />
<Rule Id="C6269" Action="Error" />
<Rule Id="C6270" Action="Error" />
<Rule Id="C6271" Action="Error" />
<Rule Id="C6272" Action="Error" />
<Rule Id="C6273" Action="Error" />
<Rule Id="C6274" Action="Error" />
<Rule Id="C6276" Action="Error" />
<Rule Id="C6277" Action="Error" />
<Rule Id="C6278" Action="Error" />
<Rule Id="C6279" Action="Error" />
<Rule Id="C6280" Action="Error" />
<Rule Id="C6281" Action="Error" />
<Rule Id="C6282" Action="Error" />
<Rule Id="C6283" Action="Error" />
<Rule Id="C6284" Action="Error" />
<Rule Id="C6285" Action="Error" />
<Rule Id="C6286" Action="Error" />
<Rule Id="C6287" Action="Error" />
<Rule Id="C6288" Action="Error" />
<Rule Id="C6289" Action="Error" />
<Rule Id="C6290" Action="Error" />
<Rule Id="C6291" Action="Error" />
<Rule Id="C6292" Action="Error" />
<Rule Id="C6293" Action="Error" />
<Rule Id="C6294" Action="Error" />
<Rule Id="C6295" Action="Error" />
<Rule Id="C6296" Action="Error" />
<Rule Id="C6297" Action="Error" />
<Rule Id="C6298" Action="Error" />
<Rule Id="C6299" Action="Error" />
<Rule Id="C6302" Action="Error" />
<Rule Id="C6303" Action="Error" />
<Rule Id="C6305" Action="Error" />
<Rule Id="C6306" Action="Error" />
<Rule Id="C6308" Action="Error" />
<Rule Id="C6310" Action="Error" />
<Rule Id="C6312" Action="Error" />
<Rule Id="C6313" Action="Error" />
<Rule Id="C6314" Action="Error" />
<Rule Id="C6315" Action="Error" />
<Rule Id="C6316" Action="Error" />
<Rule Id="C6317" Action="Error" />
<Rule Id="C6318" Action="Error" />
<Rule Id="C6319" Action="Error" />
<Rule Id="C6320" Action="Error" />
<Rule Id="C6322" Action="Error" />
<Rule Id="C6323" Action="Error" />
<Rule Id="C6324" Action="Error" />
<Rule Id="C6326" Action="Error" />
<Rule Id="C6328" Action="Error" />
<Rule Id="C6329" Action="Error" />
<Rule Id="C6330" Action="Error" />
<Rule Id="C6331" Action="Error" />
<Rule Id="C6332" Action="Error" />
<Rule Id="C6333" Action="Error" />
<Rule Id="C6334" Action="Error" />
<Rule Id="C6335" Action="Error" />
<Rule Id="C6336" Action="Error" />
<Rule Id="C6340" Action="Error" />
<Rule Id="C6381" Action="Error" />
<Rule Id="C6383" Action="Error" />
<Rule Id="C6384" Action="Error" />
<Rule Id="C6385" Action="Error" />
<Rule Id="C6386" Action="Error" />
<Rule Id="C6387" Action="Error" />
<Rule Id="C6388" Action="Error" />
<Rule Id="C6400" Action="Error" />
<Rule Id="C6401" Action="Error" />
<Rule Id="C6411" Action="Error" />
<Rule Id="C6412" Action="Error" />
<Rule Id="C6500" Action="Error" />
<Rule Id="C6501" Action="Error" />
<Rule Id="C6503" Action="Error" />
<Rule Id="C6504" Action="Error" />
<Rule Id="C6505" Action="Error" />
<Rule Id="C6506" Action="Error" />
<Rule Id="C6508" Action="Error" />
<Rule Id="C6509" Action="Error" />
<Rule Id="C6510" Action="Error" />
<Rule Id="C6511" Action="Error" />
<Rule Id="C6513" Action="Error" />
<Rule Id="C6514" Action="Error" />
<Rule Id="C6515" Action="Error" />
<Rule Id="C6516" Action="Error" />
<Rule Id="C6517" Action="Error" />
<Rule Id="C6518" Action="Error" />
<Rule Id="C6522" Action="Error" />
<Rule Id="C6525" Action="Error" />
<Rule Id="C6527" Action="Error" />
<Rule Id="C6530" Action="Error" />
<Rule Id="C6540" Action="Error" />
<Rule Id="C6551" Action="Error" />
<Rule Id="C6552" Action="Error" />
<Rule Id="C6701" Action="Error" />
<Rule Id="C6702" Action="Error" />
<Rule Id="C6703" Action="Error" />
<Rule Id="C6704" Action="Error" />
<Rule Id="C6705" Action="Error" />
<Rule Id="C6706" Action="Error" />
<Rule Id="C6707" Action="Error" />
<Rule Id="C6993" Action="Error" />
<Rule Id="C6995" Action="Error" />
<Rule Id="C6997" Action="Error" />
</Rules>
</RuleSet>

View File

@ -3,6 +3,9 @@
#include "precomp.h"
#pragma warning( push )
#pragma warning ( disable : ALL_CODE_ANALYSIS_WARNINGS )
LONG ALLOC_CACHE_HANDLER::sm_nFillPattern = 0xACA50000;
HANDLE ALLOC_CACHE_HANDLER::sm_hHeap;
@ -440,4 +443,6 @@ Finished:
}
return fRet;
}
}
#pragma warning( pop )

View File

@ -4,7 +4,10 @@
#pragma once
#include <crtdbg.h>
#include <CodeAnalysis/Warnings.h>
#pragma warning( push )
#pragma warning ( disable : ALL_CODE_ANALYSIS_WARNINGS )
//
// BUFFER_T class shouldn't be used directly. Use BUFFER specialization class instead.
@ -269,3 +272,5 @@ C_ASSERT( sizeof(VOID*) <= sizeof(ULONGLONG) );
#define INLINE_BUFFER_INIT( _name ) \
_name( (BYTE*)__aqw##_name, sizeof( __aqw##_name ) )
#pragma warning( pop )

View File

@ -21,19 +21,21 @@
// Debug error levels for DEBUG_FLAGS_VAR.
//
#define DEBUG_FLAG_INFO 0x00000001
#define DEBUG_FLAG_WARN 0x00000002
#define DEBUG_FLAG_ERROR 0x00000004
#define DEBUG_FLAG_TRACE 0x00000001
#define DEBUG_FLAG_INFO 0x00000002
#define DEBUG_FLAG_WARN 0x00000004
#define DEBUG_FLAG_ERROR 0x00000008
//
// Predefined error level values. These are backwards from the
// windows definitions.
//
#define DEBUG_FLAGS_TRACE (DEBUG_FLAG_ERROR | DEBUG_FLAG_WARN | DEBUG_FLAG_INFO | DEBUG_FLAG_TRACE)
#define DEBUG_FLAGS_INFO (DEBUG_FLAG_ERROR | DEBUG_FLAG_WARN | DEBUG_FLAG_INFO)
#define DEBUG_FLAGS_WARN (DEBUG_FLAG_ERROR | DEBUG_FLAG_WARN)
#define DEBUG_FLAGS_ERROR (DEBUG_FLAG_ERROR)
#define DEBUG_FLAGS_ANY (DEBUG_FLAG_INFO | DEBUG_FLAG_WARN | DEBUG_FLAG_ERROR)
#define DEBUG_FLAGS_ANY (DEBUG_FLAG_INFO | DEBUG_FLAG_WARN | DEBUG_FLAG_ERROR | DEBUG_FLAG_TRACE)
//
// Global variables to control tracing. Generally per module

View File

@ -6,6 +6,10 @@
#include "stringu.h"
#include "ntassert.h"
#include <CodeAnalysis/Warnings.h>
#pragma warning( push )
#pragma warning ( disable : ALL_CODE_ANALYSIS_WARNINGS )
/*++
class MULTISZ:
@ -221,5 +225,6 @@ SplitCommaDelimitedString(
MULTISZ * pmszList
);
#endif // !_MULTISZ_HXX_
#pragma warning( pop )
#endif // !_MULTISZ_HXX_

View File

@ -3,6 +3,9 @@
#pragma once
#pragma warning( push )
#pragma warning ( disable : 26451 )
template<typename T>
class PER_CPU
{
@ -302,4 +305,6 @@ Return:
*pCacheLineSize = SYSTEM_CACHE_ALIGNMENT_SIZE;
return S_OK;
}
}
#pragma warning( pop )

View File

@ -7,6 +7,10 @@
#include "macros.h"
#include <strsafe.h>
#pragma warning( push )
#pragma warning ( disable : ALL_CODE_ANALYSIS_WARNINGS )
class STRA
{
@ -513,3 +517,5 @@ CHAR* InitHelper(__out CHAR (&psz)[size])
STRA name;
#define INLINE_STRA_INIT(name) name(InitHelper(__ach##name), sizeof(__ach##name))
#pragma warning( pop )

View File

@ -1,10 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
#pragma warning (disable : 4267)
#include "precomp.h"
#pragma warning( push )
#pragma warning ( disable : 4267 ALL_CODE_ANALYSIS_WARNINGS )
STRU::STRU(
VOID
) : m_cchLen( 0 )
@ -1199,25 +1201,17 @@ STRU::ExpandEnvironmentVariables(
__out STRU * pstrExpandedString
)
/*++
Routine Description:
Expand the environment variables in a string
Arguments:
pszString - String with environment variables to expand
pstrExpandedString - Receives expanded string on success
Return Value:
HRESULT
--*/
{
HRESULT hr = S_OK;
DWORD cchNewSize = 0;
if ( pszString == NULL ||
pstrExpandedString == NULL )
{
@ -1225,7 +1219,6 @@ Return Value:
hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
goto Exit;
}
cchNewSize = ExpandEnvironmentStrings( pszString,
pstrExpandedString->QueryStr(),
pstrExpandedString->QuerySizeCCH() );
@ -1234,7 +1227,6 @@ Return Value:
hr = HRESULT_FROM_WIN32( GetLastError() );
goto Exit;
}
if ( cchNewSize > pstrExpandedString->QuerySizeCCH() )
{
hr = pstrExpandedString->Resize(
@ -1244,13 +1236,11 @@ Return Value:
{
goto Exit;
}
cchNewSize = ExpandEnvironmentStrings(
pszString,
pstrExpandedString->QueryStr(),
pstrExpandedString->QuerySizeCCH()
);
if ( cchNewSize == 0 ||
cchNewSize > pstrExpandedString->QuerySizeCCH() )
{
@ -1258,14 +1248,10 @@ Return Value:
goto Exit;
}
}
pstrExpandedString->SyncWithBuffer();
hr = S_OK;
Exit:
return hr;
}
#pragma warning(default:4267)
#pragma warning( pop )

View File

@ -4,8 +4,12 @@
#pragma once
#include "buffer.h"
#include <CodeAnalysis/Warnings.h>
#include <strsafe.h>
#pragma warning( push )
#pragma warning ( disable : ALL_CODE_ANALYSIS_WARNINGS )
class STRU
{
@ -349,13 +353,12 @@ public:
__in PCWSTR pwszFormatString,
va_list argsList
);
static
HRESULT ExpandEnvironmentVariables(
__in PCWSTR pszString,
__out STRU * pstrExpandedString
);
private:
//
@ -425,3 +428,4 @@ MakePathCanonicalizationProof(
IN PCWSTR pszName,
OUT STRU * pstrPath
);
#pragma warning( pop )

View File

@ -3,8 +3,6 @@
#include "InProcessApplicationBase.h"
hostfxr_main_fn InProcessApplicationBase::s_fMainCallback = NULL;
InProcessApplicationBase::InProcessApplicationBase(
IHttpServer& pHttpServer,
IHttpApplication& pHttpApplication)
@ -35,7 +33,21 @@ InProcessApplicationBase::StopInternal(bool fServerInitiated)
}
else
{
exit(0);
// Send WM_QUIT to the main window to initiate graceful shutdown
EnumWindows([](HWND hwnd, LPARAM) -> BOOL
{
DWORD processId;
if (GetWindowThreadProcessId(hwnd, &processId) &&
processId == GetCurrentProcessId() &&
GetConsoleWindow() != hwnd)
{
PostMessage(hwnd, WM_QUIT, 0, 0);
return false;
}
return true;
}, 0);
}
}

View File

@ -3,7 +3,6 @@
#pragma once
#include "application.h"
#include "AppOfflineTrackingApplication.h"
typedef INT(*hostfxr_main_fn) (CONST DWORD argc, CONST PCWSTR argv[]); // TODO these may need to be BSTRs
@ -23,8 +22,5 @@ public:
protected:
BOOL m_fRecycleCalled;
IHttpServer& m_pHttpServer;
// Allows to override call to hostfxr_main with custome callback
// used in testing
static hostfxr_main_fn s_fMainCallback;
};

View File

@ -2,6 +2,41 @@
// Licensed under the MIT License. See License.txt in the project root for license information.
#include "InProcessOptions.h"
#include "InvalidOperationException.h"
#include "EventLog.h"
HRESULT InProcessOptions::Create(
IHttpServer& pServer,
IHttpApplication& pHttpApplication,
std::unique_ptr<InProcessOptions>& options)
{
try
{
const WebConfigConfigurationSource configurationSource(pServer.GetAdminManager(), pHttpApplication);
options = std::make_unique<InProcessOptions>(configurationSource);
}
catch (InvalidOperationException& ex)
{
EventLog::Error(
ASPNETCORE_CONFIGURATION_LOAD_ERROR,
ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG,
ex.as_wstring().c_str());
RETURN_CAUGHT_EXCEPTION();
}
catch (std::runtime_error& ex)
{
EventLog::Error(
ASPNETCORE_CONFIGURATION_LOAD_ERROR,
ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG,
GetUnexpectedExceptionMessage(ex).c_str());
RETURN_CAUGHT_EXCEPTION();
}
CATCH_RETURN();
return S_OK;
}
InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSource) :
m_fStdoutLogEnabled(false),
@ -18,6 +53,8 @@ InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSourc
m_struStdoutLogFile = aspNetCoreSection->GetRequiredString(CS_ASPNETCORE_STDOUT_LOG_FILE);
m_fDisableStartUpErrorPage = aspNetCoreSection->GetRequiredBool(CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE);
m_environmentVariables = aspNetCoreSection->GetKeyValuePairs(CS_ASPNETCORE_ENVIRONMENT_VARIABLES);
m_dwStartupTimeLimitInMS = aspNetCoreSection->GetRequiredLong(CS_ASPNETCORE_PROCESS_STARTUP_TIME_LIMIT) * 1000;
m_dwShutdownTimeLimitInMS = aspNetCoreSection->GetRequiredLong(CS_ASPNETCORE_PROCESS_SHUTDOWN_TIME_LIMIT) * 1000;
const auto basicAuthSection = configurationSource.GetSection(CS_BASIC_AUTHENTICATION_SECTION);
m_fBasicAuthEnabled = basicAuthSection && basicAuthSection->GetBool(CS_ENABLED).value_or(false);

View File

@ -5,6 +5,7 @@
#include <string>
#include "ConfigurationSource.h"
#include "WebConfigConfigurationSource.h"
class InProcessOptions: NonCopyable
{
@ -60,12 +61,22 @@ public:
DWORD
QueryStartupTimeLimitInMS() const
{
if (IsDebuggerPresent())
{
return INFINITE;
}
return m_dwStartupTimeLimitInMS;
}
DWORD
QueryShutdownTimeLimitInMS() const
{
if (IsDebuggerPresent())
{
return INFINITE;
}
return m_dwShutdownTimeLimitInMS;
}
@ -76,6 +87,12 @@ public:
}
InProcessOptions(const ConfigurationSource &configurationSource);
static
HRESULT InProcessOptions::Create(
IHttpServer& pServer,
IHttpApplication& pHttpApplication,
std::unique_ptr<InProcessOptions>& options);
private:
std::wstring m_strArguments;

View File

@ -5,6 +5,6 @@
HRESULT StartupExceptionApplication::CreateHandler(IHttpContext *pHttpContext, IREQUEST_HANDLER ** pRequestHandler)
{
*pRequestHandler = new StartupExceptionHandler(pHttpContext, m_disableLogs, this);
*pRequestHandler = new StartupExceptionHandler(pHttpContext, m_disableLogs);
return S_OK;
}

View File

@ -16,29 +16,6 @@ public:
: m_disableLogs(disableLogs),
InProcessApplicationBase(pServer, pApplication)
{
html500Page = std::string("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"> \
<html xmlns=\"http://www.w3.org/1999/xhtml\"> \
<head> \
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" /> \
<title> IIS 500.30 Error </title><style type=\"text/css\"></style></head> \
<body> <div id = \"content\"> \
<div class = \"content-container\"><h3> HTTP Error 500.30 - ANCM In-Process Start Failure </h3></div> \
<div class = \"content-container\"> \
<fieldset> <h4> Common causes of this issue: </h4> \
<ul><li> The application failed to start </li> \
<li> The application started but then stopped </li> \
<li> The application started but threw an exception during startup </li></ul></fieldset> \
</div> \
<div class = \"content-container\"> \
<fieldset><h4> Troubleshooting steps: </h4> \
<ul><li> Check the system event log for error messages </li> \
<li> Enable logging the application process' stdout messages </li> \
<li> Attach a debugger to the application process and inspect </li></ul></fieldset> \
<fieldset><h4> For more information visit: \
<a href=\"https://go.microsoft.com/fwlink/?LinkID=808681\"> <cite> https://go.microsoft.com/fwlink/?LinkID=808681 </cite></a></h4> \
</fieldset> \
</div> \
</div></body></html>");
}
~StartupExceptionApplication() = default;

View File

@ -4,6 +4,30 @@
#include "StartupExceptionApplication.h"
#include "StartupExceptionHandler.h"
std::string StartupExceptionHandler::s_html500Page = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"> \
<html xmlns=\"http://www.w3.org/1999/xhtml\"> \
<head> \
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" /> \
<title> IIS 500.30 Error </title><style type=\"text/css\"></style></head> \
<body> <div id = \"content\"> \
<div class = \"content-container\"><h3> HTTP Error 500.30 - ANCM In-Process Start Failure </h3></div> \
<div class = \"content-container\"> \
<fieldset> <h4> Common causes of this issue: </h4> \
<ul><li> The application failed to start </li> \
<li> The application started but then stopped </li> \
<li> The application started but threw an exception during startup </li></ul></fieldset> \
</div> \
<div class = \"content-container\"> \
<fieldset><h4> Troubleshooting steps: </h4> \
<ul><li> Check the system event log for error messages </li> \
<li> Enable logging the application process' stdout messages </li> \
<li> Attach a debugger to the application process and inspect </li></ul></fieldset> \
<fieldset><h4> For more information visit: \
<a href=\"https://go.microsoft.com/fwlink/?LinkID=808681\"> <cite> https://go.microsoft.com/fwlink/?LinkID=808681 </cite></a></h4> \
</fieldset> \
</div> \
</div></body></html>";
REQUEST_NOTIFICATION_STATUS StartupExceptionHandler::OnExecuteRequestHandler()
{
if (!m_disableLogs)
@ -16,11 +40,9 @@ REQUEST_NOTIFICATION_STATUS StartupExceptionHandler::OnExecuteRequestHandler()
(USHORT)strlen("text/html"),
FALSE
);
const std::string& html500Page = m_pApplication->GetStaticHtml500Content();
DataChunk.DataChunkType = HttpDataChunkFromMemory;
DataChunk.FromMemory.pBuffer = (PVOID)html500Page.c_str();
DataChunk.FromMemory.BufferLength = (ULONG)html500Page.size();
DataChunk.FromMemory.pBuffer = (PVOID)s_html500Page.c_str();
DataChunk.FromMemory.BufferLength = (ULONG)s_html500Page.size();
pResponse->WriteEntityChunkByReference(&DataChunk);
}
else

View File

@ -3,6 +3,7 @@
#pragma once
#include <string>
#include "requesthandler.h"
class StartupExceptionApplication;
@ -10,19 +11,23 @@ class StartupExceptionApplication;
class StartupExceptionHandler : public REQUEST_HANDLER
{
public:
StartupExceptionHandler(IHttpContext* pContext, BOOL disableLogs, StartupExceptionApplication* pApplication)
StartupExceptionHandler(IHttpContext* pContext, BOOL disableLogs)
:
m_pContext(pContext),
m_disableLogs(disableLogs),
m_pApplication(pApplication)
m_disableLogs(disableLogs)
{
}
~StartupExceptionHandler()
{
}
REQUEST_NOTIFICATION_STATUS OnExecuteRequestHandler() override;
private:
IHttpContext * m_pContext;
BOOL m_disableLogs;
StartupExceptionApplication* m_pApplication;
static
std::string s_html500Page;
};

View File

@ -110,39 +110,25 @@ CreateApplication(
return S_OK;
}
const WebConfigConfigurationSource configurationSource(pServer->GetAdminManager(), *pHttpApplication);
auto pConfig = std::make_unique<InProcessOptions>(configurationSource);
BOOL disableStartupPage = pConfig->QueryDisableStartUpErrorPage();
auto pApplication = std::make_unique<IN_PROCESS_APPLICATION>(*pServer, *pHttpApplication, std::move(pConfig), pParameters, nParameters);
// never create two inprocess applications in one process
g_fInProcessApplicationCreated = true;
if (FAILED_LOG(pApplication->LoadManagedApplication()))
std::unique_ptr<IN_PROCESS_APPLICATION, IAPPLICATION_DELETER> inProcessApplication;
if (!FAILED_LOG(IN_PROCESS_APPLICATION::Start(*pServer, *pHttpApplication, pParameters, nParameters, inProcessApplication)))
{
*ppApplication = inProcessApplication.release();
}
else
{
std::unique_ptr<InProcessOptions> options;
THROW_IF_FAILED(InProcessOptions::Create(*pServer, *pHttpApplication, options));
// Set the currently running application to a fake application that returns startup exceptions.
auto pErrorApplication = std::make_unique<StartupExceptionApplication>(*pServer, *pHttpApplication, disableStartupPage);
auto pErrorApplication = std::make_unique<StartupExceptionApplication>(*pServer, *pHttpApplication, options->QueryDisableStartUpErrorPage());
RETURN_IF_FAILED(pErrorApplication->StartMonitoringAppOffline());
*ppApplication = pErrorApplication.release();
}
else
{
RETURN_IF_FAILED(pApplication->StartMonitoringAppOffline());
*ppApplication = pApplication.release();
}
}
catch(ConfigurationLoadException &ex)
{
EventLog::Error(
ASPNETCORE_CONFIGURATION_LOAD_ERROR,
ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG,
ex.get_message().c_str());
RETURN_HR(E_FAIL);
return S_OK;
}
CATCH_RETURN();
return S_OK;
}

View File

@ -6,13 +6,11 @@
#include "hostfxroptions.h"
#include "requesthandler_config.h"
#include "environmentvariablehelpers.h"
#include "SRWExclusiveLock.h"
#include "exceptions.h"
#include "LoggingHelpers.h"
#include "resources.h"
#include "EventLog.h"
const LPCSTR IN_PROCESS_APPLICATION::s_exeLocationParameterName = "InProcessExeLocation";
#include "ModuleHelpers.h"
IN_PROCESS_APPLICATION* IN_PROCESS_APPLICATION::s_Application = NULL;
@ -23,10 +21,9 @@ IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION(
APPLICATION_PARAMETER *pParameters,
DWORD nParameters) :
InProcessApplicationBase(pHttpServer, pApplication),
m_ProcessExitCode(0),
m_fBlockCallbacksIntoManaged(FALSE),
m_fShutdownCalledFromNative(FALSE),
m_fShutdownCalledFromManaged(FALSE),
m_Initialized(false),
m_blockManagedCallbacks(true),
m_waitForShutdown(true),
m_pConfig(std::move(pConfig))
{
DBG_ASSERT(m_pConfig);
@ -35,161 +32,54 @@ IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION(
{
if (_stricmp(pParameters[i].pzName, s_exeLocationParameterName) == 0)
{
m_struExeLocation.Copy(reinterpret_cast<PCWSTR>(pParameters[i].pValue));
m_dotnetExeKnownLocation = reinterpret_cast<PCWSTR>(pParameters[i].pValue);
}
}
m_status = MANAGED_APPLICATION_STATUS::STARTING;
}
IN_PROCESS_APPLICATION::~IN_PROCESS_APPLICATION()
{
s_Application = NULL;
s_Application = nullptr;
}
//static
DWORD WINAPI
IN_PROCESS_APPLICATION::DoShutDown(
LPVOID lpParam
)
{
IN_PROCESS_APPLICATION* pApplication = static_cast<IN_PROCESS_APPLICATION*>(lpParam);
DBG_ASSERT(pApplication);
pApplication->ShutDownInternal();
return 0;
}
__override
VOID
IN_PROCESS_APPLICATION::StopInternal(bool fServerInitiated)
{
UNREFERENCED_PARAMETER(fServerInitiated);
HRESULT hr = S_OK;
CHandle hThread;
DWORD dwThreadStatus = 0;
DWORD dwTimeout = m_pConfig->QueryShutdownTimeLimitInMS();
if (IsDebuggerPresent())
{
dwTimeout = INFINITE;
}
hThread.Attach(CreateThread(
NULL, // default security attributes
0, // default stack size
(LPTHREAD_START_ROUTINE)DoShutDown,
this, // thread function arguments
0, // default creation flags
NULL)); // receive thread identifier
if ((HANDLE)hThread == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
if (WaitForSingleObject(hThread, dwTimeout) != WAIT_OBJECT_0)
{
// if the thread is still running, we need kill it first before exit to avoid AV
if (GetExitCodeThread(m_hThread, &dwThreadStatus) != 0 && dwThreadStatus == STILL_ACTIVE)
{
// Calling back into managed at this point is prone to have AVs
// Calling terminate thread here may be our best solution.
TerminateThread(hThread, STATUS_CONTROL_C_EXIT);
hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
}
}
Finished:
if (FAILED(hr))
{
EventLog::Warn(
ASPNETCORE_EVENT_GRACEFUL_SHUTDOWN_FAILURE,
ASPNETCORE_EVENT_APP_SHUTDOWN_FAILURE_MSG,
QueryConfigPath().c_str());
}
else
{
EventLog::Info(
ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL,
ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL_MSG,
QueryConfigPath().c_str());
}
{
StopClr();
InProcessApplicationBase::StopInternal(fServerInitiated);
}
VOID
IN_PROCESS_APPLICATION::ShutDownInternal()
{
DWORD dwThreadStatus = 0;
DWORD dwTimeout = m_pConfig->QueryShutdownTimeLimitInMS();
IN_PROCESS_APPLICATION::StopClr()
{
LOG_INFO(L"Stopping CLR");
if (IsDebuggerPresent())
if (!m_blockManagedCallbacks)
{
dwTimeout = INFINITE;
}
// We cannot call into managed if the dll is detaching from the process.
// Calling into managed code when the dll is detaching is strictly a bad idea,
// and usually results in an AV saying "The string binding is invalid"
const auto shutdownHandler = m_ShutdownHandler;
if (m_fShutdownCalledFromNative ||
m_status == MANAGED_APPLICATION_STATUS::STARTING ||
m_status == MANAGED_APPLICATION_STATUS::FAIL)
{
return;
}
{
if (m_fShutdownCalledFromNative ||
m_status == MANAGED_APPLICATION_STATUS::STARTING ||
m_status == MANAGED_APPLICATION_STATUS::FAIL)
if (!g_fProcessDetach && shutdownHandler != nullptr)
{
return;
}
// We need to keep track of when both managed and native initiate shutdown
// to avoid AVs. If shutdown has already been initiated in managed, we don't want to call into
// managed. We still need to wait on main exiting no matter what. m_fShutdownCalledFromNative
// is used for detecting redundant calls and blocking more requests to OnExecuteRequestHandler.
m_fShutdownCalledFromNative = TRUE;
m_status = MANAGED_APPLICATION_STATUS::SHUTDOWN;
if (!m_fShutdownCalledFromManaged)
{
// We cannot call into managed if the dll is detaching from the process.
// Calling into managed code when the dll is detaching is strictly a bad idea,
// and usually results in an AV saying "The string binding is invalid"
if (!g_fProcessDetach)
{
m_ShutdownHandler(m_ShutdownHandlerContext);
m_ShutdownHandler = NULL;
}
}
// Release the lock before we wait on the thread to exit.
}
if (!m_fShutdownCalledFromManaged)
{
if (m_hThread != NULL &&
GetExitCodeThread(m_hThread, &dwThreadStatus) != 0 &&
dwThreadStatus == STILL_ACTIVE)
{
// wait for graceful shutdown, i.e., the exit of the background thread or timeout
if (WaitForSingleObject(m_hThread, dwTimeout) != WAIT_OBJECT_0)
{
// if the thread is still running, we need kill it first before exit to avoid AV
if (GetExitCodeThread(m_hThread, &dwThreadStatus) != 0 && dwThreadStatus == STILL_ACTIVE)
{
// Calling back into managed at this point is prone to have AVs
// Calling terminate thread here may be our best solution.
TerminateThread(m_hThread, STATUS_CONTROL_C_EXIT);
}
}
shutdownHandler(m_ShutdownHandlerContext);
}
}
s_Application = NULL;
// Signal shutdown
if (m_pShutdownEvent != nullptr)
{
LOG_IF_FAILED(SetEvent(m_pShutdownEvent));
}
if (m_workerThread.joinable())
{
// Worker thread would wait for clr to finish and log error if required
m_workerThread.join();
}
s_Application = nullptr;
}
VOID
@ -201,169 +91,320 @@ IN_PROCESS_APPLICATION::SetCallbackHandles(
_In_ VOID* pvShutdownHandlerContext
)
{
LOG_INFO(L"In-process callbacks set");
m_RequestHandler = request_handler;
m_RequestHandlerContext = pvRequstHandlerContext;
m_ShutdownHandler = shutdown_handler;
m_ShutdownHandlerContext = pvShutdownHandlerContext;
m_AsyncCompletionHandler = async_completion_handler;
m_blockManagedCallbacks = false;
m_Initialized = true;
// Can't check the std err handle as it isn't a critical error
// Initialization complete
EventLog::Info(
ASPNETCORE_EVENT_INPROCESS_START_SUCCESS,
ASPNETCORE_EVENT_INPROCESS_START_SUCCESS_MSG,
QueryApplicationPhysicalPath().c_str());
SetEvent(m_pInitalizeEvent);
m_fInitialized = TRUE;
SetEvent(m_pInitializeEvent);
}
// Will be called by the inprocesshandler
HRESULT
IN_PROCESS_APPLICATION::LoadManagedApplication
(
VOID
)
IN_PROCESS_APPLICATION::LoadManagedApplication()
{
HRESULT hr = S_OK;
DWORD dwTimeout;
DWORD dwResult;
THROW_LAST_ERROR_IF_NULL(m_pInitializeEvent = CreateEvent(
nullptr, // default security attributes
TRUE, // manual reset event
FALSE, // not set
nullptr)); // name
ReferenceApplication();
THROW_LAST_ERROR_IF_NULL(m_pShutdownEvent = CreateEvent(
nullptr, // default security attributes
TRUE, // manual reset event
FALSE, // not set
nullptr)); // name
if (m_status != MANAGED_APPLICATION_STATUS::STARTING)
m_workerThread = std::thread([](std::unique_ptr<IN_PROCESS_APPLICATION, IAPPLICATION_DELETER> application)
{
// Core CLR has already been loaded.
// Cannot load more than once even there was a failure
if (m_status == MANAGED_APPLICATION_STATUS::FAIL)
{
hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
}
else if (m_status == MANAGED_APPLICATION_STATUS::SHUTDOWN)
{
hr = HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IS_SCHEDULED);
}
LOG_INFO(L"Starting in-process worker thread");
application->ExecuteApplication();
LOG_INFO(L"Stopping in-process worker thread");
}, ::ReferenceApplication(this));
goto Finished;
LOG_INFO(L"Waiting for initialization");
const HANDLE waitHandles[2] = { m_pInitializeEvent, m_workerThread.native_handle() };
// Wait for shutdown request
const auto waitResult = WaitForMultipleObjects(2, waitHandles, FALSE, m_pConfig->QueryStartupTimeLimitInMS());
THROW_LAST_ERROR_IF(waitResult == WAIT_FAILED);
if (waitResult == WAIT_TIMEOUT)
{
// If server wasn't initialized in time shut application down without waiting for CLR thread to exit
m_waitForShutdown = false;
StopClr();
throw InvalidOperationException(format(L"Managed server didn't initialize after %u ms.", m_pConfig->QueryStartupTimeLimitInMS()));
}
// WAIT_OBJECT_0 + 1 is the worker thead handle
if (waitResult == WAIT_OBJECT_0 + 1)
{
SRWExclusiveLock lock(m_stateLock);
// Worker thread exited stop
StopClr();
throw InvalidOperationException(format(L"CLR worker thread exited prematurely"));
}
if (m_status != MANAGED_APPLICATION_STATUS::STARTING)
THROW_IF_FAILED(StartMonitoringAppOffline());
return S_OK;
}
void
IN_PROCESS_APPLICATION::ExecuteApplication()
{
try
{
std::unique_ptr<HOSTFXR_OPTIONS> hostFxrOptions;
auto context = std::make_shared<ExecuteClrContext>();
auto pProc = s_fMainCallback;
if (pProc == nullptr)
{
if (m_status == MANAGED_APPLICATION_STATUS::FAIL)
HMODULE hModule;
// hostfxr should already be loaded by the shim. If not, then we will need
// to load it ourselves by finding hostfxr again.
THROW_LAST_ERROR_IF_NULL(hModule = GetModuleHandle(L"hostfxr.dll"));
// Get the entry point for main
pProc = reinterpret_cast<hostfxr_main_fn>(GetProcAddress(hModule, "hostfxr_main"));
THROW_LAST_ERROR_IF_NULL(pProc);
THROW_IF_FAILED(HOSTFXR_OPTIONS::Create(
m_dotnetExeKnownLocation,
m_pConfig->QueryProcessPath(),
QueryApplicationPhysicalPath(),
m_pConfig->QueryArguments(),
hostFxrOptions
));
hostFxrOptions->GetArguments(context->m_argc, context->m_argv);
THROW_IF_FAILED(SetEnvironmentVariablesOnWorkerProcess());
}
context->m_pProc = pProc;
if (m_pLoggerProvider == nullptr)
{
THROW_IF_FAILED(LoggingHelpers::CreateLoggingProvider(
m_pConfig->QueryStdoutLogEnabled(),
!m_pHttpServer.IsCommandLineLaunch(),
m_pConfig->QueryStdoutLogFile().c_str(),
QueryApplicationPhysicalPath().c_str(),
m_pLoggerProvider));
LOG_IF_FAILED(m_pLoggerProvider->Start());
}
// There can only ever be a single instance of .NET Core
// loaded in the process but we need to get config information to boot it up in the
// first place. This is happening in an execute request handler and everyone waits
// until this initialization is done.
// We set a static so that managed code can call back into this instance and
// set the callbacks
s_Application = this;
//Start CLR thread
m_clrThread = std::thread(ClrThreadEntryPoint, context);
// Wait for thread exit or shutdown event
const HANDLE waitHandles[2] = { m_pShutdownEvent, m_clrThread.native_handle() };
// Wait for shutdown request
const auto waitResult = WaitForMultipleObjects(2, waitHandles, FALSE, INFINITE);
THROW_LAST_ERROR_IF(waitResult == WAIT_FAILED);
LOG_INFOF(L"Starting shutdown sequence %d", waitResult);
bool clrThreadExited = waitResult == (WAIT_OBJECT_0 + 1);
// shutdown was signaled
// only wait for shutdown in case of successful startup
if (m_waitForShutdown)
{
const auto clrWaitResult = WaitForSingleObject(m_clrThread.native_handle(), m_pConfig->QueryShutdownTimeLimitInMS());
THROW_LAST_ERROR_IF(waitResult == WAIT_FAILED);
clrThreadExited = clrWaitResult != WAIT_TIMEOUT;
}
LOG_INFOF(L"Clr thread wait ended: clrThreadExited: %d", clrThreadExited);
// At this point CLR thread either finished or timed out, abandon it.
m_clrThread.detach();
LOG_IF_FAILED(m_pLoggerProvider->Stop());
if (m_fStopCalled)
{
if (clrThreadExited)
{
hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
EventLog::Info(
ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL,
ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL_MSG,
QueryConfigPath().c_str());
}
else if (m_status == MANAGED_APPLICATION_STATUS::SHUTDOWN)
else
{
hr = HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IS_SCHEDULED);
EventLog::Warn(
ASPNETCORE_EVENT_GRACEFUL_SHUTDOWN_FAILURE,
ASPNETCORE_EVENT_APP_SHUTDOWN_FAILURE_MSG,
QueryConfigPath().c_str());
}
goto Finished;
}
m_hThread = CreateThread(
NULL, // default security attributes
0, // default stack size
(LPTHREAD_START_ROUTINE)ExecuteAspNetCoreProcess,
this, // thread function arguments
0, // default creation flags
NULL); // receive thread identifier
if (m_hThread == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
m_pInitalizeEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual reset event
FALSE, // not set
NULL); // name
if (m_pInitalizeEvent == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
// If the debugger is attached, never timeout
if (IsDebuggerPresent())
{
dwTimeout = INFINITE;
}
else
{
dwTimeout = m_pConfig->QueryStartupTimeLimitInMS();
if (clrThreadExited)
{
UnexpectedThreadExit(*context);
// If the inprocess server was initialized, we need to cause recycle to be called on the worker process.
// in case when it was not initialized we need to keep server running to serve 502 page
if (m_Initialized)
{
QueueStop();
}
}
}
const HANDLE pHandles[2]{ m_hThread, m_pInitalizeEvent };
// Wait on either the thread to complete or the event to be set
dwResult = WaitForMultipleObjects(2, pHandles, FALSE, dwTimeout);
// It all timed out
if (dwResult == WAIT_TIMEOUT)
{
// kill the backend thread as loading dotnet timedout
TerminateThread(m_hThread, 0);
hr = HRESULT_FROM_WIN32(dwResult);
goto Finished;
}
else if (dwResult == WAIT_FAILED)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Finished;
}
// The thread ended it means that something failed
if (dwResult == WAIT_OBJECT_0)
{
hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
goto Finished;
}
m_status = MANAGED_APPLICATION_STATUS::RUNNING_MANAGED;
}
Finished:
if (FAILED(hr))
catch (InvalidOperationException& ex)
{
m_status = MANAGED_APPLICATION_STATUS::FAIL;
EventLog::Error(
ASPNETCORE_EVENT_LOAD_CLR_FALIURE,
ASPNETCORE_EVENT_LOAD_CLR_FALIURE_MSG,
QueryApplicationId().c_str(),
QueryApplicationPhysicalPath().c_str(),
hr);
}
DereferenceApplication();
ex.as_wstring().c_str());
return hr;
OBSERVE_CAUGHT_EXCEPTION();
}
catch (std::runtime_error& ex)
{
EventLog::Error(
ASPNETCORE_EVENT_LOAD_CLR_FALIURE,
ASPNETCORE_EVENT_LOAD_CLR_FALIURE_MSG,
QueryApplicationId().c_str(),
QueryApplicationPhysicalPath().c_str(),
GetUnexpectedExceptionMessage(ex).c_str());
OBSERVE_CAUGHT_EXCEPTION();
}
}
// static
VOID
IN_PROCESS_APPLICATION::ExecuteAspNetCoreProcess(
_In_ LPVOID pContext
)
void IN_PROCESS_APPLICATION::QueueStop()
{
HRESULT hr = S_OK;
IN_PROCESS_APPLICATION *pApplication = (IN_PROCESS_APPLICATION*)pContext;
DBG_ASSERT(pApplication != NULL);
hr = pApplication->ExecuteApplication();
//
// no need to log the error here as if error happened, the thread will exit
// the error will ba catched by caller LoadManagedApplication which will log an error
//
if (m_fStopCalled)
{
return;
}
LOG_INFO(L"Queueing in-process stop thread");
std::thread stoppingThread([](std::unique_ptr<IN_PROCESS_APPLICATION, IAPPLICATION_DELETER> application)
{
LOG_INFO(L"Starting in-process stop thread");
application->Stop(false);
LOG_INFO(L"Stopping in-process stop thread");
}, ::ReferenceApplication(this));
stoppingThread.detach();
}
HRESULT IN_PROCESS_APPLICATION::Start(
IHttpServer& pServer,
IHttpApplication& pHttpApplication,
APPLICATION_PARAMETER* pParameters,
DWORD nParameters,
std::unique_ptr<IN_PROCESS_APPLICATION, IAPPLICATION_DELETER>& application)
{
try
{
std::unique_ptr<InProcessOptions> options;
THROW_IF_FAILED(InProcessOptions::Create(pServer, pHttpApplication, options));
application = std::unique_ptr<IN_PROCESS_APPLICATION, IAPPLICATION_DELETER>(
new IN_PROCESS_APPLICATION(pServer, pHttpApplication, std::move(options), pParameters, nParameters));
THROW_IF_FAILED(application->LoadManagedApplication());
return S_OK;
}
catch (InvalidOperationException& ex)
{
EventLog::Error(
ASPNETCORE_EVENT_LOAD_CLR_FALIURE,
ASPNETCORE_EVENT_LOAD_CLR_FALIURE_MSG,
pHttpApplication.GetApplicationId(),
pHttpApplication.GetApplicationPhysicalPath(),
ex.as_wstring().c_str());
RETURN_CAUGHT_EXCEPTION();
}
catch (std::runtime_error& ex)
{
EventLog::Error(
ASPNETCORE_EVENT_LOAD_CLR_FALIURE,
ASPNETCORE_EVENT_LOAD_CLR_FALIURE_MSG,
pHttpApplication.GetApplicationId(),
pHttpApplication.GetApplicationPhysicalPath(),
GetUnexpectedExceptionMessage(ex).c_str());
RETURN_CAUGHT_EXCEPTION();
}
CATCH_RETURN();
}
// Required because __try and objects with destructors can not be mixed
void
IN_PROCESS_APPLICATION::ExecuteClr(const std::shared_ptr<ExecuteClrContext>& context)
{
__try
{
auto const exitCode = context->m_pProc(context->m_argc, context->m_argv.get());
LOG_INFOF(L"Managed application exited with code %d", exitCode);
context->m_exitCode = exitCode;
}
__except(GetExceptionCode() != 0)
{
LOG_INFOF(L"Managed threw an exception %d", GetExceptionCode());
context->m_exceptionCode = GetExceptionCode();
}
}
//
// Calls hostfxr_main with the hostfxr and application as arguments.
// This method should not access IN_PROCESS_APPLICATION instance as it may be already freed
// in case of startup timeout
//
VOID
IN_PROCESS_APPLICATION::ClrThreadEntryPoint(const std::shared_ptr<ExecuteClrContext> &context)
{
LOG_INFO(L"Starting CLR thread");
// Keep aspnetcorev2_inprocess.dll loaded while this thread is running
// this is required because thread might be abandoned
HandleWrapper<ModuleHandleTraits> moduleHandle;
ModuleHelpers::IncrementCurrentModuleRefCount(moduleHandle);
ExecuteClr(context);
FreeLibraryAndExitThread(moduleHandle.release(), 0);
}
HRESULT
IN_PROCESS_APPLICATION::SetEnvironementVariablesOnWorkerProcess(
VOID
)
IN_PROCESS_APPLICATION::SetEnvironmentVariablesOnWorkerProcess()
{
auto variables = m_pConfig->QueryEnvironmentVariables();
auto inputTable = std::unique_ptr<ENVIRONMENT_VAR_HASH, ENVIRONMENT_VAR_HASH_DELETER>(new ENVIRONMENT_VAR_HASH());
@ -397,128 +438,53 @@ IN_PROCESS_APPLICATION::SetEnvironementVariablesOnWorkerProcess(
return S_OK;
}
HRESULT
IN_PROCESS_APPLICATION::ExecuteApplication(
VOID
)
{
HRESULT hr;
HMODULE hModule = nullptr;
hostfxr_main_fn pProc;
std::unique_ptr<HOSTFXR_OPTIONS> hostFxrOptions = NULL;
DWORD hostfxrArgc = 0;
std::unique_ptr<PCWSTR[]> hostfxrArgv;
DBG_ASSERT(m_status == MANAGED_APPLICATION_STATUS::STARTING);
pProc = s_fMainCallback;
if (pProc == nullptr)
{
// hostfxr should already be loaded by the shim. If not, then we will need
// to load it ourselves by finding hostfxr again.
hModule = LoadLibraryW(L"hostfxr.dll");
if (hModule == NULL)
{
// .NET Core not installed (we can log a more detailed error message here)
hr = LOG_IF_FAILED(ERROR_BAD_ENVIRONMENT);
goto Finished;
}
// Get the entry point for main
pProc = (hostfxr_main_fn)GetProcAddress(hModule, "hostfxr_main");
if (pProc == NULL)
{
hr = LOG_IF_FAILED(ERROR_BAD_ENVIRONMENT);
goto Finished;
}
FINISHED_IF_FAILED(hr = HOSTFXR_OPTIONS::Create(
m_struExeLocation.QueryStr(),
m_pConfig->QueryProcessPath().c_str(),
QueryApplicationPhysicalPath().c_str(),
m_pConfig->QueryArguments().c_str(),
hostFxrOptions
));
hostFxrOptions->GetArguments(hostfxrArgc, hostfxrArgv);
FINISHED_IF_FAILED(SetEnvironementVariablesOnWorkerProcess());
}
LOG_INFO(L"Starting managed application");
if (m_pLoggerProvider == NULL)
{
FINISHED_IF_FAILED(hr = LoggingHelpers::CreateLoggingProvider(
m_pConfig->QueryStdoutLogEnabled(),
!m_pHttpServer.IsCommandLineLaunch(),
m_pConfig->QueryStdoutLogFile().c_str(),
QueryApplicationPhysicalPath().c_str(),
m_pLoggerProvider));
LOG_IF_FAILED(m_pLoggerProvider->Start());
}
// There can only ever be a single instance of .NET Core
// loaded in the process but we need to get config information to boot it up in the
// first place. This is happening in an execute request handler and everyone waits
// until this initialization is done.
// We set a static so that managed code can call back into this instance and
// set the callbacks
s_Application = this;
hr = RunDotnetApplication(hostfxrArgc, hostfxrArgv.get(), pProc);
Finished:
//
// this method is called by the background thread and should never exit unless shutdown
// If main returned and shutdown was not called in managed, we want to block native from calling into
// managed. To do this, we can say that shutdown was called from managed.
// Don't bother locking here as there will always be a race between receiving a native shutdown
// notification and unexpected managed exit.
//
m_status = MANAGED_APPLICATION_STATUS::SHUTDOWN;
m_fShutdownCalledFromManaged = TRUE;
m_pLoggerProvider->Stop();
if (!m_fShutdownCalledFromNative)
{
LogErrorsOnMainExit(hr);
if (m_fInitialized)
{
//
// If the inprocess server was initialized, we need to cause recycle to be called on the worker process.
//
Stop(/*fServerInitiated*/ false);
}
}
return hr;
}
VOID
IN_PROCESS_APPLICATION::LogErrorsOnMainExit(
HRESULT hr
)
IN_PROCESS_APPLICATION::UnexpectedThreadExit(const ExecuteClrContext& context) const
{
STRA straStdErrOutput;
STRU struStdMsg;
auto hasStdOut = m_pLoggerProvider->GetStdOutContent(&straStdErrOutput) &&
SUCCEEDED(struStdMsg.CopyA(straStdErrOutput.QueryStr()));
if (context.m_exceptionCode != 0)
{
if (hasStdOut)
{
EventLog::Error(
ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION,
ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION_STDOUT_MSG,
QueryApplicationId().c_str(),
QueryApplicationPhysicalPath().c_str(),
context.m_exceptionCode,
struStdMsg.QueryStr());
}
else
{
EventLog::Error(
ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION,
ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION_MSG,
QueryApplicationId().c_str(),
QueryApplicationPhysicalPath().c_str(),
context.m_exceptionCode
);
}
return;
}
//
// Ungraceful shutdown, try to log an error message.
// This will be a common place for errors as it means the hostfxr_main returned
// or there was an exception.
//
STRA straStdErrOutput;
STRU struStdMsg;
if (m_pLoggerProvider->GetStdOutContent(&straStdErrOutput))
if (hasStdOut)
{
if (SUCCEEDED(struStdMsg.CopyA(straStdErrOutput.QueryStr()))) {
EventLog::Error(
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT,
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT_MSG,
QueryApplicationId().c_str(),
QueryApplicationPhysicalPath().c_str(),
hr,
struStdMsg.QueryStr());
}
EventLog::Error(
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT,
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT_MSG,
QueryApplicationId().c_str(),
QueryApplicationPhysicalPath().c_str(),
context.m_exitCode,
struStdMsg.QueryStr());
}
else
{
@ -527,53 +493,20 @@ IN_PROCESS_APPLICATION::LogErrorsOnMainExit(
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_MSG,
QueryApplicationId().c_str(),
QueryApplicationPhysicalPath().c_str(),
hr);
context.m_exitCode);
}
}
//
// Calls hostfxr_main with the hostfxr and application as arguments.
//
HRESULT
IN_PROCESS_APPLICATION::RunDotnetApplication(DWORD argc, CONST PCWSTR* argv, hostfxr_main_fn pProc)
{
HRESULT hr = S_OK;
__try
{
m_ProcessExitCode = pProc(argc, argv);
if (m_ProcessExitCode != 0)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
LOG_INFOF(L"Managed application exited with code %d", m_ProcessExitCode);
}
__except(GetExceptionCode() != 0)
{
LOG_INFOF(L"Managed threw an exception %d", GetExceptionCode());
hr = HRESULT_FROM_WIN32(GetLastError());
}
return hr;
}
HRESULT
IN_PROCESS_APPLICATION::CreateHandler(
_In_ IHttpContext *pHttpContext,
_Out_ IREQUEST_HANDLER **pRequestHandler)
{
HRESULT hr = S_OK;
IREQUEST_HANDLER* pHandler = NULL;
pHandler = new IN_PROCESS_HANDLER(::ReferenceApplication(this), pHttpContext, m_RequestHandler, m_RequestHandlerContext, m_AsyncCompletionHandler);
if (pHandler == NULL)
try
{
hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
*pRequestHandler = new IN_PROCESS_HANDLER(::ReferenceApplication(this), pHttpContext, m_RequestHandler, m_RequestHandlerContext, m_AsyncCompletionHandler);
}
*pRequestHandler = pHandler;
return hr;
CATCH_RETURN();
return S_OK;
}

View File

@ -3,6 +3,7 @@
#pragma once
#include <thread>
#include "InProcessApplicationBase.h"
#include "IOutputManager.h"
#include "InProcessOptions.h"
@ -45,35 +46,26 @@ public:
override;
// Executes the .NET Core process
void
ExecuteApplication();
HRESULT
ExecuteApplication(
VOID
);
LoadManagedApplication();
HRESULT
LoadManagedApplication(
VOID
);
VOID
LogErrorsOnMainExit(
HRESULT hr
);
VOID
StopCallsIntoManaged(
VOID
)
void
QueueStop();
void
StopIncomingRequests()
{
m_fBlockCallbacksIntoManaged = TRUE;
QueueStop();
}
VOID
StopIncomingRequests(
VOID
)
void
StopCallsIntoManaged()
{
m_fShutdownCalledFromManaged = TRUE;
m_blockManagedCallbacks = true;
}
static
@ -84,44 +76,64 @@ public:
static
IN_PROCESS_APPLICATION*
GetInstance(
VOID
)
GetInstance()
{
return s_Application;
}
PCWSTR
QueryExeLocation()
const std::wstring&
QueryExeLocation() const
{
return m_struExeLocation.QueryStr();
return m_dotnetExeKnownLocation;
}
const InProcessOptions&
QueryConfig() const
{
return *m_pConfig.get();
return *m_pConfig;
}
bool
QueryBlockCallbacksIntoManaged() const
{
return m_fBlockCallbacksIntoManaged;
return m_blockManagedCallbacks;
}
static
HRESULT Start(
IHttpServer& pServer,
IHttpApplication& pHttpApplication,
APPLICATION_PARAMETER* pParameters,
DWORD nParameters,
std::unique_ptr<IN_PROCESS_APPLICATION, IAPPLICATION_DELETER>& application);
private:
enum MANAGED_APPLICATION_STATUS
struct ExecuteClrContext: std::enable_shared_from_this<ExecuteClrContext>
{
UNKNOWN = 0,
STARTING,
RUNNING_MANAGED,
SHUTDOWN,
FAIL
};
ExecuteClrContext():
m_argc(0),
m_pProc(nullptr),
m_exitCode(0),
m_exceptionCode(0)
{
}
// Thread executing the .NET Core process
HandleWrapper<InvalidHandleTraits> m_hThread;
DWORD m_argc;
std::unique_ptr<PCWSTR[]> m_argv;
hostfxr_main_fn m_pProc;
int m_exitCode;
int m_exceptionCode;
};
// Thread executing the .NET Core process this might be abandoned in timeout cases
std::thread m_clrThread;
// Thread tracking the CLR thread, this one is always joined on shutdown
std::thread m_workerThread;
// The event that gets triggered when managed initialization is complete
HandleWrapper<NullHandleTraits> m_pInitializeEvent;
// The event that gets triggered when worker thread should exit
HandleWrapper<NullHandleTraits> m_pShutdownEvent;
// The request handler callback from managed code
PFN_REQUEST_HANDLER m_RequestHandler;
@ -133,53 +145,38 @@ private:
PFN_ASYNC_COMPLETION_HANDLER m_AsyncCompletionHandler;
// The event that gets triggered when managed initialization is complete
HandleWrapper<InvalidHandleTraits> m_pInitalizeEvent;
std::wstring m_dotnetExeKnownLocation;
STRU m_struExeLocation;
std::atomic_bool m_blockManagedCallbacks;
bool m_Initialized;
bool m_waitForShutdown;
// The exit code of the .NET Core process
INT m_ProcessExitCode;
volatile BOOL m_fBlockCallbacksIntoManaged;
volatile BOOL m_fShutdownCalledFromNative;
volatile BOOL m_fShutdownCalledFromManaged;
BOOL m_fInitialized;
MANAGED_APPLICATION_STATUS m_status;
std::unique_ptr<InProcessOptions> m_pConfig;
static IN_PROCESS_APPLICATION* s_Application;
std::unique_ptr<IOutputManager> m_pLoggerProvider;
static const LPCSTR s_exeLocationParameterName;
static
VOID
ExecuteAspNetCoreProcess(
_In_ LPVOID pContext
);
HRESULT
SetEnvironementVariablesOnWorkerProcess(
VOID
);
HRESULT
RunDotnetApplication(
DWORD argc,
CONST PCWSTR* argv,
hostfxr_main_fn pProc
);
static
DWORD WINAPI
DoShutDown(
LPVOID lpParam
);
inline static const LPCSTR s_exeLocationParameterName = "InProcessExeLocation";
VOID
ShutDownInternal(
VOID
);
UnexpectedThreadExit(const ExecuteClrContext& context) const;
HRESULT
SetEnvironmentVariablesOnWorkerProcess();
void
StopClr();
static
void
ClrThreadEntryPoint(const std::shared_ptr<ExecuteClrContext> &context);
static
void
ExecuteClr(const std::shared_ptr<ExecuteClrContext> &context);
// Allows to override call to hostfxr_main with custom callback
// used in testing
inline static hostfxr_main_fn s_fMainCallback = nullptr;
};

View File

@ -40,9 +40,7 @@ public:
) override;
IHttpContext*
QueryHttpContext(
VOID
) const
QueryHttpContext() const
{
return m_pW3Context;
}
@ -53,9 +51,7 @@ public:
);
VOID
IndicateManagedRequestComplete(
VOID
);
IndicateManagedRequestComplete();
VOID
SetAsyncCompletionStatus(
@ -68,11 +64,11 @@ public:
static
HRESULT
StaticInitialize(VOID);
StaticInitialize();
static
void
StaticTerminate(VOID);
StaticTerminate();
private:
REQUEST_NOTIFICATION_STATUS

View File

@ -184,7 +184,7 @@ http_get_application_properties(
return E_FAIL;
}
auto pConfiguration = pInProcessApplication->QueryConfig();
const auto& pConfiguration = pInProcessApplication->QueryConfig();
pIISCofigurationData->pInProcessApplication = pInProcessApplication;
pIISCofigurationData->pwzFullApplicationPath = SysAllocString(pInProcessApplication->QueryApplicationPhysicalPath().c_str());

View File

@ -115,7 +115,7 @@ Finished:
// Global initialization routine for OutOfProcess
//
HRESULT
EnsureOutOfProcessInitializtion()
EnsureOutOfProcessInitializtion(IHttpApplication *pHttpApplication)
{
DBG_ASSERT(g_pHttpServer);
@ -202,6 +202,8 @@ EnsureOutOfProcessInitializtion()
FINISHED_IF_FAILED(ALLOC_CACHE_HANDLER::StaticInitialize());
FINISHED_IF_FAILED(FORWARDING_HANDLER::StaticInitialize(g_fEnableReferenceCountTracing));
FINISHED_IF_FAILED(WEBSOCKET_HANDLER::StaticInitialize(g_fEnableReferenceCountTracing));
DebugInitializeFromConfig(*g_pHttpServer, *pHttpApplication);
}
Finished:
if (FAILED(hr))
@ -255,7 +257,7 @@ CreateApplication(
RETURN_IF_FAILED(REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(pServer, pHttpApplication, &pConfig));
std::unique_ptr<REQUESTHANDLER_CONFIG> pRequestHandlerConfig(pConfig);
RETURN_IF_FAILED(EnsureOutOfProcessInitializtion());
RETURN_IF_FAILED(EnsureOutOfProcessInitializtion(pHttpApplication));
std::unique_ptr<OUT_OF_PROCESS_APPLICATION> pApplication = std::make_unique<OUT_OF_PROCESS_APPLICATION>(*pHttpApplication, std::move(pRequestHandlerConfig));

View File

@ -48,10 +48,7 @@ FORWARDING_HANDLER::FORWARDING_HANDLER(
m_pW3Context(pW3Context),
m_pApplication(pApplication)
{
#ifdef DEBUG
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"FORWARDING_HANDLER::FORWARDING_HANDLER");
#endif
LOG_TRACE(L"FORWARDING_HANDLER::FORWARDING_HANDLER");
m_fWebSocketSupported = m_pApplication->QueryWebsocketStatus();
InitializeSRWLock(&m_RequestLock);
@ -65,10 +62,8 @@ FORWARDING_HANDLER::~FORWARDING_HANDLER(
//
m_Signature = FORWARDING_HANDLER_SIGNATURE_FREE;
#ifdef DEBUG
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"FORWARDING_HANDLER::~FORWARDING_HANDLER");
#endif
LOG_TRACE(L"FORWARDING_HANDLER::~FORWARDING_HANDLER");
//
// RemoveRequest() should already have been called and m_pDisconnect
// has been freed or m_pDisconnect was never initialized.
@ -309,10 +304,9 @@ FORWARDING_HANDLER::OnExecuteRequestHandler()
reinterpret_cast<DWORD_PTR>(static_cast<PVOID>(this))))
{
hr = HRESULT_FROM_WIN32(GetLastError());
#ifdef DEBUG
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"FORWARDING_HANDLER::OnExecuteRequestHandler, Send request failed");
#endif
LOG_TRACE(L"FORWARDING_HANDLER::OnExecuteRequestHandler, Send request failed");
// FREB log
if (ANCMEvents::ANCM_REQUEST_FORWARD_FAIL::IsEnabled(m_pW3Context->GetTraceContext()))
{
@ -460,10 +454,8 @@ REQUEST_NOTIFICATION_STATUS
if (m_RequestStatus == FORWARDER_RECEIVED_WEBSOCKET_RESPONSE)
{
#ifdef DEBUG
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"FORWARDING_HANDLER::OnAsyncCompletion, Send completed for 101 response");
#endif
LOG_TRACE(L"FORWARDING_HANDLER::OnAsyncCompletion, Send completed for 101 response");
//
// This should be the write completion of the 101 response.
//
@ -696,10 +688,7 @@ Finished:
//
// Do not use this object after dereferencing it, it may be gone.
//
#ifdef DEBUG
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"FORWARDING_HANDLER::OnAsyncCompletion Done %d", retVal);
#endif
LOG_TRACEF(L"FORWARDING_HANDLER::OnAsyncCompletion Done %d", retVal);
return retVal;
}
@ -1336,10 +1325,8 @@ None
dwInternetStatus);
}
#ifdef DEBUG
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"FORWARDING_HANDLER::OnWinHttpCompletionInternal %x -- %d --%p\n", dwInternetStatus, GetCurrentThreadId(), m_pW3Context);
#endif
LOG_TRACEF(L"FORWARDING_HANDLER::OnWinHttpCompletionInternal %x -- %d --%p\n", dwInternetStatus, GetCurrentThreadId(), m_pW3Context);
//
// Exclusive lock on the winhttp handle to protect from a client disconnect/
// server stop closing the handle while we are using it.
@ -2751,10 +2738,7 @@ FORWARDING_HANDLER::TerminateRequest(
// a winhttp callback on the same thread and we donot want to
// acquire the lock again
#ifdef DEBUG
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"FORWARDING_HANDLER::TerminateRequest %d --%p\n", GetCurrentThreadId(), m_pW3Context);
#endif // DEBUG
LOG_TRACEF(L"FORWARDING_HANDLER::TerminateRequest %d --%p\n", GetCurrentThreadId(), m_pW3Context);
if (!m_fHttpHandleInClose)
{

View File

@ -47,7 +47,7 @@ WEBSOCKET_HANDLER::WEBSOCKET_HANDLER() :
_fHandleClosed(FALSE),
_fReceivedCloseMsg(FALSE)
{
DebugPrintf (ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::WEBSOCKET_HANDLER");
LOG_TRACE(L"WEBSOCKET_HANDLER::WEBSOCKET_HANDLER");
InitializeCriticalSectionAndSpinCount(&_RequestLock, 1000);
InsertRequest();
@ -58,7 +58,7 @@ WEBSOCKET_HANDLER::Terminate(
VOID
)
{
DebugPrintf (ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::Terminate");
LOG_TRACE(L"WEBSOCKET_HANDLER::Terminate");
if (!_fHandleClosed)
{
RemoveRequest();
@ -212,8 +212,7 @@ WEBSOCKET_HANDLER::IndicateCompletionToIIS(
--*/
{
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::IndicateCompletionToIIS called %d", _dwOutstandingIo);
LOG_TRACEF(L"WEBSOCKET_HANDLER::IndicateCompletionToIIS called %d", _dwOutstandingIo);
//
// close Websocket handle. This will triger a WinHttp callback
@ -223,8 +222,7 @@ WEBSOCKET_HANDLER::IndicateCompletionToIIS(
//
if (_hWebSocketRequest != NULL && _dwOutstandingIo == 0)
{
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::IndicateCompletionToIIS");
LOG_TRACE(L"WEBSOCKET_HANDLER::IndicateCompletionToIIS");
_pHandler->SetStatus(FORWARDER_DONE);
_fHandleClosed = TRUE;
@ -262,8 +260,7 @@ Routine Description:
_pHandler = pHandler;
EnterCriticalSection(&_RequestLock);
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::ProcessRequest");
LOG_TRACEF(L"WEBSOCKET_HANDLER::ProcessRequest");
//
// Cache the points to IHttpContext3
@ -359,8 +356,7 @@ Finished:
if (FAILED_LOG(hr))
{
DebugPrintf (ASPNETCORE_DEBUG_FLAG_ERROR,
"Process Request Failed with HR=%08x", hr);
LOG_ERRORF(L"Process Request Failed with HR=%08x", hr);
}
return hr;
@ -385,8 +381,7 @@ Routine Description:
BOOL fFinalFragment;
BOOL fClose;
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::DoIisWebSocketReceive");
LOG_TRACE(L"WEBSOCKET_HANDLER::DoIisWebSocketReceive");
IncrementOutstandingIo();
@ -403,8 +398,7 @@ Routine Description:
if (FAILED_LOG(hr))
{
DecrementOutstandingIo();
DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
"WEBSOCKET_HANDLER::DoIisWebSocketSend failed with %08x", hr);
LOG_ERRORF(L"WEBSOCKET_HANDLER::DoIisWebSocketSend failed with %08x", hr);
}
return hr;
@ -426,8 +420,7 @@ Routine Description:
HRESULT hr = S_OK;
DWORD dwError = NO_ERROR;
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::DoWinHttpWebSocketReceive");
LOG_TRACE(L"WEBSOCKET_HANDLER::DoWinHttpWebSocketReceive");
IncrementOutstandingIo();
@ -442,8 +435,7 @@ Routine Description:
{
DecrementOutstandingIo();
hr = HRESULT_FROM_WIN32(dwError);
DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
"WEBSOCKET_HANDLER::DoWinHttpWebSocketReceive failed with %08x", hr);
LOG_ERRORF(L"WEBSOCKET_HANDLER::DoWinHttpWebSocketReceive failed with %08x", hr);
}
return hr;
@ -467,8 +459,7 @@ Routine Description:
BOOL fFinalFragment = FALSE;
BOOL fClose = FALSE;
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::DoIisWebSocketSend %d", eBufferType);
LOG_TRACEF(L"WEBSOCKET_HANDLER::DoIisWebSocketSend %d", eBufferType);
if (eBufferType == WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE)
{
@ -558,8 +549,7 @@ Routine Description:
Finished:
if (FAILED_LOG(hr))
{
DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
"WEBSOCKET_HANDLER::DoIisWebSocketSend failed with %08x", hr);
LOG_ERRORF(L"WEBSOCKET_HANDLER::DoIisWebSocketSend failed with %08x", hr);
}
return hr;
@ -581,8 +571,7 @@ Routine Description:
DWORD dwError = NO_ERROR;
HRESULT hr = S_OK;
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::DoWinHttpWebSocketSend, %d", eBufferType);
LOG_TRACEF(L"WEBSOCKET_HANDLER::DoWinHttpWebSocketSend, %d", eBufferType);
if (eBufferType == WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE)
{
@ -627,8 +616,7 @@ Routine Description:
// Call will complete asynchronously, return.
// ignore error.
//
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::DoWinhttpWebSocketSend IO_PENDING");
LOG_TRACE(L"WEBSOCKET_HANDLER::DoWinhttpWebSocketSend IO_PENDING");
dwError = NO_ERROR;
}
@ -639,8 +627,7 @@ Routine Description:
//
// Call completed synchronously.
//
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::DoWinhttpWebSocketSend Shutdown successful.");
LOG_TRACE(L"WEBSOCKET_HANDLER::DoWinhttpWebSocketSend Shutdown successful.");
}
}
}
@ -666,8 +653,7 @@ Routine Description:
Finished:
if (FAILED_LOG(hr))
{
DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
"WEBSOCKET_HANDLER::DoWinHttpWebSocketSend failed with %08x", hr);
LOG_ERRORF(L"WEBSOCKET_HANDLER::DoWinHttpWebSocketSend failed with %08x", hr);
}
return hr;
@ -755,8 +741,7 @@ Routine Description:
BOOL fLocked = FALSE;
CleanupReason cleanupReason = CleanupReasonUnknown;
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::OnWinHttpSendComplete");
LOG_TRACE(L"WEBSOCKET_HANDLER::OnWinHttpSendComplete");
if (_fCleanupInProgress)
{
@ -792,8 +777,7 @@ Finished:
{
Cleanup (cleanupReason);
DebugPrintf (ASPNETCORE_DEBUG_FLAG_ERROR,
"WEBSOCKET_HANDLER::OnWinsockSendComplete failed with HR=%08x", hr);
LOG_ERRORF(L"WEBSOCKET_HANDLER::OnWinsockSendComplete failed with HR=%08x", hr);
}
//
@ -810,8 +794,7 @@ WEBSOCKET_HANDLER::OnWinHttpShutdownComplete(
VOID
)
{
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::OnWinHttpShutdownComplete --%p", _pHandler);
LOG_TRACEF(L"WEBSOCKET_HANDLER::OnWinHttpShutdownComplete --%p", _pHandler);
DecrementOutstandingIo();
@ -825,8 +808,7 @@ WEBSOCKET_HANDLER::OnWinHttpIoError(
{
HRESULT hr = HRESULT_FROM_WIN32(pCompletionStatus->AsyncResult.dwError);
DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR,
"WEBSOCKET_HANDLER::OnWinHttpIoError HR = %08x, Operation = %d",
LOG_ERRORF(L"WEBSOCKET_HANDLER::OnWinHttpIoError HR = %08x, Operation = %d",
hr, pCompletionStatus->AsyncResult.dwResult);
Cleanup(ServerDisconnect);
@ -858,8 +840,7 @@ Routine Description:
BOOL fLocked = FALSE;
CleanupReason cleanupReason = CleanupReasonUnknown;
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::OnWinHttpReceiveComplete --%p", _pHandler);
LOG_TRACEF(L"WEBSOCKET_HANDLER::OnWinHttpReceiveComplete --%p", _pHandler);
if (_fCleanupInProgress)
{
@ -893,8 +874,7 @@ Finished:
{
Cleanup (cleanupReason);
DebugPrintf (ASPNETCORE_DEBUG_FLAG_ERROR,
"WEBSOCKET_HANDLER::OnWinsockReceiveComplete failed with HR=%08x", hr);
LOG_ERRORF(L"WEBSOCKET_HANDLER::OnWinsockReceiveComplete failed with HR=%08x", hr);
}
//
@ -929,7 +909,7 @@ Routine Description:
UNREFERENCED_PARAMETER(cbIo);
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, "WEBSOCKET_HANDLER::OnIisSendComplete");
LOG_TRACE(L"WEBSOCKET_HANDLER::OnIisSendComplete");
if (FAILED_LOG(hrCompletion))
{
@ -974,8 +954,7 @@ Finished:
{
Cleanup (cleanupReason);
DebugPrintf (ASPNETCORE_DEBUG_FLAG_ERROR,
"WEBSOCKET_HANDLER::OnIisSendComplete failed with HR=%08x", hr);
LOG_ERRORF(L"WEBSOCKET_HANDLER::OnIisSendComplete failed with HR=%08x", hr);
}
//
@ -1014,8 +993,7 @@ Routine Description:
CleanupReason cleanupReason = CleanupReasonUnknown;
WINHTTP_WEB_SOCKET_BUFFER_TYPE BufferType;
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::OnIisReceiveComplete");
LOG_TRACE(L"WEBSOCKET_HANDLER::OnIisReceiveComplete");
if (FAILED_LOG(hrCompletion))
{
@ -1065,8 +1043,7 @@ Finished:
{
Cleanup (cleanupReason);
DebugPrintf (ASPNETCORE_DEBUG_FLAG_ERROR,
"WEBSOCKET_HANDLER::OnIisReceiveComplete failed with HR=%08x", hr);
LOG_ERRORF(L"WEBSOCKET_HANDLER::OnIisReceiveComplete failed with HR=%08x", hr);
}
//
@ -1097,8 +1074,7 @@ Arguments:
--*/
{
BOOL fLocked = FALSE;
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"WEBSOCKET_HANDLER::Cleanup Initiated with reason %d", reason);
LOG_TRACEF(L"WEBSOCKET_HANDLER::Cleanup Initiated with reason %d", reason);
if (_fCleanupInProgress)
{

View File

@ -38,7 +38,7 @@ HRESULT AppOfflineTrackingApplication::StartMonitoringAppOflineImpl()
{
if (m_fileWatcher)
{
RETURN_IF_FAILED(E_UNEXPECTED);
RETURN_HR(E_UNEXPECTED);
}
m_fileWatcher = std::make_unique<FILE_WATCHER>();

View File

@ -72,16 +72,20 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>C:\AspNetCoreModule\src\IISLib;$(IncludePath)</IncludePath>
<OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>

View File

@ -1,2 +0,0 @@
LANGUAGE 0x9,0x1
1 11 "MSG00001.bin"

View File

@ -55,8 +55,6 @@ REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(
goto Finished;
}
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO,
"REQUESTHANDLER_CONFIG::GetConfig, set config to ModuleContext");
// set appliction info here instead of inside Populate()
// as the destructor will delete the backend process
hr = pRequestHandlerConfig->QueryApplicationPath()->Copy(pHttpApplication->GetApplicationId());

View File

@ -20,9 +20,9 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
{
private const string WebSocketVersionString = "WEBSOCKET_VERSION";
private static NativeMethods.PFN_REQUEST_HANDLER _requestHandler = HandleRequest;
private static NativeMethods.PFN_SHUTDOWN_HANDLER _shutdownHandler = HandleShutdown;
private static NativeMethods.PFN_ASYNC_COMPLETION _onAsyncCompletion = OnAsyncCompletion;
private static readonly NativeMethods.PFN_REQUEST_HANDLER _requestHandler = HandleRequest;
private static readonly NativeMethods.PFN_SHUTDOWN_HANDLER _shutdownHandler = HandleShutdown;
private static readonly NativeMethods.PFN_ASYNC_COMPLETION _onAsyncCompletion = OnAsyncCompletion;
private IISContextFactory _iisContextFactory;
private readonly MemoryPool<byte> _memoryPool = new SlabMemoryPool();
@ -147,15 +147,24 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
private static NativeMethods.REQUEST_NOTIFICATION_STATUS HandleRequest(IntPtr pInProcessHandler, IntPtr pvRequestContext)
{
// Unwrap the server so we can create an http context and process the request
var server = (IISHttpServer)GCHandle.FromIntPtr(pvRequestContext).Target;
Interlocked.Increment(ref server._outstandingRequests);
IISHttpServer server = null;
try
{
// Unwrap the server so we can create an http context and process the request
server = (IISHttpServer)GCHandle.FromIntPtr(pvRequestContext).Target;
Interlocked.Increment(ref server._outstandingRequests);
var context = server._iisContextFactory.CreateHttpContext(pInProcessHandler);
var context = server._iisContextFactory.CreateHttpContext(pInProcessHandler);
ThreadPool.QueueUserWorkItem(state => _ = HandleRequest((IISHttpContext)state), context);
ThreadPool.QueueUserWorkItem(state => _ = HandleRequest((IISHttpContext)state), context);
return NativeMethods.REQUEST_NOTIFICATION_STATUS.RQ_NOTIFICATION_PENDING;
}
catch (Exception ex)
{
server?._logger.LogError(0, ex, $"Unexpected exception in static {nameof(IISHttpServer)}.{nameof(HandleRequest)}.");
return NativeMethods.REQUEST_NOTIFICATION_STATUS.RQ_NOTIFICATION_PENDING;
return NativeMethods.REQUEST_NOTIFICATION_STATUS.RQ_NOTIFICATION_FINISH_REQUEST;
}
}
private static async Task HandleRequest(IISHttpContext context)
@ -167,7 +176,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
}
catch (Exception ex)
{
context.Server._logger.LogError("Exception in ProcessRequestAsync", ex);
context.Server._logger.LogError(0, ex, $"Unexpected exception in {nameof(IISHttpServer)}.{nameof(HandleRequest)}.");
}
finally
{
@ -177,16 +186,34 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
private static bool HandleShutdown(IntPtr pvRequestContext)
{
var server = (IISHttpServer)GCHandle.FromIntPtr(pvRequestContext).Target;
server._applicationLifetime.StopApplication();
IISHttpServer server = null;
try
{
server = (IISHttpServer)GCHandle.FromIntPtr(pvRequestContext).Target;
server._applicationLifetime.StopApplication();
}
catch (Exception ex)
{
server?._logger.LogError(0, ex, $"Unexpected exception in {nameof(IISHttpServer)}.{nameof(HandleShutdown)}.");
}
return true;
}
private static NativeMethods.REQUEST_NOTIFICATION_STATUS OnAsyncCompletion(IntPtr pvManagedHttpContext, int hr, int bytes)
{
var context = (IISHttpContext)GCHandle.FromIntPtr(pvManagedHttpContext).Target;
context.OnAsyncCompletion(hr, bytes);
return NativeMethods.REQUEST_NOTIFICATION_STATUS.RQ_NOTIFICATION_PENDING;
IISHttpContext context = null;
try
{
context = (IISHttpContext)GCHandle.FromIntPtr(pvManagedHttpContext).Target;
context.OnAsyncCompletion(hr, bytes);
return NativeMethods.REQUEST_NOTIFICATION_STATUS.RQ_NOTIFICATION_PENDING;
}
catch (Exception ex)
{
context?.Server._logger.LogError(0, ex, $"Unexpected exception in {nameof(IISHttpServer)}.{nameof(OnAsyncCompletion)}.");
return NativeMethods.REQUEST_NOTIFICATION_STATUS.RQ_NOTIFICATION_FINISH_REQUEST;
}
}
private static void CompleteRequest(IISHttpContext context, bool result)

View File

@ -8,6 +8,7 @@ using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks.Sources;
using Microsoft.AspNetCore.Connections;
namespace Microsoft.AspNetCore.Server.IIS.Core.IO
{
@ -103,7 +104,8 @@ namespace Microsoft.AspNetCore.Server.IIS.Core.IO
_result = bytes;
if (hr != NativeMethods.HR_OK)
{
_exception = new IOException("Native IO operation failed", Marshal.GetExceptionForHR(hr));
// Treat all errors as the client disconnect
_exception = new ConnectionResetException("The client has disconnected", Marshal.GetExceptionForHR(hr));
}
}
else

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
@ -24,6 +24,7 @@
<PackageReference Include="Microsoft.AspNetCore.Authentication.Core" Version="$(MicrosoftAspNetCoreAuthenticationCorePackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="$(MicrosoftAspNetCoreHostingAbstractionsPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Connections.Abstractions" Version="$(MicrosoftAspNetCoreConnectionsAbstractionsPackageVersion)" />
</ItemGroup>
<ItemGroup Condition="'$(VCTargetsPath)' != ''">

View File

@ -88,7 +88,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
!IISDeploymentParameters.HandlerSettings.ContainsKey("debugFile"))
{
_debugLogFile = Path.GetTempFileName();
IISDeploymentParameters.HandlerSettings["debugLevel"] = "4";
IISDeploymentParameters.HandlerSettings["debugLevel"] = "file";
IISDeploymentParameters.HandlerSettings["debugFile"] = _debugLogFile;
}
@ -254,6 +254,11 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
}
HostProcess = Process.GetProcessById(workerProcess.ProcessId);
// Ensure w3wp.exe is killed if test process termination is non-graceful.
// Prevents locked files when stop debugging unit test.
ProcessTracker.Add(HostProcess);
// cache the process start time for verifying log file name.
var _ = HostProcess.StartTime;

View File

@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
{
public static void AddDebugLogToWebConfig(this IISDeploymentParameters parameters, string filename)
{
parameters.HandlerSettings["debugLevel"] = "4";
parameters.HandlerSettings["debugLevel"] = "file";
parameters.HandlerSettings["debugFile"] = filename;
}
@ -60,5 +60,25 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
deploymentParameters.WebConfigActionList.Add(
WebConfigHelpers.AddOrModifyAspNetCoreSection("stdoutLogFile", Path.Combine(path, "std")));
}
public static void TransformPath(this IISDeploymentParameters parameters, Func<string, string, string> transformation)
{
parameters.WebConfigActionList.Add(
(config, contentRoot) =>
{
var aspNetCoreElement = config.Descendants("aspNetCore").Single();
aspNetCoreElement.SetAttributeValue("processPath", transformation((string)aspNetCoreElement.Attribute("processPath"), contentRoot));
});
}
public static void TransformArguments(this IISDeploymentParameters parameters, Func<string, string, string> transformation)
{
parameters.WebConfigActionList.Add(
(config, contentRoot) =>
{
var aspNetCoreElement = config.Descendants("aspNetCore").Single();
aspNetCoreElement.SetAttributeValue("arguments", transformation((string)aspNetCoreElement.Attribute("arguments"), contentRoot));
});
}
}
}

View File

@ -249,8 +249,14 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
else
{
_hostProcess = process;
// Ensure iisexpress.exe is killed if test process termination is non-graceful.
// Prevents locked files when stop debugging unit test.
ProcessTracker.Add(_hostProcess);
// cache the process start time for verifying log file name.
var _ = _hostProcess.StartTime;
Logger.LogInformation("Started iisexpress successfully. Process Id : {processId}, Port: {port}", _hostProcess.Id, port);
return (url: url, hostExitToken: hostExitTokenSource.Token);
}
@ -483,7 +489,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
}
else
{
throw new InvalidOperationException($"iisexpress Process {hostProcess.Id} crashed before shutdown was triggered.");
throw new InvalidOperationException($"iisexpress Process {hostProcess?.Id} crashed before shutdown was triggered.");
}
}
}

View File

@ -0,0 +1,128 @@
// 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.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
{
// Uses Windows Job Objects to ensure external processes are killed if the current process is terminated non-gracefully.
internal static class ProcessTracker
{
private static readonly IntPtr _jobHandle;
static ProcessTracker()
{
// Requires Win8 or later
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || Environment.OSVersion.Version < new Version(6, 2))
{
return;
}
// Job name is optional but helps with diagnostics. Job name must be unique if non-null.
_jobHandle = CreateJobObject(IntPtr.Zero, name: $"ProcessTracker{Process.GetCurrentProcess().Id}");
var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
BasicLimitInformation = new JOBOBJECT_BASIC_LIMIT_INFORMATION
{
LimitFlags = JOBOBJECTLIMIT.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
}
};
var length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
var extendedInfoPtr = Marshal.AllocHGlobal(length);
try
{
Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);
if (!SetInformationJobObject(_jobHandle, JobObjectInfoType.ExtendedLimitInformation,
extendedInfoPtr, (uint)length))
{
throw new Win32Exception();
}
}
finally
{
Marshal.FreeHGlobal(extendedInfoPtr);
}
}
public static void Add(Process process)
{
if (_jobHandle != IntPtr.Zero)
{
var success = AssignProcessToJobObject(_jobHandle, process.Handle);
if (!success && !process.HasExited)
{
throw new Win32Exception();
}
}
}
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
static extern IntPtr CreateJobObject(IntPtr lpJobAttributes, string name);
[DllImport("kernel32.dll")]
static extern bool SetInformationJobObject(IntPtr job, JobObjectInfoType infoType,
IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
private enum JobObjectInfoType
{
AssociateCompletionPortInformation = 7,
BasicLimitInformation = 2,
BasicUIRestrictions = 4,
EndOfJobTimeInformation = 6,
ExtendedLimitInformation = 9,
SecurityLimitInformation = 5,
GroupInformation = 11
}
[StructLayout(LayoutKind.Sequential)]
private struct JOBOBJECT_BASIC_LIMIT_INFORMATION
{
public Int64 PerProcessUserTimeLimit;
public Int64 PerJobUserTimeLimit;
public JOBOBJECTLIMIT LimitFlags;
public UIntPtr MinimumWorkingSetSize;
public UIntPtr MaximumWorkingSetSize;
public UInt32 ActiveProcessLimit;
public Int64 Affinity;
public UInt32 PriorityClass;
public UInt32 SchedulingClass;
}
[Flags]
private enum JOBOBJECTLIMIT : uint
{
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x2000
}
[StructLayout(LayoutKind.Sequential)]
private struct IO_COUNTERS
{
public UInt64 ReadOperationCount;
public UInt64 WriteOperationCount;
public UInt64 OtherOperationCount;
public UInt64 ReadTransferCount;
public UInt64 WriteTransferCount;
public UInt64 OtherTransferCount;
}
[StructLayout(LayoutKind.Sequential)]
private struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
public IO_COUNTERS IoInfo;
public UIntPtr ProcessMemoryLimit;
public UIntPtr JobMemoryLimit;
public UIntPtr PeakProcessMemoryUsed;
public UIntPtr PeakJobMemoryUsed;
}
}
}

View File

@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
await deploymentResult.HttpClient.RetryRequestAsync("/HelloWorld", r => r.StatusCode == HttpStatusCode.InternalServerError);
StopServer();
EventLogHelpers.VerifyEventLogEvent(deploymentResult, TestSink, "Could not find the assembly 'aspnetcorev2_inprocess.dll'");
EventLogHelpers.VerifyEventLogEvent(deploymentResult, "Could not find the assembly 'aspnetcorev2_inprocess.dll'");
}
[ConditionalTheory]

View File

@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
StopServer();
EventLogHelpers.VerifyEventLogEvent(deploymentResult, TestSink, "Application '.+' started the coreclr in-process successfully.");
EventLogHelpers.VerifyEventLogEvent(deploymentResult, "Application '.+' started the coreclr in-process successfully.");
}
[ConditionalFact]
@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
StopServer();
EventLogHelpers.VerifyEventLogEvent(deploymentResult, TestSink, "Application '.+' has shutdown.");
EventLogHelpers.VerifyEventLogEvent(deploymentResult, "Application '.+' has shutdown.");
}
}
}

View File

@ -200,17 +200,44 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
}
}
private static void AssertLogs(string logPath)
[ConditionalFact]
public async Task DebugLogsAreWrittenToEventLog()
{
var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
deploymentParameters.HandlerSettings["debugLevel"] = "file,eventlog";
var deploymentResult = await StartAsync(deploymentParameters);
StopServer();
EventLogHelpers.VerifyEventLogEvent(deploymentResult, @"\[aspnetcorev2.dll\] Initializing logs for .*?Description: IIS ASP.NET Core Module V2");
}
[ConditionalFact]
public async Task OutOfProcessReadsLogConfiguration()
{
var deploymentParameters = _fixture.GetBaseDeploymentParameters(hostingModel:HostingModel.OutOfProcess, publish: true);
deploymentParameters.HandlerSettings["debugLevel"] = "file,trace";
deploymentParameters.HandlerSettings["debugFile"] = "";
var deploymentResult = await StartAsync(deploymentParameters);
var logContents = ReadLogs(Path.Combine(deploymentResult.ContentRoot, "aspnetcore-debug.log"));
Assert.Contains("FORWARDING_HANDLER::", logContents);
}
private static string ReadLogs(string logPath)
{
using (var stream = File.Open(logPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var streamReader = new StreamReader(stream))
{
var logContents = streamReader.ReadToEnd();
Assert.Contains("[aspnetcorev2.dll]", logContents);
Assert.Contains("[aspnetcorev2_inprocess.dll]", logContents);
Assert.Contains("Description: IIS ASP.NET Core Module V2. Commit:", logContents);
Assert.Contains("Description: IIS ASP.NET Core Module V2 Request Handler. Commit:", logContents);
return streamReader.ReadToEnd();
}
}
private static void AssertLogs(string logPath)
{
var logContents = ReadLogs(logPath);
Assert.Contains("[aspnetcorev2.dll]", logContents);
Assert.Contains("[aspnetcorev2_inprocess.dll]", logContents);
Assert.Contains("Description: IIS ASP.NET Core Module V2. Commit:", logContents);
Assert.Contains("Description: IIS ASP.NET Core Module V2 Request Handler. Commit:", logContents);
}
}
}

Some files were not shown because too many files have changed in this diff Show More