Fix ANCM environment variables bugs (#6083)
This commit is contained in:
parent
a25c7d95e3
commit
a7b783724e
|
|
@ -37,7 +37,7 @@ jobs:
|
|||
- template: jobs/iisintegration-job.yml
|
||||
parameters:
|
||||
TestGroupName: IISExpress
|
||||
skipArgs: "/p:SkipIISBackwardsCompatibilityTests=false /p:SkipIISTests=true /p:SkipIISExpressTests=false /p:SkipIISForwardsCompatibilityTests=true"
|
||||
skipArgs: "/p:SkipIISBackwardsCompatibilityTests=true /p:SkipIISTests=true /p:SkipIISExpressTests=false /p:SkipIISForwardsCompatibilityTests=true"
|
||||
- template: jobs/iisintegration-job.yml
|
||||
parameters:
|
||||
TestGroupName: IISForwardCompat
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "StringHelpers.h"
|
||||
#include "ConfigurationLoadException.h"
|
||||
#include <map>
|
||||
|
||||
std::wstring ConfigurationSection::GetRequiredString(const std::wstring& name) const
|
||||
{
|
||||
|
|
@ -63,6 +64,17 @@ std::vector<std::pair<std::wstring, std::wstring>> ConfigurationSection::GetKeyV
|
|||
return pairs;
|
||||
}
|
||||
|
||||
std::map<std::wstring, std::wstring, ignore_case_comparer> ConfigurationSection::GetMap(const std::wstring& name) const
|
||||
{
|
||||
std::map<std::wstring, std::wstring, ignore_case_comparer> pairs;
|
||||
|
||||
for (auto const element : GetRequiredSection(name)->GetCollection())
|
||||
{
|
||||
pairs.insert_or_assign(element->GetRequiredString(CS_ASPNETCORE_COLLECTION_ITEM_NAME), element->GetString(CS_ASPNETCORE_COLLECTION_ITEM_VALUE).value_or(L""));
|
||||
}
|
||||
return pairs;
|
||||
}
|
||||
|
||||
std::shared_ptr<ConfigurationSection> ConfigurationSection::GetRequiredSection(const std::wstring& name) const
|
||||
{
|
||||
auto section = GetSection(name);
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@
|
|||
#include <string>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "NonCopyable.h"
|
||||
#include "StringHelpers.h"
|
||||
|
||||
#define CS_ASPNETCORE_COLLECTION_ITEM_NAME L"name"
|
||||
#define CS_ASPNETCORE_COLLECTION_ITEM_VALUE L"value"
|
||||
|
|
@ -46,6 +48,7 @@ public:
|
|||
DWORD GetRequiredTimespan(const std::wstring& name) const;
|
||||
|
||||
virtual std::vector<std::pair<std::wstring, std::wstring>> GetKeyValuePairs(const std::wstring& name) const;
|
||||
virtual std::map<std::wstring, std::wstring, ignore_case_comparer> GetMap(const std::wstring& name) const;
|
||||
|
||||
virtual std::shared_ptr<ConfigurationSection> GetRequiredSection(const std::wstring & name) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -17,13 +17,18 @@ bool ends_with(const std::wstring &source, const std::wstring &suffix, bool igno
|
|||
|
||||
bool equals_ignore_case(const std::wstring& s1, const std::wstring& s2)
|
||||
{
|
||||
return CSTR_EQUAL == CompareStringOrdinal(s1.c_str(), static_cast<int>(s1.length()), s2.c_str(), static_cast<int>(s2.length()), true);
|
||||
return compare_ignore_case(s1, s2) == 0;
|
||||
}
|
||||
|
||||
int compare_ignore_case(const std::wstring& s1, const std::wstring& s2)
|
||||
{
|
||||
return CompareStringOrdinal(s1.c_str(), static_cast<int>(s1.length()), s2.c_str(), static_cast<int>(s2.length()), true) - CSTR_EQUAL;
|
||||
}
|
||||
|
||||
std::wstring to_wide_string(const std::string &source, const unsigned int codePage)
|
||||
{
|
||||
// MultiByteToWideChar returns 0 on failure, which is also the same return value
|
||||
// for empty strings. Preemptive return.
|
||||
// for empty strings. Preemptive return.
|
||||
if (source.length() == 0)
|
||||
{
|
||||
return L"";
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ bool ends_with(const std::wstring &source, const std::wstring &suffix, bool igno
|
|||
[[nodiscard]]
|
||||
bool equals_ignore_case(const std::wstring& s1, const std::wstring& s2);
|
||||
|
||||
[[nodiscard]]
|
||||
int compare_ignore_case(const std::wstring& s1, const std::wstring& s2);
|
||||
|
||||
[[nodiscard]]
|
||||
std::wstring to_wide_string(const std::string &source, const unsigned int codePage);
|
||||
|
||||
|
|
@ -48,3 +51,9 @@ std::string format(const std::string& format, Args ... args)
|
|||
return result;
|
||||
}
|
||||
|
||||
struct ignore_case_comparer
|
||||
{
|
||||
bool operator() (const std::wstring & s1, const std::wstring & s2) const {
|
||||
return compare_ignore_case(s1, s2) == -1;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -134,6 +134,12 @@ private:
|
|||
return condition;
|
||||
}
|
||||
|
||||
__declspec(noinline) inline VOID ReportException(LOCATION_ARGUMENTS const InvalidOperationException& exception)
|
||||
{
|
||||
TraceException(LOCATION_CALL exception);
|
||||
DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR, "InvalidOperationException '%ls' caught at " LOCATION_FORMAT, exception.as_wstring().c_str(), LOCATION_CALL_ONLY);
|
||||
}
|
||||
|
||||
__declspec(noinline) inline VOID ReportException(LOCATION_ARGUMENTS const std::exception& exception)
|
||||
{
|
||||
TraceException(LOCATION_CALL exception);
|
||||
|
|
@ -165,6 +171,11 @@ __declspec(noinline) inline HRESULT CaughtExceptionHResult(LOCATION_ARGUMENTS_ON
|
|||
ReportException(LOCATION_CALL exception);
|
||||
return exception.GetResult();
|
||||
}
|
||||
catch (const InvalidOperationException& exception)
|
||||
{
|
||||
ReportException(LOCATION_CALL exception);
|
||||
return HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION);
|
||||
}
|
||||
catch (const std::exception& exception)
|
||||
{
|
||||
ReportException(LOCATION_CALL exception);
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSourc
|
|||
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);
|
||||
m_environmentVariables = aspNetCoreSection->GetMap(CS_ASPNETCORE_ENVIRONMENT_VARIABLES);
|
||||
|
||||
const auto handlerSettings = aspNetCoreSection->GetKeyValuePairs(CS_ASPNETCORE_HANDLER_SETTINGS);
|
||||
m_fSetCurrentDirectory = equals_ignore_case(find_element(handlerSettings, CS_ASPNETCORE_HANDLER_SET_CURRENT_DIRECTORY).value_or(L"true"), L"true");
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "BindingInformation.h"
|
||||
#include "ConfigurationSource.h"
|
||||
#include "WebConfigConfigurationSource.h"
|
||||
#include <map>
|
||||
|
||||
class InProcessOptions: NonCopyable
|
||||
{
|
||||
|
|
@ -87,7 +88,7 @@ public:
|
|||
return m_dwShutdownTimeLimitInMS;
|
||||
}
|
||||
|
||||
const std::vector<std::pair<std::wstring, std::wstring>>&
|
||||
const std::map<std::wstring, std::wstring, ignore_case_comparer>&
|
||||
QueryEnvironmentVariables() const
|
||||
{
|
||||
return m_environmentVariables;
|
||||
|
|
@ -120,7 +121,7 @@ private:
|
|||
bool m_fAnonymousAuthEnabled;
|
||||
DWORD m_dwStartupTimeLimitInMS;
|
||||
DWORD m_dwShutdownTimeLimitInMS;
|
||||
std::vector<std::pair<std::wstring, std::wstring>> m_environmentVariables;
|
||||
std::map<std::wstring, std::wstring, ignore_case_comparer> m_environmentVariables;
|
||||
std::vector<BindingInformation> m_bindingInformation;
|
||||
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -425,37 +425,20 @@ IN_PROCESS_APPLICATION::ClrThreadEntryPoint(const std::shared_ptr<ExecuteClrCont
|
|||
HRESULT
|
||||
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());
|
||||
RETURN_IF_FAILED(inputTable->Initialize(37 /*prime*/));
|
||||
// Copy environment variables to old style hash table
|
||||
for (auto & variable : variables)
|
||||
{
|
||||
auto pNewEntry = std::unique_ptr<ENVIRONMENT_VAR_ENTRY, ENVIRONMENT_VAR_ENTRY_DELETER>(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<ENVIRONMENT_VAR_HASH, ENVIRONMENT_VAR_HASH_DELETER> table;
|
||||
RETURN_IF_FAILED(ENVIRONMENT_VAR_HELPERS::InitEnvironmentVariablesTable(
|
||||
inputTable.get(),
|
||||
auto variables = ENVIRONMENT_VAR_HELPERS::InitEnvironmentVariablesTable(
|
||||
m_pConfig->QueryEnvironmentVariables(),
|
||||
m_pConfig->QueryWindowsAuthEnabled(),
|
||||
m_pConfig->QueryBasicAuthEnabled(),
|
||||
m_pConfig->QueryAnonymousAuthEnabled(),
|
||||
false, // fAddHostingStartup
|
||||
QueryApplicationPhysicalPath().c_str(),
|
||||
nullptr, /* pHttpsPort */
|
||||
&pHashTable));
|
||||
nullptr);
|
||||
|
||||
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);
|
||||
for (const auto & variable : variables)
|
||||
{
|
||||
LOG_INFOF(L"Setting environment variable %ls=%ls", variable.first.c_str(), variable.second.c_str());
|
||||
SetEnvironmentVariable(variable.first.c_str(), variable.second.c_str());
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ SERVER_PROCESS::Initialize(
|
|||
BOOL fWindowsAuthEnabled,
|
||||
BOOL fBasicAuthEnabled,
|
||||
BOOL fAnonymousAuthEnabled,
|
||||
ENVIRONMENT_VAR_HASH *pEnvironmentVariables,
|
||||
std::map<std::wstring, std::wstring, ignore_case_comparer>& pEnvironmentVariables,
|
||||
BOOL fStdoutLogEnabled,
|
||||
BOOL fWebSocketSupported,
|
||||
STRU *pstruStdoutLogFile,
|
||||
|
|
@ -761,6 +761,8 @@ SERVER_PROCESS::StartProcess(
|
|||
ENVIRONMENT_VAR_HASH *pHashTable = NULL;
|
||||
PWSTR pStrStage = NULL;
|
||||
BOOL fCriticalError = FALSE;
|
||||
std::map<std::wstring, std::wstring, ignore_case_comparer> variables;
|
||||
|
||||
GetStartupInfoW(&startupInfo);
|
||||
|
||||
//
|
||||
|
|
@ -782,27 +784,30 @@ SERVER_PROCESS::StartProcess(
|
|||
goto Failure;
|
||||
}
|
||||
|
||||
if (FAILED_LOG(hr = ENVIRONMENT_VAR_HELPERS::InitEnvironmentVariablesTable(
|
||||
m_pEnvironmentVarTable,
|
||||
m_fWindowsAuthEnabled,
|
||||
m_fBasicAuthEnabled,
|
||||
m_fAnonymousAuthEnabled,
|
||||
m_struAppFullPath.QueryStr(),
|
||||
m_struHttpsPort.QueryStr(),
|
||||
&pHashTable)))
|
||||
try
|
||||
{
|
||||
pStrStage = L"InitEnvironmentVariablesTable";
|
||||
goto Failure;
|
||||
variables = ENVIRONMENT_VAR_HELPERS::InitEnvironmentVariablesTable(
|
||||
m_pEnvironmentVarTable,
|
||||
m_fWindowsAuthEnabled,
|
||||
m_fBasicAuthEnabled,
|
||||
m_fAnonymousAuthEnabled,
|
||||
true, // fAddHostingStartup
|
||||
m_struAppFullPath.QueryStr(),
|
||||
m_struHttpsPort.QueryStr());
|
||||
|
||||
variables = ENVIRONMENT_VAR_HELPERS::AddWebsocketEnabledToEnvironmentVariables(variables, m_fWebSocketSupported);
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
if (FAILED_LOG(hr = ENVIRONMENT_VAR_HELPERS::AddWebsocketEnabledToEnvironmentVariables(
|
||||
pHashTable,
|
||||
m_fWebSocketSupported
|
||||
)))
|
||||
|
||||
pHashTable = new ENVIRONMENT_VAR_HASH();
|
||||
RETURN_IF_FAILED(pHashTable->Initialize(37 /*prime*/));
|
||||
// Copy environment variables to old style hash table
|
||||
for (auto & variable : variables)
|
||||
{
|
||||
pStrStage = L"AddWebsocketEnabledToEnvironmentVariables";
|
||||
goto Failure;
|
||||
|
||||
auto pNewEntry = std::unique_ptr<ENVIRONMENT_VAR_ENTRY, ENVIRONMENT_VAR_ENTRY_DELETER>(new ENVIRONMENT_VAR_ENTRY());
|
||||
RETURN_IF_FAILED(pNewEntry->Initialize((variable.first + L"=").c_str(), variable.second.c_str()));
|
||||
RETURN_IF_FAILED(pHashTable->InsertRecord(pNewEntry.get()));
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -1793,7 +1798,6 @@ SERVER_PROCESS::~SERVER_PROCESS()
|
|||
|
||||
CleanUp();
|
||||
|
||||
m_pEnvironmentVarTable = NULL;
|
||||
// no need to free m_pEnvironmentVarTable, as it references to
|
||||
// the same hash table hold by configuration.
|
||||
// the hashtable memory will be freed once onfiguration got recycled
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <random>
|
||||
#include <map>
|
||||
|
||||
#define MIN_PORT 1025
|
||||
#define MAX_PORT 48000
|
||||
|
|
@ -33,7 +34,7 @@ public:
|
|||
_In_ BOOL fWindowsAuthEnabled,
|
||||
_In_ BOOL fBasicAuthEnabled,
|
||||
_In_ BOOL fAnonymousAuthEnabled,
|
||||
_In_ ENVIRONMENT_VAR_HASH* pEnvironmentVariables,
|
||||
_In_ std::map<std::wstring, std::wstring, ignore_case_comparer>& pEnvironmentVariables,
|
||||
_In_ BOOL fStdoutLogEnabled,
|
||||
_In_ BOOL fWebSocketSupported,
|
||||
_In_ STRU *pstruStdoutLogFile,
|
||||
|
|
@ -290,5 +291,5 @@ private:
|
|||
HANDLE m_hChildProcessWaitHandles[MAX_ACTIVE_CHILD_PROCESSES];
|
||||
|
||||
PROCESS_MANAGER *m_pProcessManager;
|
||||
ENVIRONMENT_VAR_HASH *m_pEnvironmentVarTable ;
|
||||
std::map<std::wstring, std::wstring, ignore_case_comparer> m_pEnvironmentVarTable;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,12 +4,11 @@
|
|||
#pragma once
|
||||
|
||||
#define HOSTING_STARTUP_ASSEMBLIES_ENV_STR L"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES"
|
||||
#define HOSTING_STARTUP_ASSEMBLIES_NAME L"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES="
|
||||
#define HOSTING_STARTUP_ASSEMBLIES_VALUE L"Microsoft.AspNetCore.Server.IISIntegration"
|
||||
#define ASPNETCORE_IIS_AUTH_ENV_STR L"ASPNETCORE_IIS_HTTPAUTH="
|
||||
#define ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED_ENV_STR L"ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED="
|
||||
#define ASPNETCORE_IIS_PHYSICAL_PATH_ENV_STR L"ASPNETCORE_IIS_PHYSICAL_PATH="
|
||||
#define ASPNETCORE_HTTPS_PORT_ENV_STR L"ASPNETCORE_HTTPS_PORT="
|
||||
#define ASPNETCORE_IIS_AUTH_ENV_STR L"ASPNETCORE_IIS_HTTPAUTH"
|
||||
#define ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED_ENV_STR L"ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED"
|
||||
#define ASPNETCORE_IIS_PHYSICAL_PATH_ENV_STR L"ASPNETCORE_IIS_PHYSICAL_PATH"
|
||||
#define ASPNETCORE_HTTPS_PORT_ENV_STR L"ASPNETCORE_HTTPS_PORT"
|
||||
#define ASPNETCORE_IIS_AUTH_WINDOWS L"windows;"
|
||||
#define ASPNETCORE_IIS_AUTH_BASIC L"basic;"
|
||||
#define ASPNETCORE_IIS_AUTH_ANONYMOUS L"anonymous;"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include "Environment.h"
|
||||
|
||||
class ENVIRONMENT_VAR_HELPERS
|
||||
{
|
||||
|
|
@ -24,422 +26,77 @@ public:
|
|||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
CopyToTable(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry,
|
||||
PVOID pvData
|
||||
)
|
||||
{
|
||||
// best effort copy, ignore the failure
|
||||
ENVIRONMENT_VAR_ENTRY * pNewEntry = new ENVIRONMENT_VAR_ENTRY();
|
||||
if (pNewEntry != NULL)
|
||||
{
|
||||
pNewEntry->Initialize(pEntry->QueryName(), pEntry->QueryValue());
|
||||
ENVIRONMENT_VAR_HASH *pHash = static_cast<ENVIRONMENT_VAR_HASH *>(pvData);
|
||||
DBG_ASSERT(pHash);
|
||||
pHash->InsertRecord(pNewEntry);
|
||||
// Need to dereference as InsertRecord references it now
|
||||
pNewEntry->Dereference();
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
AppendEnvironmentVariables
|
||||
(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry,
|
||||
PVOID pvData
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
DWORD dwResult = 0;
|
||||
DWORD dwError = 0;
|
||||
STRU struNameBuffer;
|
||||
STACK_STRU(struValueBuffer, 300);
|
||||
BOOL fFound = FALSE;
|
||||
|
||||
HRESULT* pHr = static_cast<HRESULT*>(pvData);
|
||||
|
||||
// pEntry->QueryName includes the trailing =, remove it before calling stru
|
||||
if (FAILED(hr = struNameBuffer.Copy(pEntry->QueryName())))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
dwResult = struNameBuffer.LastIndexOf(L'=');
|
||||
if (dwResult != -1)
|
||||
{
|
||||
struNameBuffer.QueryStr()[dwResult] = L'\0';
|
||||
if (FAILED(hr = struNameBuffer.SyncWithBuffer()))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
dwResult = GetEnvironmentVariable(struNameBuffer.QueryStr(), struValueBuffer.QueryStr(), struValueBuffer.QuerySizeCCH());
|
||||
if (dwResult == 0)
|
||||
{
|
||||
dwError = GetLastError();
|
||||
// Windows API (e.g., CreateProcess) allows variable with empty string value
|
||||
// in such case dwResult will be 0 and dwError will also be 0
|
||||
// As UI and CMD does not allow empty value, ignore this environment var
|
||||
if (dwError != ERROR_ENVVAR_NOT_FOUND && dwError != ERROR_SUCCESS)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(dwError);
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
else if (dwResult > struValueBuffer.QuerySizeCCH())
|
||||
{
|
||||
// have to increase the buffer and try get environment var again
|
||||
struValueBuffer.Reset();
|
||||
struValueBuffer.Resize(dwResult + (DWORD)wcslen(pEntry->QueryValue()) + 2); // for null char and semicolon
|
||||
dwResult = GetEnvironmentVariable(struNameBuffer.QueryStr(),
|
||||
struValueBuffer.QueryStr(),
|
||||
struValueBuffer.QuerySizeCCH());
|
||||
|
||||
if (dwResult <= 0)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
goto Finished;
|
||||
}
|
||||
fFound = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
fFound = TRUE;
|
||||
}
|
||||
|
||||
if (FAILED(hr = struValueBuffer.SyncWithBuffer()))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (fFound)
|
||||
{
|
||||
if (FAILED(hr = struValueBuffer.Append(L";")))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
if (FAILED(hr = struValueBuffer.Append(pEntry->QueryValue())))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (FAILED(hr = pEntry->Initialize(pEntry->QueryName(), struValueBuffer.QueryStr())))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
Finished:
|
||||
if (FAILED(hr))
|
||||
{
|
||||
*pHr = hr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
SetEnvironmentVariables
|
||||
(
|
||||
ENVIRONMENT_VAR_ENTRY * pEntry,
|
||||
PVOID pvData
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(pvData);
|
||||
HRESULT hr = S_OK;
|
||||
DWORD dwResult = 0;
|
||||
STRU struNameBuffer;
|
||||
|
||||
HRESULT* pHr = static_cast<HRESULT*>(pvData);
|
||||
|
||||
// pEntry->QueryName includes the trailing =, remove it before calling SetEnvironmentVariable.
|
||||
if (FAILED(hr = struNameBuffer.Copy(pEntry->QueryName())))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
dwResult = struNameBuffer.LastIndexOf(L'=');
|
||||
if (dwResult != -1)
|
||||
{
|
||||
struNameBuffer.QueryStr()[dwResult] = L'\0';
|
||||
if (FAILED(hr = struNameBuffer.SyncWithBuffer()))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
dwResult = SetEnvironmentVariable(struNameBuffer.QueryStr(), pEntry->QueryValue());
|
||||
if (dwResult == 0)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
Finished:
|
||||
if (FAILED(hr))
|
||||
{
|
||||
*pHr = hr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static
|
||||
HRESULT
|
||||
std::map<std::wstring, std::wstring, ignore_case_comparer>
|
||||
InitEnvironmentVariablesTable
|
||||
(
|
||||
_In_ ENVIRONMENT_VAR_HASH* pInEnvironmentVarTable,
|
||||
_In_ const std::map<std::wstring, std::wstring, ignore_case_comparer>& pInEnvironmentVarTable,
|
||||
_In_ BOOL fWindowsAuthEnabled,
|
||||
_In_ BOOL fBasicAuthEnabled,
|
||||
_In_ BOOL fAnonymousAuthEnabled,
|
||||
_In_ BOOL fAddHostingStartup,
|
||||
_In_ PCWSTR pApplicationPhysicalPath,
|
||||
_In_ PCWSTR pHttpsPort,
|
||||
_Out_ ENVIRONMENT_VAR_HASH** ppEnvironmentVarTable
|
||||
_In_ PCWSTR pHttpsPort
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
BOOL fFound = FALSE;
|
||||
DWORD dwResult, dwError;
|
||||
STRU strIisAuthEnvValue;
|
||||
STACK_STRU(strStartupAssemblyEnv, 1024);
|
||||
ENVIRONMENT_VAR_ENTRY* pHostingEntry = NULL;
|
||||
ENVIRONMENT_VAR_ENTRY* pIISAuthEntry = NULL;
|
||||
ENVIRONMENT_VAR_ENTRY* pIISPathEntry = NULL;
|
||||
ENVIRONMENT_VAR_ENTRY* pIISHttpsPort = NULL;
|
||||
ENVIRONMENT_VAR_HASH* pEnvironmentVarTable = NULL;
|
||||
std::map<std::wstring, std::wstring, ignore_case_comparer> environmentVariables = pInEnvironmentVarTable;
|
||||
|
||||
pEnvironmentVarTable = new ENVIRONMENT_VAR_HASH();
|
||||
|
||||
//
|
||||
// few environment variables expected, small bucket size for hash table
|
||||
//
|
||||
if (FAILED(hr = pEnvironmentVarTable->Initialize(37 /*prime*/)))
|
||||
environmentVariables.insert_or_assign(ASPNETCORE_IIS_PHYSICAL_PATH_ENV_STR, pApplicationPhysicalPath);
|
||||
if (pHttpsPort)
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
// copy the envirable hash table (from configuration) to a temp one as we may need to remove elements
|
||||
pInEnvironmentVarTable->Apply(ENVIRONMENT_VAR_HELPERS::CopyToTable, pEnvironmentVarTable);
|
||||
if (pEnvironmentVarTable->Count() != pInEnvironmentVarTable->Count())
|
||||
{
|
||||
// hash table copy failed
|
||||
hr = E_UNEXPECTED;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pEnvironmentVarTable->FindKey((PWSTR)ASPNETCORE_IIS_PHYSICAL_PATH_ENV_STR, &pIISPathEntry);
|
||||
if (pIISPathEntry != NULL)
|
||||
{
|
||||
// user defined ASPNETCORE_IIS_PHYSICAL_PATH in configuration, wipe it off
|
||||
pIISPathEntry->Dereference();
|
||||
pEnvironmentVarTable->DeleteKey((PWSTR)ASPNETCORE_IIS_PHYSICAL_PATH_ENV_STR);
|
||||
}
|
||||
|
||||
pIISPathEntry = new ENVIRONMENT_VAR_ENTRY();
|
||||
|
||||
if (FAILED(hr = pIISPathEntry->Initialize(ASPNETCORE_IIS_PHYSICAL_PATH_ENV_STR, pApplicationPhysicalPath)) ||
|
||||
FAILED(hr = pEnvironmentVarTable->InsertRecord(pIISPathEntry)))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (pHttpsPort != nullptr)
|
||||
{
|
||||
pEnvironmentVarTable->FindKey((PWSTR)ASPNETCORE_HTTPS_PORT_ENV_STR, &pIISHttpsPort);
|
||||
if (pIISHttpsPort != NULL)
|
||||
{
|
||||
// user defined ASPNETCORE_HTTPS_PORT in configuration, don't override it
|
||||
pIISHttpsPort->Dereference();
|
||||
}
|
||||
else
|
||||
{
|
||||
pIISHttpsPort = new ENVIRONMENT_VAR_ENTRY();
|
||||
|
||||
if (FAILED(hr = pIISHttpsPort->Initialize(ASPNETCORE_HTTPS_PORT_ENV_STR, pHttpsPort)) ||
|
||||
FAILED(hr = pEnvironmentVarTable->InsertRecord(pIISHttpsPort)))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pEnvironmentVarTable->FindKey((PWSTR)ASPNETCORE_IIS_AUTH_ENV_STR, &pIISAuthEntry);
|
||||
if (pIISAuthEntry != NULL)
|
||||
{
|
||||
// user defined ASPNETCORE_IIS_HTTPAUTH in configuration, wipe it off
|
||||
pIISAuthEntry->Dereference();
|
||||
pEnvironmentVarTable->DeleteKey((PWSTR)ASPNETCORE_IIS_AUTH_ENV_STR);
|
||||
environmentVariables.try_emplace(ASPNETCORE_HTTPS_PORT_ENV_STR, pHttpsPort);
|
||||
}
|
||||
|
||||
std::wstring strIisAuthEnvValue;
|
||||
if (fWindowsAuthEnabled)
|
||||
{
|
||||
strIisAuthEnvValue.Copy(ASPNETCORE_IIS_AUTH_WINDOWS);
|
||||
strIisAuthEnvValue.append(ASPNETCORE_IIS_AUTH_WINDOWS);
|
||||
}
|
||||
|
||||
if (fBasicAuthEnabled)
|
||||
{
|
||||
strIisAuthEnvValue.Append(ASPNETCORE_IIS_AUTH_BASIC);
|
||||
strIisAuthEnvValue.append(ASPNETCORE_IIS_AUTH_BASIC);
|
||||
}
|
||||
|
||||
if (fAnonymousAuthEnabled)
|
||||
{
|
||||
strIisAuthEnvValue.Append(ASPNETCORE_IIS_AUTH_ANONYMOUS);
|
||||
strIisAuthEnvValue.append(ASPNETCORE_IIS_AUTH_ANONYMOUS);
|
||||
}
|
||||
if (strIisAuthEnvValue.empty())
|
||||
{
|
||||
strIisAuthEnvValue.append(ASPNETCORE_IIS_AUTH_NONE);
|
||||
}
|
||||
|
||||
if (strIisAuthEnvValue.IsEmpty())
|
||||
{
|
||||
strIisAuthEnvValue.Copy(ASPNETCORE_IIS_AUTH_NONE);
|
||||
}
|
||||
environmentVariables.insert_or_assign(ASPNETCORE_IIS_AUTH_ENV_STR, strIisAuthEnvValue);
|
||||
|
||||
pIISAuthEntry = new ENVIRONMENT_VAR_ENTRY();
|
||||
|
||||
if (FAILED(hr = pIISAuthEntry->Initialize(ASPNETCORE_IIS_AUTH_ENV_STR, strIisAuthEnvValue.QueryStr())) ||
|
||||
FAILED(hr = pEnvironmentVarTable->InsertRecord(pIISAuthEntry)))
|
||||
if (fAddHostingStartup && environmentVariables.count(HOSTING_STARTUP_ASSEMBLIES_ENV_STR) == 0)
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
auto hostingStartupValues = Environment::GetEnvironmentVariableValue(HOSTING_STARTUP_ASSEMBLIES_ENV_STR).value_or(L"");
|
||||
|
||||
// Compiler is complaining about conversion between PCWSTR and PWSTR here.
|
||||
// Explictly casting.
|
||||
pEnvironmentVarTable->FindKey((PWSTR)HOSTING_STARTUP_ASSEMBLIES_NAME, &pHostingEntry);
|
||||
if (pHostingEntry != NULL)
|
||||
{
|
||||
// user defined ASPNETCORE_HOSTINGSTARTUPASSEMBLIES in configuration
|
||||
// the value will be used in OutputEnvironmentVariables. Do nothing here
|
||||
pHostingEntry->Dereference();
|
||||
pHostingEntry = NULL;
|
||||
goto Skipped;
|
||||
}
|
||||
|
||||
//check whether ASPNETCORE_HOSTINGSTARTUPASSEMBLIES is defined in system
|
||||
dwResult = GetEnvironmentVariable(HOSTING_STARTUP_ASSEMBLIES_ENV_STR,
|
||||
strStartupAssemblyEnv.QueryStr(),
|
||||
strStartupAssemblyEnv.QuerySizeCCH());
|
||||
if (dwResult == 0)
|
||||
{
|
||||
dwError = GetLastError();
|
||||
// Windows API (e.g., CreateProcess) allows variable with empty string value
|
||||
// in such case dwResult will be 0 and dwError will also be 0
|
||||
// As UI and CMD does not allow empty value, ignore this environment var
|
||||
if (dwError != ERROR_ENVVAR_NOT_FOUND && dwError != ERROR_SUCCESS)
|
||||
if (hostingStartupValues.find(HOSTING_STARTUP_ASSEMBLIES_ENV_STR) == std::wstring::npos)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(dwError);
|
||||
goto Finished;
|
||||
hostingStartupValues += std::wstring(L";") + HOSTING_STARTUP_ASSEMBLIES_VALUE;
|
||||
}
|
||||
}
|
||||
else if (dwResult > strStartupAssemblyEnv.QuerySizeCCH())
|
||||
{
|
||||
// have to increase the buffer and try get environment var again
|
||||
strStartupAssemblyEnv.Reset();
|
||||
strStartupAssemblyEnv.Resize(dwResult + (DWORD)wcslen(HOSTING_STARTUP_ASSEMBLIES_VALUE) + 1);
|
||||
dwResult = GetEnvironmentVariable(HOSTING_STARTUP_ASSEMBLIES_ENV_STR,
|
||||
strStartupAssemblyEnv.QueryStr(),
|
||||
strStartupAssemblyEnv.QuerySizeCCH());
|
||||
if (dwResult <= 0)
|
||||
{
|
||||
hr = E_UNEXPECTED;
|
||||
goto Finished;
|
||||
}
|
||||
fFound = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
fFound = TRUE;
|
||||
|
||||
environmentVariables.insert_or_assign(HOSTING_STARTUP_ASSEMBLIES_ENV_STR, hostingStartupValues);
|
||||
}
|
||||
|
||||
strStartupAssemblyEnv.SyncWithBuffer();
|
||||
if (strStartupAssemblyEnv.IndexOf(HOSTING_STARTUP_ASSEMBLIES_VALUE) == -1)
|
||||
for (auto& environmentVariable : environmentVariables)
|
||||
{
|
||||
if (fFound)
|
||||
{
|
||||
strStartupAssemblyEnv.Append(L";");
|
||||
}
|
||||
strStartupAssemblyEnv.Append(HOSTING_STARTUP_ASSEMBLIES_VALUE);
|
||||
environmentVariable.second = Environment::ExpandEnvironmentVariables(environmentVariable.second);
|
||||
}
|
||||
|
||||
// the environment variable was not defined, create it and add to hashtable
|
||||
pHostingEntry = new ENVIRONMENT_VAR_ENTRY();
|
||||
|
||||
if (FAILED(hr = pHostingEntry->Initialize(HOSTING_STARTUP_ASSEMBLIES_NAME, strStartupAssemblyEnv.QueryStr())) ||
|
||||
FAILED(hr = pEnvironmentVarTable->InsertRecord(pHostingEntry)))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
Skipped:
|
||||
*ppEnvironmentVarTable = pEnvironmentVarTable;
|
||||
pEnvironmentVarTable = NULL;
|
||||
|
||||
Finished:
|
||||
if (pHostingEntry != NULL)
|
||||
{
|
||||
pHostingEntry->Dereference();
|
||||
pHostingEntry = NULL;
|
||||
}
|
||||
|
||||
if (pIISAuthEntry != NULL)
|
||||
{
|
||||
pIISAuthEntry->Dereference();
|
||||
pIISAuthEntry = NULL;
|
||||
}
|
||||
|
||||
if (pEnvironmentVarTable != NULL)
|
||||
{
|
||||
pEnvironmentVarTable->Clear();
|
||||
delete pEnvironmentVarTable;
|
||||
pEnvironmentVarTable = NULL;
|
||||
}
|
||||
return hr;
|
||||
return environmentVariables;
|
||||
}
|
||||
|
||||
static
|
||||
HRESULT
|
||||
std::map<std::wstring, std::wstring, ignore_case_comparer>
|
||||
AddWebsocketEnabledToEnvironmentVariables
|
||||
(
|
||||
_Inout_ ENVIRONMENT_VAR_HASH* pInEnvironmentVarTable,
|
||||
_Inout_ const std::map<std::wstring, std::wstring, ignore_case_comparer>& pInEnvironmentVarTable,
|
||||
_In_ BOOL fWebsocketsEnabled
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
ENVIRONMENT_VAR_ENTRY* pIISWebsocketEntry = NULL;
|
||||
STACK_STRU(strIISWebsocketEnvValue, 40);
|
||||
|
||||
// We only need to set the WEBSOCKET_SUPPORTED environment variable for out of process
|
||||
pInEnvironmentVarTable->FindKey((PWSTR)ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED_ENV_STR, &pIISWebsocketEntry);
|
||||
if (pIISWebsocketEntry != NULL)
|
||||
{
|
||||
// user defined ASPNETCORE_IIS_WEBSOCKETS in configuration, wipe it off
|
||||
pIISWebsocketEntry->Dereference();
|
||||
pInEnvironmentVarTable->DeleteKey((PWSTR)ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED_ENV_STR);
|
||||
}
|
||||
// Set either true or false for the WebsocketEnvValue.
|
||||
if (fWebsocketsEnabled)
|
||||
{
|
||||
if (FAILED(hr = strIISWebsocketEnvValue.Copy(L"true")))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FAILED(hr = strIISWebsocketEnvValue.Copy(L"false")))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
pIISWebsocketEntry = new ENVIRONMENT_VAR_ENTRY();
|
||||
|
||||
if (FAILED(hr = pIISWebsocketEntry->Initialize(ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED_ENV_STR, strIISWebsocketEnvValue.QueryStr())) ||
|
||||
FAILED(hr = pInEnvironmentVarTable->InsertRecord(pIISWebsocketEntry)))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
Finished:
|
||||
return hr;
|
||||
std::map<std::wstring, std::wstring, ignore_case_comparer> environmentVariables = pInEnvironmentVarTable;
|
||||
environmentVariables.insert_or_assign(ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED_ENV_STR, fWebsocketsEnabled ? L"true" : L"false");
|
||||
return environmentVariables;
|
||||
}
|
||||
public:
|
||||
ENVIRONMENT_VAR_HELPERS();
|
||||
~ENVIRONMENT_VAR_HELPERS();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -15,13 +15,6 @@ REQUESTHANDLER_CONFIG::~REQUESTHANDLER_CONFIG()
|
|||
delete[] m_ppStrArguments;
|
||||
m_ppStrArguments = NULL;
|
||||
}
|
||||
|
||||
if (m_pEnvironmentVariables != NULL)
|
||||
{
|
||||
m_pEnvironmentVariables->Clear();
|
||||
delete m_pEnvironmentVariables;
|
||||
m_pEnvironmentVariables = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
|
|
@ -100,12 +93,7 @@ REQUESTHANDLER_CONFIG::Populate(
|
|||
IAppHostElement *pWindowsAuthenticationElement = NULL;
|
||||
IAppHostElement *pBasicAuthenticationElement = NULL;
|
||||
IAppHostElement *pAnonymousAuthenticationElement = NULL;
|
||||
IAppHostElement *pEnvVarList = NULL;
|
||||
IAppHostElement *pEnvVar = NULL;
|
||||
IAppHostElementCollection *pEnvVarCollection = NULL;
|
||||
ULONGLONG ullRawTimeSpan = 0;
|
||||
ENUM_INDEX index;
|
||||
ENVIRONMENT_VAR_ENTRY* pEntry = NULL;
|
||||
DWORD dwCounter = 0;
|
||||
DWORD dwPosition = 0;
|
||||
WCHAR* pszPath = NULL;
|
||||
|
|
@ -114,26 +102,20 @@ REQUESTHANDLER_CONFIG::Populate(
|
|||
BSTR bstrAnonymousAuthSection = NULL;
|
||||
BSTR bstrAspNetCoreSection = NULL;
|
||||
|
||||
m_pEnvironmentVariables = new ENVIRONMENT_VAR_HASH();
|
||||
if (FAILED(hr = m_pEnvironmentVariables->Initialize(37 /*prime*/)))
|
||||
{
|
||||
delete m_pEnvironmentVariables;
|
||||
m_pEnvironmentVariables = NULL;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pAdminManager = pHttpServer->GetAdminManager();
|
||||
if (pSite != nullptr)
|
||||
try
|
||||
{
|
||||
try
|
||||
WebConfigConfigurationSource source(pAdminManager, *pHttpApplication);
|
||||
if (pSite != nullptr)
|
||||
{
|
||||
WebConfigConfigurationSource source(pAdminManager, *pHttpApplication);
|
||||
m_struHttpsPort.Copy(BindingInformation::GetHttpsPort(BindingInformation::Load(source, *pSite)).c_str());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
FINISHED_IF_FAILED(OBSERVE_CAUGHT_EXCEPTION());
|
||||
}
|
||||
|
||||
m_pEnvironmentVariables = source.GetSection(CS_ASPNETCORE_SECTION)->GetMap(CS_ASPNETCORE_ENVIRONMENT_VARIABLES);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
FINISHED_IF_FAILED(OBSERVE_CAUGHT_EXCEPTION());
|
||||
}
|
||||
|
||||
hr = m_struConfigPath.Copy(pHttpApplication->GetAppConfigPath());
|
||||
|
|
@ -397,58 +379,6 @@ REQUESTHANDLER_CONFIG::Populate(
|
|||
goto Finished;
|
||||
}
|
||||
|
||||
hr = GetElementChildByName(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_ENVIRONMENT_VARIABLES,
|
||||
&pEnvVarList);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = pEnvVarList->get_Collection(&pEnvVarCollection);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
for (hr = FindFirstElement(pEnvVarCollection, &index, &pEnvVar);
|
||||
SUCCEEDED(hr);
|
||||
hr = FindNextElement(pEnvVarCollection, &index, &pEnvVar))
|
||||
{
|
||||
if (hr == S_FALSE)
|
||||
{
|
||||
hr = S_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
if (FAILED(hr = GetElementStringProperty(pEnvVar,
|
||||
CS_ASPNETCORE_ENVIRONMENT_VARIABLE_NAME,
|
||||
&strEnvName)) ||
|
||||
FAILED(hr = GetElementStringProperty(pEnvVar,
|
||||
CS_ASPNETCORE_ENVIRONMENT_VARIABLE_VALUE,
|
||||
&strEnvValue)) ||
|
||||
FAILED(hr = strEnvName.Append(L"=")) ||
|
||||
FAILED(hr = STRU::ExpandEnvironmentVariables(strEnvValue.QueryStr(), &strExpandedEnvValue)))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pEntry = new ENVIRONMENT_VAR_ENTRY();
|
||||
|
||||
if (FAILED(hr = pEntry->Initialize(strEnvName.QueryStr(), strExpandedEnvValue.QueryStr())) ||
|
||||
FAILED(hr = m_pEnvironmentVariables->InsertRecord(pEntry)))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
strEnvName.Reset();
|
||||
strEnvValue.Reset();
|
||||
strExpandedEnvValue.Reset();
|
||||
pEnvVar->Release();
|
||||
pEnvVar = NULL;
|
||||
pEntry->Dereference();
|
||||
pEntry = NULL;
|
||||
}
|
||||
|
||||
Finished:
|
||||
|
||||
if (pAspNetCoreElement != NULL)
|
||||
|
|
@ -475,29 +405,5 @@ Finished:
|
|||
pBasicAuthenticationElement = NULL;
|
||||
}
|
||||
|
||||
if (pEnvVarList != NULL)
|
||||
{
|
||||
pEnvVarList->Release();
|
||||
pEnvVarList = NULL;
|
||||
}
|
||||
|
||||
if (pEnvVar != NULL)
|
||||
{
|
||||
pEnvVar->Release();
|
||||
pEnvVar = NULL;
|
||||
}
|
||||
|
||||
if (pEnvVarCollection != NULL)
|
||||
{
|
||||
pEnvVarCollection->Release();
|
||||
pEnvVarCollection = NULL;
|
||||
}
|
||||
|
||||
if (pEntry != NULL)
|
||||
{
|
||||
pEntry->Dereference();
|
||||
pEntry = NULL;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ public:
|
|||
_Out_ REQUESTHANDLER_CONFIG **ppAspNetCoreConfig
|
||||
);
|
||||
|
||||
ENVIRONMENT_VAR_HASH*
|
||||
std::map<std::wstring, std::wstring, ignore_case_comparer>&
|
||||
QueryEnvironmentVariables(
|
||||
VOID
|
||||
)
|
||||
|
|
@ -225,7 +225,6 @@ protected:
|
|||
//
|
||||
REQUESTHANDLER_CONFIG() :
|
||||
m_fStdoutLogEnabled(FALSE),
|
||||
m_pEnvironmentVariables(NULL),
|
||||
m_hostingModel(HOSTING_UNKNOWN),
|
||||
m_ppStrArguments(NULL)
|
||||
{
|
||||
|
|
@ -257,7 +256,7 @@ protected:
|
|||
BOOL m_fBasicAuthEnabled;
|
||||
BOOL m_fAnonymousAuthEnabled;
|
||||
APP_HOSTING_MODEL m_hostingModel;
|
||||
ENVIRONMENT_VAR_HASH* m_pEnvironmentVariables;
|
||||
std::map<std::wstring, std::wstring, ignore_case_comparer> m_pEnvironmentVariables;
|
||||
STRU m_struHostFxrLocation;
|
||||
PWSTR* m_ppStrArguments;
|
||||
DWORD m_dwArgc;
|
||||
|
|
|
|||
|
|
@ -2,50 +2,132 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
[Collection(IISTestSiteCollection.Name)]
|
||||
public class EnvironmentVariableTests: FixtureLoggedTest
|
||||
{
|
||||
private readonly IISTestSiteFixture _fixture;
|
||||
[Collection(PublishedSitesCollection.Name)]
|
||||
|
||||
public EnvironmentVariableTests(IISTestSiteFixture fixture): base(fixture)
|
||||
public class EnvironmentVariableTests: IISFunctionalTestBase
|
||||
{
|
||||
private readonly PublishedSitesFixture _fixture;
|
||||
|
||||
public EnvironmentVariableTests(PublishedSitesFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task GetUniqueEnvironmentVariable()
|
||||
[ConditionalTheory]
|
||||
[InlineData(HostingModel.InProcess)]
|
||||
[InlineData(HostingModel.OutOfProcess)]
|
||||
public async Task GetLongEnvironmentVariable(HostingModel hostingModel)
|
||||
{
|
||||
Assert.Equal("foobar", await _fixture.Client.GetStringAsync("/CheckEnvironmentVariable"));
|
||||
}
|
||||
var expectedValue = "AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative" +
|
||||
"AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative" +
|
||||
"AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative" +
|
||||
"AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative" +
|
||||
"AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative" +
|
||||
"AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative";
|
||||
|
||||
|
||||
var deploymentParameters = _fixture.GetBaseDeploymentParameters(hostingModel, publish: true);
|
||||
deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_INPROCESS_TESTING_LONG_VALUE"] = expectedValue;
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task GetLongEnvironmentVariable()
|
||||
{
|
||||
Assert.Equal(
|
||||
"AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative" +
|
||||
"AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative" +
|
||||
"AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative" +
|
||||
"AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative" +
|
||||
"AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative" +
|
||||
"AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative",
|
||||
await _fixture.Client.GetStringAsync("/CheckEnvironmentLongValueVariable"));
|
||||
expectedValue,
|
||||
await GetStringAsync(deploymentParameters, "/GetEnvironmentVariable?name=ASPNETCORE_INPROCESS_TESTING_LONG_VALUE"));
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task GetExistingEnvironmentVariable()
|
||||
[RequiresNewHandler]
|
||||
public Task AuthHeaderEnvironmentVariableRemoved_InProcess() => AuthHeaderEnvironmentVariableRemoved(HostingModel.InProcess);
|
||||
|
||||
[ConditionalFact]
|
||||
public Task AuthHeaderEnvironmentVariableRemoved_OutOfProcess() => AuthHeaderEnvironmentVariableRemoved(HostingModel.OutOfProcess);
|
||||
|
||||
private async Task AuthHeaderEnvironmentVariableRemoved(HostingModel hostingModel)
|
||||
{
|
||||
Assert.Contains(";foobarbaz", await _fixture.Client.GetStringAsync("/CheckAppendedEnvironmentVariable"));
|
||||
var deploymentParameters = _fixture.GetBaseDeploymentParameters(hostingModel, publish: true);
|
||||
deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_IIS_HTTPAUTH"] = "shouldberemoved";
|
||||
|
||||
Assert.DoesNotContain("shouldberemoved", await GetStringAsync(deploymentParameters,"/GetEnvironmentVariable?name=ASPNETCORE_IIS_HTTPAUTH"));
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task AuthHeaderEnvironmentVariableRemoved()
|
||||
[RequiresNewHandler]
|
||||
[RequiresIIS(IISCapability.PoolEnvironmentVariables)]
|
||||
public Task WebConfigOverridesGlobalEnvironmentVariables_InProcess() => WebConfigOverridesGlobalEnvironmentVariables(HostingModel.InProcess);
|
||||
|
||||
[ConditionalFact]
|
||||
[RequiresIIS(IISCapability.PoolEnvironmentVariables)]
|
||||
public Task WebConfigOverridesGlobalEnvironmentVariables_OutOfProcess() => WebConfigOverridesGlobalEnvironmentVariables(HostingModel.OutOfProcess);
|
||||
|
||||
private async Task WebConfigOverridesGlobalEnvironmentVariables(HostingModel hostingModel)
|
||||
{
|
||||
Assert.DoesNotContain("shouldberemoved", await _fixture.Client.GetStringAsync("/CheckRemoveAuthEnvironmentVariable"));
|
||||
var deploymentParameters = _fixture.GetBaseDeploymentParameters(hostingModel, publish: true);
|
||||
deploymentParameters.EnvironmentVariables["ASPNETCORE_ENVIRONMENT"] = "Development";
|
||||
deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_ENVIRONMENT"] = "Production";
|
||||
Assert.Equal("Production", await GetStringAsync(deploymentParameters, "/GetEnvironmentVariable?name=ASPNETCORE_ENVIRONMENT"));
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
[RequiresNewHandler]
|
||||
[RequiresIIS(IISCapability.PoolEnvironmentVariables)]
|
||||
public Task WebConfigAppendsHostingStartup_InProcess() => WebConfigAppendsHostingStartup(HostingModel.InProcess);
|
||||
|
||||
[ConditionalFact]
|
||||
[RequiresIIS(IISCapability.PoolEnvironmentVariables)]
|
||||
public Task WebConfigAppendsHostingStartup_OutOfProcess() => WebConfigAppendsHostingStartup(HostingModel.OutOfProcess);
|
||||
|
||||
private async Task WebConfigAppendsHostingStartup(HostingModel hostingModel)
|
||||
{
|
||||
var deploymentParameters = _fixture.GetBaseDeploymentParameters(hostingModel, publish: true);
|
||||
deploymentParameters.EnvironmentVariables["ASPNETCORE_HOSTINGSTARTUPASSEMBLIES"] = "Asm1";
|
||||
if (hostingModel == HostingModel.InProcess)
|
||||
{
|
||||
Assert.Equal("Asm1", await GetStringAsync(deploymentParameters, "/GetEnvironmentVariable?name=ASPNETCORE_HOSTINGSTARTUPASSEMBLIES"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Equal("Asm1;Microsoft.AspNetCore.Server.IISIntegration", await GetStringAsync(deploymentParameters, "/GetEnvironmentVariable?name=ASPNETCORE_HOSTINGSTARTUPASSEMBLIES"));
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
[RequiresNewHandler]
|
||||
[RequiresIIS(IISCapability.PoolEnvironmentVariables)]
|
||||
public Task WebConfigOverridesHostingStartup_InProcess() => WebConfigOverridesHostingStartup(HostingModel.InProcess);
|
||||
|
||||
[ConditionalFact]
|
||||
[RequiresIIS(IISCapability.PoolEnvironmentVariables)]
|
||||
public Task WebConfigOverridesHostingStartup_OutOfProcess() => WebConfigOverridesHostingStartup(HostingModel.OutOfProcess);
|
||||
|
||||
private async Task WebConfigOverridesHostingStartup(HostingModel hostingModel)
|
||||
{
|
||||
var deploymentParameters = _fixture.GetBaseDeploymentParameters(hostingModel, publish: true);
|
||||
deploymentParameters.EnvironmentVariables["ASPNETCORE_HOSTINGSTARTUPASSEMBLIES"] = "Asm1";
|
||||
deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_HOSTINGSTARTUPASSEMBLIES"] = "Asm2";
|
||||
Assert.Equal("Asm2", await GetStringAsync(deploymentParameters, "/GetEnvironmentVariable?name=ASPNETCORE_HOSTINGSTARTUPASSEMBLIES"));
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
[RequiresNewHandler]
|
||||
[RequiresIIS(IISCapability.PoolEnvironmentVariables)]
|
||||
public Task WebConfigExpandsVariables_InProcess() => WebConfigExpandsVariables(HostingModel.InProcess);
|
||||
|
||||
[ConditionalFact]
|
||||
[RequiresIIS(IISCapability.PoolEnvironmentVariables)]
|
||||
public Task WebConfigExpandsVariables_OutOfProcess() => WebConfigExpandsVariables(HostingModel.OutOfProcess);
|
||||
|
||||
private async Task WebConfigExpandsVariables(HostingModel hostingModel)
|
||||
{
|
||||
var deploymentParameters = _fixture.GetBaseDeploymentParameters(hostingModel, publish: true);
|
||||
deploymentParameters.EnvironmentVariables["TestVariable"] = "World";
|
||||
deploymentParameters.WebConfigBasedEnvironmentVariables["OtherVariable"] = "%TestVariable%;Hello";
|
||||
Assert.Equal("World;Hello", await GetStringAsync(deploymentParameters, "/GetEnvironmentVariable?name=OtherVariable"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,12 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
return result;
|
||||
}
|
||||
|
||||
protected virtual async Task<string> GetStringAsync(IISDeploymentParameters parameters, string path)
|
||||
{
|
||||
var result = await DeployAsync(parameters);
|
||||
return await result.HttpClient.GetStringAsync(path);
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
StopServer(false);
|
||||
|
|
|
|||
|
|
@ -266,29 +266,6 @@ namespace TestSite
|
|||
}
|
||||
}
|
||||
|
||||
private async Task CheckEnvironmentVariable(HttpContext ctx)
|
||||
{
|
||||
var variable = Environment.GetEnvironmentVariable("ASPNETCORE_INPROCESS_TESTING_VALUE");
|
||||
await ctx.Response.WriteAsync(variable);
|
||||
}
|
||||
|
||||
private async Task CheckEnvironmentLongValueVariable(HttpContext ctx)
|
||||
{
|
||||
var variable = Environment.GetEnvironmentVariable("ASPNETCORE_INPROCESS_TESTING_LONG_VALUE");
|
||||
await ctx.Response.WriteAsync(variable);
|
||||
}
|
||||
|
||||
private async Task CheckAppendedEnvironmentVariable(HttpContext ctx)
|
||||
{
|
||||
var variable = Environment.GetEnvironmentVariable("ProgramFiles");
|
||||
await ctx.Response.WriteAsync(variable);
|
||||
}
|
||||
|
||||
private async Task CheckRemoveAuthEnvironmentVariable(HttpContext ctx)
|
||||
{
|
||||
var variable = Environment.GetEnvironmentVariable("ASPNETCORE_IIS_HTTPAUTH");
|
||||
await ctx.Response.WriteAsync(variable);
|
||||
}
|
||||
private async Task ReadAndWriteSynchronously(HttpContext ctx)
|
||||
{
|
||||
var t2 = Task.Run(() => WriteManyTimesToResponseBody(ctx));
|
||||
|
|
|
|||
|
|
@ -5,12 +5,6 @@
|
|||
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
|
||||
</handlers>
|
||||
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" hostingModel="inprocess">
|
||||
<environmentVariables>
|
||||
<environmentVariable name="ASPNETCORE_INPROCESS_TESTING_VALUE" value="foobar" />
|
||||
<environmentVariable name="ASPNETCORE_INPROCESS_TESTING_LONG_VALUE" value="AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative" />
|
||||
<environmentVariable name="ProgramFiles" value="foobarbaz" />
|
||||
<environmentVariable name="ASPNETCORE_IIS_HTTPAUTH" value="shouldberemoved" />
|
||||
</environmentVariables>
|
||||
</aspNetCore>
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
|
|
|
|||
|
|
@ -134,5 +134,10 @@ namespace TestSite
|
|||
GetDllDirectory(1024, builder);
|
||||
await context.Response.WriteAsync(builder.ToString());
|
||||
}
|
||||
|
||||
private async Task GetEnvironmentVariable(HttpContext ctx)
|
||||
{
|
||||
await ctx.Response.WriteAsync(Environment.GetEnvironmentVariable(ctx.Request.Query["name"].ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue