diff --git a/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj b/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj
index b809cdeadc..d700f7ed1b 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj
+++ b/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj
@@ -231,7 +231,7 @@
-
+
@@ -246,7 +246,7 @@
-
+
diff --git a/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp
index 51b8cb611e..fbed8b09e9 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp
+++ b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp
@@ -12,6 +12,8 @@
#include "file_utility.h"
#include "LoggingHelpers.h"
#include "resources.h"
+#include "ConfigurationLoadException.h"
+#include "WebConfigConfigurationSource.h"
const PCWSTR HandlerResolver::s_pwzAspnetcoreInProcessRequestHandlerName = L"aspnetcorev2_inprocess.dll";
const PCWSTR HandlerResolver::s_pwzAspnetcoreOutOfProcessRequestHandlerName = L"aspnetcorev2_outofprocess.dll";
@@ -25,7 +27,7 @@ HandlerResolver::HandlerResolver(HMODULE hModule, IHttpServer &pServer)
}
HRESULT
-HandlerResolver::LoadRequestHandlerAssembly(IHttpApplication &pApplication, ASPNETCORE_SHIM_CONFIG& pConfiguration, std::unique_ptr& pApplicationFactory)
+HandlerResolver::LoadRequestHandlerAssembly(IHttpApplication &pApplication, ShimOptions& pConfiguration, std::unique_ptr& pApplicationFactory)
{
HRESULT hr;
PCWSTR pstrHandlerDllName;
@@ -65,7 +67,7 @@ HandlerResolver::LoadRequestHandlerAssembly(IHttpApplication &pApplication, ASPN
RETURN_IF_FAILED(LoggingHelpers::CreateLoggingProvider(
pConfiguration.QueryStdoutLogEnabled(),
!m_pServer.IsCommandLineLaunch(),
- pConfiguration.QueryStdoutLogFile()->QueryStr(),
+ pConfiguration.QueryStdoutLogFile().c_str(),
pApplication.GetApplicationPhysicalPath(),
outputManager));
@@ -129,20 +131,20 @@ HandlerResolver::GetApplicationFactory(IHttpApplication &pApplication, std::uniq
{
try
{
- ASPNETCORE_SHIM_CONFIG pConfiguration;
- RETURN_IF_FAILED(pConfiguration.Populate(&m_pServer, &pApplication));
+ const WebConfigConfigurationSource configurationSource(m_pServer.GetAdminManager(), pApplication);
+ ShimOptions options(configurationSource);
SRWExclusiveLock lock(m_requestHandlerLoadLock);
if (m_loadedApplicationHostingModel != HOSTING_UNKNOWN)
{
// Mixed hosting models
- if (m_loadedApplicationHostingModel != pConfiguration.QueryHostingModel())
+ if (m_loadedApplicationHostingModel != options.QueryHostingModel())
{
EventLog::Error(
ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR,
ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG,
pApplication.GetApplicationId(),
- pConfiguration.QueryHostingModel());
+ options.QueryHostingModel());
return E_FAIL;
}
@@ -158,11 +160,20 @@ HandlerResolver::GetApplicationFactory(IHttpApplication &pApplication, std::uniq
}
}
- m_loadedApplicationHostingModel = pConfiguration.QueryHostingModel();
+ m_loadedApplicationHostingModel = options.QueryHostingModel();
m_loadedApplicationId = pApplication.GetApplicationId();
- RETURN_IF_FAILED(LoadRequestHandlerAssembly(pApplication, pConfiguration, pApplicationFactory));
+ RETURN_IF_FAILED(LoadRequestHandlerAssembly(pApplication, options, pApplicationFactory));
}
+ catch(ConfigurationLoadException &ex)
+ {
+ EventLog::Error(
+ ASPNETCORE_CONFIGURATION_LOAD_ERROR,
+ ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG,
+ ex.get_message().c_str());
+
+ RETURN_HR(E_FAIL);
+ }
CATCH_RETURN();
return S_OK;
@@ -178,7 +189,7 @@ void HandlerResolver::ResetHostingModel()
HRESULT
HandlerResolver::FindNativeAssemblyFromGlobalLocation(
- ASPNETCORE_SHIM_CONFIG& pConfiguration,
+ ShimOptions& pConfiguration,
PCWSTR pstrHandlerDllName,
std::wstring& handlerDllPath
)
diff --git a/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h
index 101b1ad2a0..be927693ab 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h
+++ b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h
@@ -2,10 +2,10 @@
// Licensed under the MIT License. See License.txt in the project root for license information.
#pragma once
-#include "aspnetcore_shim_config.h"
#include
#include
+#include "ShimOptions.h"
#include "hostfxroptions.h"
#include "HandleWrapper.h"
#include "ApplicationFactory.h"
@@ -18,8 +18,8 @@ public:
void ResetHostingModel();
private:
- HRESULT LoadRequestHandlerAssembly(IHttpApplication &pApplication, ASPNETCORE_SHIM_CONFIG& pConfiguration, std::unique_ptr& pApplicationFactory);
- HRESULT FindNativeAssemblyFromGlobalLocation(ASPNETCORE_SHIM_CONFIG& pConfiguration, PCWSTR libraryName, std::wstring& handlerDllPath);
+ HRESULT LoadRequestHandlerAssembly(IHttpApplication &pApplication, ShimOptions& pConfiguration, std::unique_ptr& pApplicationFactory);
+ HRESULT FindNativeAssemblyFromGlobalLocation(ShimOptions& pConfiguration, PCWSTR libraryName, std::wstring& handlerDllPath);
HRESULT FindNativeAssemblyFromHostfxr(HOSTFXR_OPTIONS& hostfxrOptions, PCWSTR libraryName, std::wstring& handlerDllPath);
HMODULE m_hModule;
diff --git a/src/AspNetCoreModuleV2/AspNetCore/PollingAppOfflineApplication.h b/src/AspNetCoreModuleV2/AspNetCore/PollingAppOfflineApplication.h
index e7ec367c17..193a63e639 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/PollingAppOfflineApplication.h
+++ b/src/AspNetCoreModuleV2/AspNetCore/PollingAppOfflineApplication.h
@@ -15,7 +15,7 @@ class PollingAppOfflineApplication: public APPLICATION
{
public:
PollingAppOfflineApplication(IHttpApplication& pApplication, PollingAppOfflineApplicationMode mode)
- :
+ : APPLICATION(pApplication),
m_ulLastCheckTime(0),
m_appOfflineLocation(GetAppOfflineLocation(pApplication)),
m_fAppOfflineFound(false),
diff --git a/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp b/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp
new file mode 100644
index 0000000000..3ba1db7889
--- /dev/null
+++ b/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp
@@ -0,0 +1,43 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "ShimOptions.h"
+
+#include "StringHelpers.h"
+#include "ConfigurationLoadException.h"
+
+#define CS_ASPNETCORE_HANDLER_VERSION L"handlerVersion"
+
+ShimOptions::ShimOptions(const ConfigurationSource &configurationSource) :
+ m_hostingModel(HOSTING_UNKNOWN),
+ m_fStdoutLogEnabled(false)
+{
+ auto const section = configurationSource.GetRequiredSection(CS_ASPNETCORE_SECTION);
+ auto hostingModel = section->GetString(CS_ASPNETCORE_HOSTING_MODEL).value_or(L"");
+
+ if (hostingModel.empty() || equals_ignore_case(hostingModel, CS_ASPNETCORE_HOSTING_MODEL_OUTOFPROCESS))
+ {
+ m_hostingModel = HOSTING_OUT_PROCESS;
+ }
+ else if (equals_ignore_case(hostingModel, CS_ASPNETCORE_HOSTING_MODEL_INPROCESS))
+ {
+ m_hostingModel = HOSTING_IN_PROCESS;
+ }
+ else
+ {
+ throw ConfigurationLoadException(format(
+ L"Unknown hosting model '%s'. Please specify either hostingModel=\"inprocess\" "
+ "or hostingModel=\"outofprocess\" in the web.config file.", hostingModel.c_str()));
+ }
+
+ if (m_hostingModel == HOSTING_OUT_PROCESS)
+ {
+ const auto handlerSettings = section->GetKeyValuePairs(CS_ASPNETCORE_HANDLER_SETTINGS);
+ m_strHandlerVersion = find_element(handlerSettings, CS_ASPNETCORE_HANDLER_VERSION).value_or(std::wstring());
+ }
+
+ m_strProcessPath = section->GetRequiredString(CS_ASPNETCORE_PROCESS_EXE_PATH);
+ m_strArguments = section->GetString(CS_ASPNETCORE_PROCESS_ARGUMENTS).value_or(CS_ASPNETCORE_PROCESS_ARGUMENTS_DEFAULT);
+ m_fStdoutLogEnabled = section->GetRequiredBool(CS_ASPNETCORE_STDOUT_LOG_ENABLED);
+ m_struStdoutLogFile = section->GetRequiredString(CS_ASPNETCORE_STDOUT_LOG_FILE);
+}
diff --git a/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.h b/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.h
new file mode 100644
index 0000000000..f987e864ba
--- /dev/null
+++ b/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.h
@@ -0,0 +1,65 @@
+// 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
+#include "ConfigurationSource.h"
+#include "exceptions.h"
+
+enum APP_HOSTING_MODEL
+{
+ HOSTING_UNKNOWN = 0,
+ HOSTING_IN_PROCESS,
+ HOSTING_OUT_PROCESS
+};
+
+class ShimOptions: NonCopyable
+{
+public:
+ const std::wstring&
+ QueryProcessPath() const
+ {
+ return m_strProcessPath;
+ }
+
+ const std::wstring&
+ QueryArguments() const
+ {
+ return m_strArguments;
+ }
+
+ APP_HOSTING_MODEL
+ QueryHostingModel() const
+ {
+ return m_hostingModel;
+ }
+
+ const std::wstring&
+ QueryHandlerVersion() const
+ {
+ return m_strHandlerVersion;
+ }
+
+ BOOL
+ QueryStdoutLogEnabled() const
+ {
+ return m_fStdoutLogEnabled;
+ }
+
+ const std::wstring&
+ QueryStdoutLogFile() const
+ {
+ return m_struStdoutLogFile;
+ }
+
+ ShimOptions(const ConfigurationSource &configurationSource);
+
+private:
+ std::wstring m_strArguments;
+ std::wstring m_strProcessPath;
+ APP_HOSTING_MODEL m_hostingModel;
+ std::wstring m_strHandlerVersion;
+ std::wstring m_struStdoutLogFile;
+ bool m_fStdoutLogEnabled;
+};
diff --git a/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.h b/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.h
index 90f9fe8df9..94f2718e08 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.h
+++ b/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.h
@@ -4,7 +4,6 @@
#pragma once
#include "hostfxroptions.h"
-#include "aspnetcore_shim_config.h"
#include "iapplication.h"
#include "SRWSharedLock.h"
#include "HandlerResolver.h"
diff --git a/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.cpp b/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.cpp
deleted file mode 100644
index f994fcc06d..0000000000
--- a/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the MIT License. See License.txt in the project root for license information.
-
-#include "aspnetcore_shim_config.h"
-
-#include "EventLog.h"
-#include "config_utility.h"
-#include "ahutil.h"
-
-HRESULT
-ASPNETCORE_SHIM_CONFIG::Populate(
- IHttpServer *pHttpServer,
- IHttpApplication *pHttpApplication
-)
-{
- STACK_STRU(strHostingModel, 12);
- CComPtr pAspNetCoreElement;
-
- IAppHostAdminManager *pAdminManager = pHttpServer->GetAdminManager();
- const CComBSTR bstrAspNetCoreSection = CS_ASPNETCORE_SECTION;
- const CComBSTR applicationConfigPath = pHttpApplication->GetAppConfigPath();
-
- RETURN_IF_FAILED(pAdminManager->GetAdminSection(bstrAspNetCoreSection,
- applicationConfigPath,
- &pAspNetCoreElement));
-
- CComBSTR struProcessPath;
- RETURN_IF_FAILED(GetElementStringProperty(pAspNetCoreElement,
- CS_ASPNETCORE_PROCESS_EXE_PATH,
- &struProcessPath));
- m_strProcessPath = struProcessPath;
-
- // Swallow this error for backward compatibility
- // Use default behavior for empty string
- GetElementStringProperty(pAspNetCoreElement,
- CS_ASPNETCORE_HOSTING_MODEL,
- &strHostingModel);
-
- if (strHostingModel.IsEmpty() || strHostingModel.Equals(L"outofprocess", TRUE))
- {
- m_hostingModel = HOSTING_OUT_PROCESS;
- }
- else if (strHostingModel.Equals(L"inprocess", TRUE))
- {
- m_hostingModel = HOSTING_IN_PROCESS;
- }
- else
- {
- // block unknown hosting value
- EventLog::Error(
- ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR,
- ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR_MSG,
- strHostingModel.QueryStr());
- RETURN_HR(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));
- }
-
- CComBSTR struArguments;
- RETURN_IF_FAILED(GetElementStringProperty(pAspNetCoreElement,
- CS_ASPNETCORE_PROCESS_ARGUMENTS,
- &struArguments));
-
- m_strArguments = struArguments;
-
- if (m_hostingModel == HOSTING_OUT_PROCESS)
- {
- STRU struHandlerVersion;
- RETURN_IF_FAILED(ConfigUtility::FindHandlerVersion(pAspNetCoreElement, struHandlerVersion));
- m_strHandlerVersion = struHandlerVersion.QueryStr();
- }
-
-
- RETURN_IF_FAILED(GetElementBoolProperty(pAspNetCoreElement,
- CS_ASPNETCORE_STDOUT_LOG_ENABLED,
- &m_fStdoutLogEnabled));
- RETURN_IF_FAILED(GetElementStringProperty(pAspNetCoreElement,
- CS_ASPNETCORE_STDOUT_LOG_FILE,
- &m_struStdoutLogFile));
-
- return S_OK;
-}
diff --git a/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.h b/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.h
deleted file mode 100644
index c380433e72..0000000000
--- a/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// 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
-#include
-#include
-
-#define CS_ASPNETCORE_SECTION L"system.webServer/aspNetCore"
-#define CS_ASPNETCORE_PROCESS_EXE_PATH L"processPath"
-#define CS_ASPNETCORE_PROCESS_ARGUMENTS L"arguments"
-#define CS_ASPNETCORE_HOSTING_MODEL L"hostingModel"
-#define CS_ASPNETCORE_STDOUT_LOG_ENABLED L"stdoutLogEnabled"
-#define CS_ASPNETCORE_STDOUT_LOG_FILE L"stdoutLogFile"
-
-enum APP_HOSTING_MODEL
-{
- HOSTING_UNKNOWN = 0,
- HOSTING_IN_PROCESS,
- HOSTING_OUT_PROCESS
-};
-
-class ASPNETCORE_SHIM_CONFIG
-{
-public:
- virtual
- ~ASPNETCORE_SHIM_CONFIG() = default;
-
- HRESULT
- Populate(
- IHttpServer *pHttpServer,
- IHttpApplication *pHttpApplication
- );
-
- std::wstring&
- QueryProcessPath()
- {
- return m_strProcessPath;
- }
-
- std::wstring&
- QueryArguments()
- {
- return m_strArguments;
- }
-
- APP_HOSTING_MODEL
- QueryHostingModel()
- {
- return m_hostingModel;
- }
-
- std::wstring&
- QueryHandlerVersion()
- {
- return m_strHandlerVersion;
- }
-
- BOOL
- QueryStdoutLogEnabled()
- {
- return m_fStdoutLogEnabled;
- }
-
- STRU*
- QueryStdoutLogFile()
- {
- return &m_struStdoutLogFile;
- }
-
- ASPNETCORE_SHIM_CONFIG() :
- m_hostingModel(HOSTING_UNKNOWN)
- {
- }
-
-private:
-
- std::wstring m_strArguments;
- std::wstring m_strProcessPath;
- APP_HOSTING_MODEL m_hostingModel;
- std::wstring m_strHandlerVersion;
- BOOL m_fStdoutLogEnabled;
- STRU m_struStdoutLogFile;
-};
diff --git a/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj b/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj
index 84b7f360cc..ef9f1c1986 100644
--- a/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj
+++ b/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj
@@ -195,6 +195,9 @@
+
+
+
@@ -211,6 +214,7 @@
+
@@ -221,8 +225,12 @@
+
+
+
+
@@ -245,6 +253,8 @@
Create
+
+
diff --git a/src/AspNetCoreModuleV2/CommonLib/ConfigurationLoadException.h b/src/AspNetCoreModuleV2/CommonLib/ConfigurationLoadException.h
new file mode 100644
index 0000000000..0aade37061
--- /dev/null
+++ b/src/AspNetCoreModuleV2/CommonLib/ConfigurationLoadException.h
@@ -0,0 +1,20 @@
+// 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
+
+class ConfigurationLoadException: public std::runtime_error
+{
+ public:
+ ConfigurationLoadException(std::wstring msg)
+ : runtime_error("Configuration load exception has occured"), message(std::move(msg))
+ {
+ }
+
+ std::wstring get_message() const { return message; }
+
+ private:
+ std::wstring message;
+};
diff --git a/src/AspNetCoreModuleV2/CommonLib/ConfigurationSection.cpp b/src/AspNetCoreModuleV2/CommonLib/ConfigurationSection.cpp
new file mode 100644
index 0000000000..77c3319dd1
--- /dev/null
+++ b/src/AspNetCoreModuleV2/CommonLib/ConfigurationSection.cpp
@@ -0,0 +1,57 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "ConfigurationSection.h"
+
+#include "StringHelpers.h"
+#include "ConfigurationLoadException.h"
+
+std::wstring ConfigurationSection::GetRequiredString(const std::wstring& name) const
+{
+ auto result = GetString(name);
+ if (!result.has_value() || result.value().empty())
+ {
+ ThrowRequiredException(name);
+ }
+ return result.value();
+}
+
+bool ConfigurationSection::GetRequiredBool(const std::wstring& name) const
+{
+ auto result = GetBool(name);
+ if (!result.has_value())
+ {
+ ThrowRequiredException(name);
+ }
+ return result.value();
+}
+
+DWORD ConfigurationSection::GetRequiredTimespan(const std::wstring& name) const
+{
+ auto result = GetTimespan(name);
+ if (!result.has_value())
+ {
+ ThrowRequiredException(name);
+ }
+ return result.value();
+}
+
+void ConfigurationSection::ThrowRequiredException(const std::wstring& name)
+{
+ throw ConfigurationLoadException(format(L"Attribute '%s' is required.", name.c_str()));
+}
+
+std::optional find_element(const std::vector>& pairs, const std::wstring& name)
+{
+ const auto iter = std::find_if(
+ pairs.begin(),
+ pairs.end(),
+ [&](const std::pair& pair) { return equals_ignore_case(pair.first, name); });
+
+ if (iter == pairs.end())
+ {
+ return std::nullopt;
+ }
+
+ return std::make_optional(iter->second);
+}
diff --git a/src/AspNetCoreModuleV2/CommonLib/ConfigurationSection.h b/src/AspNetCoreModuleV2/CommonLib/ConfigurationSection.h
new file mode 100644
index 0000000000..163f50f8e5
--- /dev/null
+++ b/src/AspNetCoreModuleV2/CommonLib/ConfigurationSection.h
@@ -0,0 +1,46 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#pragma once
+
+#include
+#include
+#include
+
+#include "NonCopyable.h"
+
+#define CS_ASPNETCORE_COLLECTION_ITEM_NAME L"name"
+#define CS_ASPNETCORE_COLLECTION_ITEM_VALUE L"value"
+#define CS_ASPNETCORE_ENVIRONMENT_VARIABLES L"environmentVariables"
+#define CS_ASPNETCORE_STDOUT_LOG_FILE L"stdoutLogFile"
+#define CS_ASPNETCORE_STDOUT_LOG_ENABLED L"stdoutLogEnabled"
+#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_HOSTING_MODEL_OUTOFPROCESS L"outofprocess"
+#define CS_ASPNETCORE_HOSTING_MODEL_INPROCESS L"inprocess"
+#define CS_ASPNETCORE_HOSTING_MODEL L"hostingModel"
+#define CS_ASPNETCORE_HANDLER_SETTINGS L"handlerSettings"
+#define CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE L"disableStartUpErrorPage"
+#define CS_ENABLED L"enabled"
+
+class ConfigurationSection: NonCopyable
+{
+public:
+ ConfigurationSection() = default;
+ virtual ~ConfigurationSection() = default;
+ virtual std::optional GetString(const std::wstring& name) const = 0;
+ virtual std::optional GetBool(const std::wstring& name) const = 0;
+ virtual std::optional GetTimespan(const std::wstring& name) const = 0;
+
+ std::wstring GetRequiredString(const std::wstring& name) const;
+ bool GetRequiredBool(const std::wstring& name) const;
+ DWORD GetRequiredTimespan(const std::wstring& name) const;
+
+ virtual std::vector> GetKeyValuePairs(const std::wstring& name) const = 0;
+
+protected:
+ static void ThrowRequiredException(const std::wstring& name);
+};
+
+std::optional find_element(const std::vector>& pairs, const std::wstring& name);
diff --git a/src/AspNetCoreModuleV2/CommonLib/ConfigurationSource.cpp b/src/AspNetCoreModuleV2/CommonLib/ConfigurationSource.cpp
new file mode 100644
index 0000000000..558d054659
--- /dev/null
+++ b/src/AspNetCoreModuleV2/CommonLib/ConfigurationSource.cpp
@@ -0,0 +1,18 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "ConfigurationSource.h"
+
+#include "StringHelpers.h"
+#include "ConfigurationLoadException.h"
+
+std::shared_ptr ConfigurationSource::GetRequiredSection(const std::wstring& name) const
+{
+ auto section = GetSection(name);
+ if (!section)
+ {
+ throw ConfigurationLoadException(format(L"Unable to get required configuration section '%s'. Possible reason is web.config authoring error.", name.c_str()));
+ }
+ return section;
+}
+
diff --git a/src/AspNetCoreModuleV2/CommonLib/ConfigurationSource.h b/src/AspNetCoreModuleV2/CommonLib/ConfigurationSource.h
new file mode 100644
index 0000000000..53ab5a5218
--- /dev/null
+++ b/src/AspNetCoreModuleV2/CommonLib/ConfigurationSource.h
@@ -0,0 +1,24 @@
+// 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
+#include
+#include
+#include "NonCopyable.h"
+#include "ConfigurationSection.h"
+
+#define CS_ASPNETCORE_SECTION L"system.webServer/aspNetCore"
+#define CS_WINDOWS_AUTHENTICATION_SECTION L"system.webServer/security/authentication/windowsAuthentication"
+#define CS_BASIC_AUTHENTICATION_SECTION L"system.webServer/security/authentication/basicAuthentication"
+#define CS_ANONYMOUS_AUTHENTICATION_SECTION L"system.webServer/security/authentication/anonymousAuthentication"
+
+class ConfigurationSource: NonCopyable
+{
+public:
+ ConfigurationSource() = default;
+ virtual ~ConfigurationSource() = default;
+ virtual std::shared_ptr GetSection(const std::wstring& name) const = 0;
+ std::shared_ptr GetRequiredSection(const std::wstring& name) const;
+};
diff --git a/src/AspNetCoreModuleV2/CommonLib/NonCopyable.h b/src/AspNetCoreModuleV2/CommonLib/NonCopyable.h
new file mode 100644
index 0000000000..8dcb282411
--- /dev/null
+++ b/src/AspNetCoreModuleV2/CommonLib/NonCopyable.h
@@ -0,0 +1,11 @@
+// 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 NonCopyable {
+public:
+ NonCopyable() = default;
+ NonCopyable(const NonCopyable&) = default;
+ NonCopyable& operator=(const NonCopyable&) = default;
+};
diff --git a/src/AspNetCoreModuleV2/CommonLib/StringHelpers.cpp b/src/AspNetCoreModuleV2/CommonLib/StringHelpers.cpp
index 8e574677cd..5e251f69ed 100644
--- a/src/AspNetCoreModuleV2/CommonLib/StringHelpers.cpp
+++ b/src/AspNetCoreModuleV2/CommonLib/StringHelpers.cpp
@@ -13,3 +13,8 @@ bool ends_with(const std::wstring &source, const std::wstring &suffix, bool igno
const auto offset = source.length() - suffix.length();
return CSTR_EQUAL == CompareStringOrdinal(source.c_str() + offset, static_cast(suffix.length()), suffix.c_str(), static_cast(suffix.length()), ignoreCase);
}
+
+bool equals_ignore_case(const std::wstring& s1, const std::wstring& s2)
+{
+ return CSTR_EQUAL == CompareStringOrdinal(s1.c_str(), static_cast(s1.length()), s2.c_str(), static_cast(s2.length()), true);
+}
diff --git a/src/AspNetCoreModuleV2/CommonLib/StringHelpers.h b/src/AspNetCoreModuleV2/CommonLib/StringHelpers.h
index 4999bec7a7..957f5bc3d6 100644
--- a/src/AspNetCoreModuleV2/CommonLib/StringHelpers.h
+++ b/src/AspNetCoreModuleV2/CommonLib/StringHelpers.h
@@ -8,6 +8,9 @@
[[nodiscard]]
bool ends_with(const std::wstring &source, const std::wstring &suffix, bool ignoreCase = false);
+[[nodiscard]]
+bool equals_ignore_case(const std::wstring& s1, const std::wstring& s2);
+
template
[[nodiscard]]
std::wstring format(const std::wstring& format, Args ... args)
@@ -18,3 +21,13 @@ std::wstring format(const std::wstring& format, Args ... args)
return std::wstring(formattedBuffer.get(), formattedBuffer.get() + size - 1);
}
+template
+[[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 formattedBuffer(new char[size]);
+ snprintf(formattedBuffer.get(), size, format.c_str(), args ... );
+ return std::string(formattedBuffer.get(), formattedBuffer.get() + size - 1);
+}
+
diff --git a/src/AspNetCoreModuleV2/CommonLib/WebConfigConfigurationSection.cpp b/src/AspNetCoreModuleV2/CommonLib/WebConfigConfigurationSection.cpp
new file mode 100644
index 0000000000..aa2495359b
--- /dev/null
+++ b/src/AspNetCoreModuleV2/CommonLib/WebConfigConfigurationSection.cpp
@@ -0,0 +1,81 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "WebConfigConfigurationSection.h"
+
+#include "exceptions.h"
+#include "ahutil.h"
+
+std::optional WebConfigConfigurationSection::GetString(const std::wstring& name) const
+{
+ CComBSTR result;
+ if (FAILED_LOG(GetElementStringProperty(m_element, name.c_str(), &result.m_str)))
+ {
+ return std::nullopt;
+ }
+
+ return std::make_optional(std::wstring(result));
+}
+
+std::optional WebConfigConfigurationSection::GetBool(const std::wstring& name) const
+{
+ bool result;
+ if (FAILED_LOG(GetElementBoolProperty(m_element, name.c_str(), &result)))
+ {
+ return std::nullopt;
+ }
+
+ return std::make_optional(result);
+}
+
+std::optional WebConfigConfigurationSection::GetTimespan(const std::wstring& name) const
+{
+ ULONGLONG result;
+ if (FAILED_LOG(GetElementRawTimeSpanProperty(m_element, name.c_str(), &result)))
+ {
+ return std::nullopt;
+ }
+
+ return std::make_optional(static_cast(result / 10000ull));
+}
+
+std::vector> WebConfigConfigurationSection::GetKeyValuePairs(const std::wstring& name) const
+{
+ std::vector> pairs;
+ HRESULT findElementResult;
+ CComPtr element = nullptr;
+ CComPtr elementCollection = nullptr;
+ CComPtr collectionEntry = nullptr;
+ ENUM_INDEX index{};
+
+ if (FAILED_LOG(GetElementChildByName(m_element, name.c_str(), &element)))
+ {
+ return pairs;
+ }
+
+ THROW_IF_FAILED(element->get_Collection(&elementCollection));
+ THROW_IF_FAILED(findElementResult = FindFirstElement(elementCollection, &index, &collectionEntry));
+
+ while (findElementResult != S_FALSE)
+ {
+ CComBSTR strHandlerName;
+ if (LOG_IF_FAILED(GetElementStringProperty(collectionEntry, CS_ASPNETCORE_COLLECTION_ITEM_NAME, &strHandlerName.m_str)))
+ {
+ ThrowRequiredException(CS_ASPNETCORE_COLLECTION_ITEM_NAME);
+ }
+
+ CComBSTR strHandlerValue;
+ if (LOG_IF_FAILED(GetElementStringProperty(collectionEntry, CS_ASPNETCORE_COLLECTION_ITEM_VALUE, &strHandlerValue.m_str)))
+ {
+ ThrowRequiredException(CS_ASPNETCORE_COLLECTION_ITEM_VALUE);
+ }
+
+ pairs.emplace_back(strHandlerName, strHandlerValue);
+
+ collectionEntry.Release();
+
+ THROW_IF_FAILED(findElementResult = FindNextElement(elementCollection, &index, &collectionEntry));
+ }
+
+ return pairs;
+}
diff --git a/src/AspNetCoreModuleV2/CommonLib/WebConfigConfigurationSection.h b/src/AspNetCoreModuleV2/CommonLib/WebConfigConfigurationSection.h
new file mode 100644
index 0000000000..c2f87a9cfe
--- /dev/null
+++ b/src/AspNetCoreModuleV2/CommonLib/WebConfigConfigurationSection.h
@@ -0,0 +1,25 @@
+// 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
+#include
+#include "ConfigurationSection.h"
+
+class WebConfigConfigurationSection: public ConfigurationSection
+{
+public:
+ WebConfigConfigurationSection(IAppHostElement* pElement)
+ : m_element(pElement)
+ {
+ }
+
+ std::optional GetString(const std::wstring& name) const override;
+ std::optional GetBool(const std::wstring& name) const override;
+ std::optional GetTimespan(const std::wstring& name) const override;
+ std::vector> GetKeyValuePairs(const std::wstring& name) const override;
+
+private:
+ CComPtr m_element;
+};
diff --git a/src/AspNetCoreModuleV2/CommonLib/WebConfigConfigurationSource.cpp b/src/AspNetCoreModuleV2/CommonLib/WebConfigConfigurationSource.cpp
new file mode 100644
index 0000000000..c433913ec7
--- /dev/null
+++ b/src/AspNetCoreModuleV2/CommonLib/WebConfigConfigurationSource.cpp
@@ -0,0 +1,20 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "WebConfigConfigurationSource.h"
+
+#include "exceptions.h"
+#include "WebConfigConfigurationSection.h"
+
+std::shared_ptr WebConfigConfigurationSource::GetSection(const std::wstring& name) const
+{
+ const CComBSTR bstrAspNetCoreSection = name.c_str();
+ const CComBSTR applicationConfigPath = m_application.GetAppConfigPath();
+
+ IAppHostElement* sectionElement;
+ if (LOG_IF_FAILED(m_manager->GetAdminSection(bstrAspNetCoreSection, applicationConfigPath, §ionElement)))
+ {
+ return nullptr;
+ }
+ return std::make_unique(sectionElement);
+}
diff --git a/src/AspNetCoreModuleV2/CommonLib/WebConfigConfigurationSource.h b/src/AspNetCoreModuleV2/CommonLib/WebConfigConfigurationSource.h
new file mode 100644
index 0000000000..ce8dbcdc50
--- /dev/null
+++ b/src/AspNetCoreModuleV2/CommonLib/WebConfigConfigurationSource.h
@@ -0,0 +1,23 @@
+// 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
+#include "ConfigurationSection.h"
+#include "ConfigurationSource.h"
+
+class WebConfigConfigurationSource: public ConfigurationSource
+{
+public:
+ WebConfigConfigurationSource(IAppHostAdminManager *pAdminManager, IHttpApplication &pHttpApplication)
+ : m_manager(pAdminManager),
+ m_application(pHttpApplication)
+ {
+ }
+
+ std::shared_ptr GetSection(const std::wstring& name) const override;
+
+private:
+ CComPtr m_manager;
+ IHttpApplication &m_application;
+};
diff --git a/src/AspNetCoreModuleV2/CommonLib/application.h b/src/AspNetCoreModuleV2/CommonLib/application.h
index 9c02484b1a..5e87e4ddf8 100644
--- a/src/AspNetCoreModuleV2/CommonLib/application.h
+++ b/src/AspNetCoreModuleV2/CommonLib/application.h
@@ -3,6 +3,7 @@
#pragma once
+#include
#include "iapplication.h"
#include "ntassert.h"
#include "SRWExclusiveLock.h"
@@ -20,11 +21,15 @@ public:
return m_fStopCalled ? APPLICATION_STATUS::RECYCLED : APPLICATION_STATUS::RUNNING;
}
- APPLICATION()
+ APPLICATION(const IHttpApplication& pHttpApplication)
: m_fStopCalled(false),
- m_cRefs(1)
+ m_cRefs(1),
+ m_applicationPhysicalPath(pHttpApplication.GetApplicationPhysicalPath()),
+ m_applicationConfigPath(pHttpApplication.GetAppConfigPath()),
+ m_applicationId(pHttpApplication.GetApplicationId())
{
InitializeSRWLock(&m_stateLock);
+ m_applicationVirtualPath = ToVirtualPath(m_applicationConfigPath);
}
@@ -69,10 +74,58 @@ public:
}
}
+ const std::wstring&
+ QueryApplicationId() const
+ {
+ return m_applicationId;
+ }
+
+ const std::wstring&
+ QueryApplicationPhysicalPath() const
+ {
+ return m_applicationPhysicalPath;
+ }
+
+ const std::wstring&
+ QueryApplicationVirtualPath() const
+ {
+ return m_applicationVirtualPath;
+ }
+
+ const std::wstring&
+ QueryConfigPath() const
+ {
+ return m_applicationConfigPath;
+ }
+
protected:
- SRWLOCK m_stateLock;
+ SRWLOCK m_stateLock {};
bool m_fStopCalled;
private:
mutable LONG m_cRefs;
+
+ std::wstring m_applicationPhysicalPath;
+ std::wstring m_applicationVirtualPath;
+ std::wstring m_applicationConfigPath;
+ std::wstring m_applicationId;
+
+ static std::wstring ToVirtualPath(const std::wstring& configurationPath)
+ {
+ auto segments = 0;
+ auto position = configurationPath.find('/');
+ // Skip first 4 segments of config path
+ while (segments != 3 && position != std::wstring::npos)
+ {
+ segments++;
+ position = configurationPath.find('/', position + 1);
+ }
+
+ if (position != std::wstring::npos)
+ {
+ return configurationPath.substr(position);
+ }
+
+ return L"/";
+ }
};
diff --git a/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc b/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc
index f0e3d66de3..7289b85ce6 100644
--- a/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc
+++ b/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc
@@ -190,7 +190,7 @@ Language=English
.
Messageid=1034
-SymbolicName=ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR
+SymbolicName=ASPNETCORE_CONFIGURATION_LOAD_ERROR
Language=English
%1
.
diff --git a/src/AspNetCoreModuleV2/CommonLib/exceptions.h b/src/AspNetCoreModuleV2/CommonLib/exceptions.h
index 31873bc743..8d9a50ded3 100644
--- a/src/AspNetCoreModuleV2/CommonLib/exceptions.h
+++ b/src/AspNetCoreModuleV2/CommonLib/exceptions.h
@@ -6,6 +6,7 @@
#include
#include "debugutil.h"
+#include "StringHelpers.h"
#define LOCATION_INFO_ENABLED TRUE
@@ -26,10 +27,11 @@
#endif
#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 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_CAUGHT_EXCEPTION() return CaughtExceptionHResult(LOCATION_INFO);
#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)
@@ -39,6 +41,11 @@
#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(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 THROW_IF_NULL_ALLOC(ptr) Throw_IfNullAlloc(ptr)
#define CATCH_RETURN() catch (...) { RETURN_CAUGHT_EXCEPTION(); }
@@ -48,6 +55,22 @@
#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) :
+ runtime_error(format("HRESULT 0x%x returned at " LOCATION_FORMAT, hr, LOCATION_CALL_ONLY)),
+ m_hr(hr)
+ {
+ }
+
+ HRESULT GetResult() const { return m_hr; }
+
+private:
+ HRESULT m_hr;
+};
+
__declspec(noinline) inline VOID ReportUntypedException(LOCATION_ARGUMENTS_ONLY)
{
DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR, LOCATION_FORMAT "Unhandled non-standard exception", LOCATION_CALL_ONLY);
@@ -75,7 +98,7 @@
__declspec(noinline) inline VOID ReportException(LOCATION_ARGUMENTS std::exception& exception)
{
- DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR, "Exception : %s caught at" LOCATION_FORMAT, exception.what(), LOCATION_CALL_ONLY);
+ DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR, "Exception '%s' caught at " LOCATION_FORMAT, exception.what(), LOCATION_CALL_ONLY);
}
__declspec(noinline) inline HRESULT LogHResultFailed(LOCATION_ARGUMENTS HRESULT hr)
@@ -97,10 +120,10 @@ __declspec(noinline) inline HRESULT CaughtExceptionHResult(LOCATION_ARGUMENTS_ON
{
return E_OUTOFMEMORY;
}
- catch (std::system_error& exception)
+ catch (ResultException& exception)
{
ReportException(LOCATION_CALL exception);
- return exception.code().value();
+ return exception.GetResult();
}
catch (std::exception& exception)
{
@@ -114,6 +137,13 @@ __declspec(noinline) inline HRESULT CaughtExceptionHResult(LOCATION_ARGUMENTS_ON
}
}
+[[noreturn]]
+ __declspec(noinline) inline void ThrowResultException(LOCATION_ARGUMENTS HRESULT hr)
+{
+ DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR, "Throwing ResultException for HRESULT 0x%x at " LOCATION_FORMAT, hr, LOCATION_CALL_ONLY);
+ throw ResultException(hr, LOCATION_CALL_ONLY);
+}
+
template auto Throw_IfNullAlloc(PointerT pointer)
{
if (pointer == nullptr)
diff --git a/src/AspNetCoreModuleV2/CommonLib/resources.h b/src/AspNetCoreModuleV2/CommonLib/resources.h
index b2ea6f5b85..c9cca2b8b6 100644
--- a/src/AspNetCoreModuleV2/CommonLib/resources.h
+++ b/src/AspNetCoreModuleV2/CommonLib/resources.h
@@ -28,7 +28,7 @@
#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_EVENT_UNKNOWN_HOSTING_MODEL_ERROR_MSG L"Unknown hosting model '%s'. Please specify either hostingModel=\"inprocess\" or hostingModel=\"outofprocess\" in the web.config file."
+#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."
diff --git a/src/AspNetCoreModuleV2/IISLib/ahutil.h b/src/AspNetCoreModuleV2/IISLib/ahutil.h
index 3632650aa4..d17dc7be30 100644
--- a/src/AspNetCoreModuleV2/IISLib/ahutil.h
+++ b/src/AspNetCoreModuleV2/IISLib/ahutil.h
@@ -2,6 +2,7 @@
// Licensed under the MIT License. See License.txt in the project root for license information.
#pragma once
+#include "stringu.h"
#include
HRESULT
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.cpp b/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.cpp
new file mode 100644
index 0000000000..6b26b3dcc9
--- /dev/null
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.cpp
@@ -0,0 +1,30 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "InProcessOptions.h"
+
+InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSource) :
+ m_fStdoutLogEnabled(false),
+ m_fWindowsAuthEnabled(false),
+ m_fBasicAuthEnabled(false),
+ m_fAnonymousAuthEnabled(false),
+ m_dwStartupTimeLimitInMS(INFINITE),
+ m_dwShutdownTimeLimitInMS(INFINITE)
+{
+ auto const aspNetCoreSection = configurationSource.GetRequiredSection(CS_ASPNETCORE_SECTION);
+ m_strArguments = aspNetCoreSection->GetString(CS_ASPNETCORE_PROCESS_ARGUMENTS).value_or(CS_ASPNETCORE_PROCESS_ARGUMENTS_DEFAULT);
+ m_strProcessPath = aspNetCoreSection->GetRequiredString(CS_ASPNETCORE_PROCESS_EXE_PATH);
+ m_fStdoutLogEnabled = aspNetCoreSection->GetRequiredBool(CS_ASPNETCORE_STDOUT_LOG_ENABLED);
+ 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);
+
+ const auto basicAuthSection = configurationSource.GetSection(CS_BASIC_AUTHENTICATION_SECTION);
+ m_fBasicAuthEnabled = basicAuthSection && basicAuthSection->GetBool(CS_ENABLED).value_or(false);
+
+ const auto windowsAuthSection = configurationSource.GetSection(CS_WINDOWS_AUTHENTICATION_SECTION);
+ m_fWindowsAuthEnabled = windowsAuthSection && windowsAuthSection->GetBool(CS_ENABLED).value_or(false);
+
+ const auto anonAuthSection = configurationSource.GetSection(CS_ANONYMOUS_AUTHENTICATION_SECTION);
+ m_fAnonymousAuthEnabled = anonAuthSection && anonAuthSection->GetBool(CS_ENABLED).value_or(false);
+}
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.h b/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.h
new file mode 100644
index 0000000000..c0509b3003
--- /dev/null
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.h
@@ -0,0 +1,95 @@
+// 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
+#include "ConfigurationSource.h"
+
+class InProcessOptions: NonCopyable
+{
+public:
+ const std::wstring&
+ QueryProcessPath() const
+ {
+ return m_strProcessPath;
+ }
+
+ const std::wstring&
+ QueryArguments() const
+ {
+ return m_strArguments;
+ }
+
+ bool
+ QueryStdoutLogEnabled() const
+ {
+ return m_fStdoutLogEnabled;
+ }
+
+ const std::wstring&
+ QueryStdoutLogFile() const
+ {
+ return m_struStdoutLogFile;
+ }
+
+ bool
+ QueryDisableStartUpErrorPage() const
+ {
+ return m_fDisableStartUpErrorPage;
+ }
+
+ bool
+ QueryWindowsAuthEnabled() const
+ {
+ return m_fWindowsAuthEnabled;
+ }
+
+ bool
+ QueryBasicAuthEnabled() const
+ {
+ return m_fBasicAuthEnabled;
+ }
+
+ bool
+ QueryAnonymousAuthEnabled() const
+ {
+ return m_fAnonymousAuthEnabled;
+ }
+
+ DWORD
+ QueryStartupTimeLimitInMS() const
+ {
+ return m_dwStartupTimeLimitInMS;
+ }
+
+ DWORD
+ QueryShutdownTimeLimitInMS() const
+ {
+ return m_dwShutdownTimeLimitInMS;
+ }
+
+ const std::vector>&
+ QueryEnvironmentVariables() const
+ {
+ return m_environmentVariables;
+ }
+
+ InProcessOptions(const ConfigurationSource &configurationSource);
+
+private:
+ std::wstring m_strArguments;
+ std::wstring m_strProcessPath;
+ std::wstring m_struStdoutLogFile;
+ bool m_fStdoutLogEnabled;
+ bool m_fDisableStartUpErrorPage;
+ bool m_fWindowsAuthEnabled;
+ bool m_fBasicAuthEnabled;
+ bool m_fAnonymousAuthEnabled;
+ DWORD m_dwStartupTimeLimitInMS;
+ DWORD m_dwShutdownTimeLimitInMS;
+ std::vector> m_environmentVariables;
+
+protected:
+ InProcessOptions() = default;
+};
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRequestHandler.vcxproj b/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRequestHandler.vcxproj
index 08e3b32bd3..f295280e4e 100644
--- a/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRequestHandler.vcxproj
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRequestHandler.vcxproj
@@ -228,6 +228,7 @@
+
@@ -238,6 +239,7 @@
+
Create
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cpp b/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cpp
index 2a0369206b..90779ce6d8 100644
--- a/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cpp
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cpp
@@ -13,6 +13,10 @@
#include "resources.h"
#include "exceptions.h"
#include "ShuttingDownApplication.h"
+#include "InProcessOptions.h"
+#include "EventLog.h"
+#include "WebConfigConfigurationSource.h"
+#include "ConfigurationLoadException.h"
DECLARE_DEBUG_PRINT_OBJECT("aspnetcorev2_inprocess.dll");
@@ -106,13 +110,12 @@ CreateApplication(
return S_OK;
}
- REQUESTHANDLER_CONFIG *pConfig = nullptr;
- RETURN_IF_FAILED(REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(pServer, pHttpApplication, &pConfig));
- std::unique_ptr pRequestHandlerConfig(pConfig);
+ const WebConfigConfigurationSource configurationSource(pServer->GetAdminManager(), *pHttpApplication);
+ auto pConfig = std::make_unique(configurationSource);
BOOL disableStartupPage = pConfig->QueryDisableStartUpErrorPage();
- auto pApplication = std::make_unique(*pServer, *pHttpApplication, std::move(pRequestHandlerConfig), pParameters, nParameters);
+ auto pApplication = std::make_unique(*pServer, *pHttpApplication, std::move(pConfig), pParameters, nParameters);
// never create two inprocess applications in one process
g_fInProcessApplicationCreated = true;
@@ -130,6 +133,15 @@ CreateApplication(
*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);
+ }
CATCH_RETURN();
return S_OK;
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp
index 182ee53148..0a07ccc616 100644
--- a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp
@@ -19,7 +19,7 @@ IN_PROCESS_APPLICATION* IN_PROCESS_APPLICATION::s_Application = NULL;
IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION(
IHttpServer& pHttpServer,
IHttpApplication& pApplication,
- std::unique_ptr pConfig,
+ std::unique_ptr pConfig,
APPLICATION_PARAMETER *pParameters,
DWORD nParameters) :
InProcessApplicationBase(pHttpServer, pApplication),
@@ -108,14 +108,14 @@ Finished:
EventLog::Warn(
ASPNETCORE_EVENT_GRACEFUL_SHUTDOWN_FAILURE,
ASPNETCORE_EVENT_APP_SHUTDOWN_FAILURE_MSG,
- m_pConfig->QueryConfigPath()->QueryStr());
+ QueryConfigPath().c_str());
}
else
{
EventLog::Info(
ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL,
ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL_MSG,
- m_pConfig->QueryConfigPath()->QueryStr());
+ QueryConfigPath().c_str());
}
InProcessApplicationBase::StopInternal(fServerInitiated);
@@ -212,7 +212,7 @@ IN_PROCESS_APPLICATION::SetCallbackHandles(
EventLog::Info(
ASPNETCORE_EVENT_INPROCESS_START_SUCCESS,
ASPNETCORE_EVENT_INPROCESS_START_SUCCESS_MSG,
- m_pConfig->QueryApplicationPhysicalPath()->QueryStr());
+ QueryApplicationPhysicalPath().c_str());
SetEvent(m_pInitalizeEvent);
m_fInitialized = TRUE;
}
@@ -334,8 +334,8 @@ Finished:
EventLog::Error(
ASPNETCORE_EVENT_LOAD_CLR_FALIURE,
ASPNETCORE_EVENT_LOAD_CLR_FALIURE_MSG,
- m_pConfig->QueryApplicationPath()->QueryStr(),
- m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
+ QueryApplicationId().c_str(),
+ QueryApplicationPhysicalPath().c_str(),
hr);
}
DereferenceApplication();
@@ -365,11 +365,21 @@ IN_PROCESS_APPLICATION::SetEnvironementVariablesOnWorkerProcess(
VOID
)
{
- HRESULT hr = S_OK;
+ auto variables = m_pConfig->QueryEnvironmentVariables();
+ auto inputTable = std::unique_ptr(new ENVIRONMENT_VAR_HASH());
+ RETURN_IF_FAILED(inputTable->Initialize(37 /*prime*/));
+ // Copy environment variables to old style hash table
+ for (auto & variable : variables)
+ {
+ auto pNewEntry = std::unique_ptr(new ENVIRONMENT_VAR_ENTRY());
+ RETURN_IF_FAILED(pNewEntry->Initialize((variable.first + L"=").c_str(), variable.second.c_str()));
+ RETURN_IF_FAILED(inputTable->InsertRecord(pNewEntry.get()));
+ }
+
ENVIRONMENT_VAR_HASH* pHashTable = NULL;
std::unique_ptr table;
- RETURN_IF_FAILED(hr = ENVIRONMENT_VAR_HELPERS::InitEnvironmentVariablesTable(
- m_pConfig->QueryEnvironmentVariables(),
+ RETURN_IF_FAILED(ENVIRONMENT_VAR_HELPERS::InitEnvironmentVariablesTable(
+ inputTable.get(),
m_pConfig->QueryWindowsAuthEnabled(),
m_pConfig->QueryBasicAuthEnabled(),
m_pConfig->QueryAnonymousAuthEnabled(),
@@ -377,11 +387,13 @@ IN_PROCESS_APPLICATION::SetEnvironementVariablesOnWorkerProcess(
table.reset(pHashTable);
+ HRESULT hr = S_OK;
table->Apply(ENVIRONMENT_VAR_HELPERS::AppendEnvironmentVariables, &hr);
RETURN_IF_FAILED(hr);
table->Apply(ENVIRONMENT_VAR_HELPERS::SetEnvironmentVariables, &hr);
RETURN_IF_FAILED(hr);
+
return S_OK;
}
@@ -422,9 +434,9 @@ IN_PROCESS_APPLICATION::ExecuteApplication(
FINISHED_IF_FAILED(hr = HOSTFXR_OPTIONS::Create(
m_struExeLocation.QueryStr(),
- m_pConfig->QueryProcessPath()->QueryStr(),
- m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
- m_pConfig->QueryArguments()->QueryStr(),
+ m_pConfig->QueryProcessPath().c_str(),
+ QueryApplicationPhysicalPath().c_str(),
+ m_pConfig->QueryArguments().c_str(),
hostFxrOptions
));
hostFxrOptions->GetArguments(hostfxrArgc, hostfxrArgv);
@@ -438,8 +450,8 @@ IN_PROCESS_APPLICATION::ExecuteApplication(
FINISHED_IF_FAILED(hr = LoggingHelpers::CreateLoggingProvider(
m_pConfig->QueryStdoutLogEnabled(),
!m_pHttpServer.IsCommandLineLaunch(),
- m_pConfig->QueryStdoutLogFile()->QueryStr(),
- m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
+ m_pConfig->QueryStdoutLogFile().c_str(),
+ QueryApplicationPhysicalPath().c_str(),
m_pLoggerProvider));
LOG_IF_FAILED(m_pLoggerProvider->Start());
@@ -502,8 +514,8 @@ IN_PROCESS_APPLICATION::LogErrorsOnMainExit(
EventLog::Error(
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT,
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT_MSG,
- m_pConfig->QueryApplicationPath()->QueryStr(),
- m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
+ QueryApplicationId().c_str(),
+ QueryApplicationPhysicalPath().c_str(),
hr,
struStdMsg.QueryStr());
}
@@ -513,8 +525,8 @@ IN_PROCESS_APPLICATION::LogErrorsOnMainExit(
EventLog::Error(
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT,
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_MSG,
- m_pConfig->QueryApplicationPath()->QueryStr(),
- m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
+ QueryApplicationId().c_str(),
+ QueryApplicationPhysicalPath().c_str(),
hr);
}
}
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.h b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.h
index 1d5cfec4c9..7183ad86b3 100644
--- a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.h
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.h
@@ -4,8 +4,8 @@
#pragma once
#include "InProcessApplicationBase.h"
-#include "requesthandler_config.h"
#include "IOutputManager.h"
+#include "InProcessOptions.h"
class IN_PROCESS_HANDLER;
typedef REQUEST_NOTIFICATION_STATUS(WINAPI * PFN_REQUEST_HANDLER) (IN_PROCESS_HANDLER* pInProcessHandler, void* pvRequestHandlerContext);
@@ -18,7 +18,7 @@ public:
IN_PROCESS_APPLICATION(
IHttpServer& pHttpServer,
IHttpApplication& pApplication,
- std::unique_ptr pConfig,
+ std::unique_ptr pConfig,
APPLICATION_PARAMETER *pParameters,
DWORD nParameters);
@@ -97,10 +97,10 @@ public:
return m_struExeLocation.QueryStr();
}
- REQUESTHANDLER_CONFIG*
- QueryConfig()
+ const InProcessOptions&
+ QueryConfig() const
{
- return m_pConfig.get();
+ return *m_pConfig.get();
}
bool
@@ -146,7 +146,7 @@ private:
volatile BOOL m_fShutdownCalledFromManaged;
BOOL m_fInitialized;
MANAGED_APPLICATION_STATUS m_status;
- std::unique_ptr m_pConfig;
+ std::unique_ptr m_pConfig;
static IN_PROCESS_APPLICATION* s_Application;
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp b/src/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp
index af0035be11..d8d28e5a28 100644
--- a/src/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp
@@ -187,11 +187,11 @@ http_get_application_properties(
auto pConfiguration = pInProcessApplication->QueryConfig();
pIISCofigurationData->pInProcessApplication = pInProcessApplication;
- pIISCofigurationData->pwzFullApplicationPath = SysAllocString(pConfiguration->QueryApplicationPhysicalPath()->QueryStr());
- pIISCofigurationData->pwzVirtualApplicationPath = SysAllocString(pConfiguration->QueryApplicationVirtualPath()->QueryStr());
- pIISCofigurationData->fWindowsAuthEnabled = pConfiguration->QueryWindowsAuthEnabled();
- pIISCofigurationData->fBasicAuthEnabled = pConfiguration->QueryBasicAuthEnabled();
- pIISCofigurationData->fAnonymousAuthEnable = pConfiguration->QueryAnonymousAuthEnabled();
+ pIISCofigurationData->pwzFullApplicationPath = SysAllocString(pInProcessApplication->QueryApplicationPhysicalPath().c_str());
+ pIISCofigurationData->pwzVirtualApplicationPath = SysAllocString(pInProcessApplication->QueryApplicationVirtualPath().c_str());
+ pIISCofigurationData->fWindowsAuthEnabled = pConfiguration.QueryWindowsAuthEnabled();
+ pIISCofigurationData->fBasicAuthEnabled = pConfiguration.QueryBasicAuthEnabled();
+ pIISCofigurationData->fAnonymousAuthEnable = pConfiguration.QueryAnonymousAuthEnabled();
return S_OK;
}
diff --git a/src/AspNetCoreModuleV2/RequestHandlerLib/AppOfflineTrackingApplication.h b/src/AspNetCoreModuleV2/RequestHandlerLib/AppOfflineTrackingApplication.h
index f2ce7a5c20..b504a730fd 100644
--- a/src/AspNetCoreModuleV2/RequestHandlerLib/AppOfflineTrackingApplication.h
+++ b/src/AspNetCoreModuleV2/RequestHandlerLib/AppOfflineTrackingApplication.h
@@ -12,7 +12,7 @@ class AppOfflineTrackingApplication: public APPLICATION
{
public:
AppOfflineTrackingApplication(const IHttpApplication& application)
- : APPLICATION(),
+ : APPLICATION(application),
m_applicationPath(application.GetApplicationPhysicalPath()),
m_fileWatcher(nullptr),
m_fAppOfflineProcessed(false)
diff --git a/src/AspNetCoreModuleV2/RequestHandlerLib/environmentvariablehash.h b/src/AspNetCoreModuleV2/RequestHandlerLib/environmentvariablehash.h
index 98bcd5ada4..c5f63f6fde 100644
--- a/src/AspNetCoreModuleV2/RequestHandlerLib/environmentvariablehash.h
+++ b/src/AspNetCoreModuleV2/RequestHandlerLib/environmentvariablehash.h
@@ -33,13 +33,13 @@ public:
{
HRESULT hr = S_OK;
if (FAILED(hr = _strName.Copy(pszName)) ||
- FAILED(hr = _strValue.Copy(pszValue)))
+ FAILED(hr = _strValue.Copy(pszValue)))
{
}
- return hr;
+ return hr;
}
- VOID
+ VOID
Reference() const
{
InterlockedIncrement(&_cRefs);
@@ -139,3 +139,11 @@ struct ENVIRONMENT_VAR_HASH_DELETER
delete hashTable;
}
};
+
+struct ENVIRONMENT_VAR_ENTRY_DELETER
+{
+ void operator ()(ENVIRONMENT_VAR_ENTRY* entry) const
+ {
+ entry->Dereference();
+ }
+};
diff --git a/test/Common.FunctionalTests/Inprocess/EnvironmentVariableTests.cs b/test/Common.FunctionalTests/Inprocess/EnvironmentVariableTests.cs
index 413aa4c35f..ae8fde39ed 100644
--- a/test/Common.FunctionalTests/Inprocess/EnvironmentVariableTests.cs
+++ b/test/Common.FunctionalTests/Inprocess/EnvironmentVariableTests.cs
@@ -8,11 +8,11 @@ using Xunit;
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
{
[Collection(IISTestSiteCollection.Name)]
- public class EnvironmentVariableTests
+ public class EnvironmentVariableTests: FixtureLoggedTest
{
private readonly IISTestSiteFixture _fixture;
- public EnvironmentVariableTests(IISTestSiteFixture fixture)
+ public EnvironmentVariableTests(IISTestSiteFixture fixture): base(fixture)
{
_fixture = fixture;
}
diff --git a/test/Common.FunctionalTests/Utilities/Helpers.cs b/test/Common.FunctionalTests/Utilities/Helpers.cs
index d0b1ebc109..34fb88082a 100644
--- a/test/Common.FunctionalTests/Utilities/Helpers.cs
+++ b/test/Common.FunctionalTests/Utilities/Helpers.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Xml.Linq;
@@ -133,5 +134,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
await verificationAction();
}
}
+
+ public static IEnumerable