Fix ANCM environment variables bugs (#6083)

This commit is contained in:
Pavel Krymets 2018-12-28 15:48:20 -08:00 committed by GitHub
parent a25c7d95e3
commit a7b783724e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 246 additions and 592 deletions

View File

@ -37,7 +37,7 @@ jobs:
- template: jobs/iisintegration-job.yml - template: jobs/iisintegration-job.yml
parameters: parameters:
TestGroupName: IISExpress 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 - template: jobs/iisintegration-job.yml
parameters: parameters:
TestGroupName: IISForwardCompat TestGroupName: IISForwardCompat

View File

@ -5,6 +5,7 @@
#include "StringHelpers.h" #include "StringHelpers.h"
#include "ConfigurationLoadException.h" #include "ConfigurationLoadException.h"
#include <map>
std::wstring ConfigurationSection::GetRequiredString(const std::wstring& name) const 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; 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 std::shared_ptr<ConfigurationSection> ConfigurationSection::GetRequiredSection(const std::wstring& name) const
{ {
auto section = GetSection(name); auto section = GetSection(name);

View File

@ -6,8 +6,10 @@
#include <string> #include <string>
#include <optional> #include <optional>
#include <vector> #include <vector>
#include <map>
#include "NonCopyable.h" #include "NonCopyable.h"
#include "StringHelpers.h"
#define CS_ASPNETCORE_COLLECTION_ITEM_NAME L"name" #define CS_ASPNETCORE_COLLECTION_ITEM_NAME L"name"
#define CS_ASPNETCORE_COLLECTION_ITEM_VALUE L"value" #define CS_ASPNETCORE_COLLECTION_ITEM_VALUE L"value"
@ -46,6 +48,7 @@ public:
DWORD GetRequiredTimespan(const std::wstring& name) const; DWORD GetRequiredTimespan(const std::wstring& name) const;
virtual std::vector<std::pair<std::wstring, std::wstring>> GetKeyValuePairs(const std::wstring& name) const; 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; virtual std::shared_ptr<ConfigurationSection> GetRequiredSection(const std::wstring & name) const;

View File

@ -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) 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) 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 // 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) if (source.length() == 0)
{ {
return L""; return L"";

View File

@ -11,6 +11,9 @@ bool ends_with(const std::wstring &source, const std::wstring &suffix, bool igno
[[nodiscard]] [[nodiscard]]
bool equals_ignore_case(const std::wstring& s1, const std::wstring& s2); 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]] [[nodiscard]]
std::wstring to_wide_string(const std::string &source, const unsigned int codePage); 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; return result;
} }
struct ignore_case_comparer
{
bool operator() (const std::wstring & s1, const std::wstring & s2) const {
return compare_ignore_case(s1, s2) == -1;
}
};

View File

@ -134,6 +134,12 @@ private:
return condition; 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) __declspec(noinline) inline VOID ReportException(LOCATION_ARGUMENTS const std::exception& exception)
{ {
TraceException(LOCATION_CALL exception); TraceException(LOCATION_CALL exception);
@ -165,6 +171,11 @@ __declspec(noinline) inline HRESULT CaughtExceptionHResult(LOCATION_ARGUMENTS_ON
ReportException(LOCATION_CALL exception); ReportException(LOCATION_CALL exception);
return exception.GetResult(); return exception.GetResult();
} }
catch (const InvalidOperationException& exception)
{
ReportException(LOCATION_CALL exception);
return HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION);
}
catch (const std::exception& exception) catch (const std::exception& exception)
{ {
ReportException(LOCATION_CALL exception); ReportException(LOCATION_CALL exception);

View File

@ -53,7 +53,7 @@ InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSourc
m_fStdoutLogEnabled = aspNetCoreSection->GetRequiredBool(CS_ASPNETCORE_STDOUT_LOG_ENABLED); m_fStdoutLogEnabled = aspNetCoreSection->GetRequiredBool(CS_ASPNETCORE_STDOUT_LOG_ENABLED);
m_struStdoutLogFile = aspNetCoreSection->GetRequiredString(CS_ASPNETCORE_STDOUT_LOG_FILE); m_struStdoutLogFile = aspNetCoreSection->GetRequiredString(CS_ASPNETCORE_STDOUT_LOG_FILE);
m_fDisableStartUpErrorPage = aspNetCoreSection->GetRequiredBool(CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE); 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); 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"); m_fSetCurrentDirectory = equals_ignore_case(find_element(handlerSettings, CS_ASPNETCORE_HANDLER_SET_CURRENT_DIRECTORY).value_or(L"true"), L"true");

View File

@ -7,6 +7,7 @@
#include "BindingInformation.h" #include "BindingInformation.h"
#include "ConfigurationSource.h" #include "ConfigurationSource.h"
#include "WebConfigConfigurationSource.h" #include "WebConfigConfigurationSource.h"
#include <map>
class InProcessOptions: NonCopyable class InProcessOptions: NonCopyable
{ {
@ -87,7 +88,7 @@ public:
return m_dwShutdownTimeLimitInMS; return m_dwShutdownTimeLimitInMS;
} }
const std::vector<std::pair<std::wstring, std::wstring>>& const std::map<std::wstring, std::wstring, ignore_case_comparer>&
QueryEnvironmentVariables() const QueryEnvironmentVariables() const
{ {
return m_environmentVariables; return m_environmentVariables;
@ -120,7 +121,7 @@ private:
bool m_fAnonymousAuthEnabled; bool m_fAnonymousAuthEnabled;
DWORD m_dwStartupTimeLimitInMS; DWORD m_dwStartupTimeLimitInMS;
DWORD m_dwShutdownTimeLimitInMS; 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; std::vector<BindingInformation> m_bindingInformation;
protected: protected:

View File

@ -425,37 +425,20 @@ IN_PROCESS_APPLICATION::ClrThreadEntryPoint(const std::shared_ptr<ExecuteClrCont
HRESULT HRESULT
IN_PROCESS_APPLICATION::SetEnvironmentVariablesOnWorkerProcess() IN_PROCESS_APPLICATION::SetEnvironmentVariablesOnWorkerProcess()
{ {
auto variables = m_pConfig->QueryEnvironmentVariables(); auto variables = ENVIRONMENT_VAR_HELPERS::InitEnvironmentVariablesTable(
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(),
m_pConfig->QueryWindowsAuthEnabled(), m_pConfig->QueryWindowsAuthEnabled(),
m_pConfig->QueryBasicAuthEnabled(), m_pConfig->QueryBasicAuthEnabled(),
m_pConfig->QueryAnonymousAuthEnabled(), m_pConfig->QueryAnonymousAuthEnabled(),
false, // fAddHostingStartup
QueryApplicationPhysicalPath().c_str(), QueryApplicationPhysicalPath().c_str(),
nullptr, /* pHttpsPort */ nullptr);
&pHashTable));
table.reset(pHashTable); for (const auto & variable : variables)
{
HRESULT hr = S_OK; LOG_INFOF(L"Setting environment variable %ls=%ls", variable.first.c_str(), variable.second.c_str());
table->Apply(ENVIRONMENT_VAR_HELPERS::AppendEnvironmentVariables, &hr); SetEnvironmentVariable(variable.first.c_str(), variable.second.c_str());
RETURN_IF_FAILED(hr); }
table->Apply(ENVIRONMENT_VAR_HELPERS::SetEnvironmentVariables, &hr);
RETURN_IF_FAILED(hr);
return S_OK; return S_OK;
} }

View File

@ -24,7 +24,7 @@ SERVER_PROCESS::Initialize(
BOOL fWindowsAuthEnabled, BOOL fWindowsAuthEnabled,
BOOL fBasicAuthEnabled, BOOL fBasicAuthEnabled,
BOOL fAnonymousAuthEnabled, BOOL fAnonymousAuthEnabled,
ENVIRONMENT_VAR_HASH *pEnvironmentVariables, std::map<std::wstring, std::wstring, ignore_case_comparer>& pEnvironmentVariables,
BOOL fStdoutLogEnabled, BOOL fStdoutLogEnabled,
BOOL fWebSocketSupported, BOOL fWebSocketSupported,
STRU *pstruStdoutLogFile, STRU *pstruStdoutLogFile,
@ -761,6 +761,8 @@ SERVER_PROCESS::StartProcess(
ENVIRONMENT_VAR_HASH *pHashTable = NULL; ENVIRONMENT_VAR_HASH *pHashTable = NULL;
PWSTR pStrStage = NULL; PWSTR pStrStage = NULL;
BOOL fCriticalError = FALSE; BOOL fCriticalError = FALSE;
std::map<std::wstring, std::wstring, ignore_case_comparer> variables;
GetStartupInfoW(&startupInfo); GetStartupInfoW(&startupInfo);
// //
@ -782,27 +784,30 @@ SERVER_PROCESS::StartProcess(
goto Failure; goto Failure;
} }
if (FAILED_LOG(hr = ENVIRONMENT_VAR_HELPERS::InitEnvironmentVariablesTable( try
m_pEnvironmentVarTable,
m_fWindowsAuthEnabled,
m_fBasicAuthEnabled,
m_fAnonymousAuthEnabled,
m_struAppFullPath.QueryStr(),
m_struHttpsPort.QueryStr(),
&pHashTable)))
{ {
pStrStage = L"InitEnvironmentVariablesTable"; variables = ENVIRONMENT_VAR_HELPERS::InitEnvironmentVariablesTable(
goto Failure; 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, pHashTable = new ENVIRONMENT_VAR_HASH();
m_fWebSocketSupported RETURN_IF_FAILED(pHashTable->Initialize(37 /*prime*/));
))) // Copy environment variables to old style hash table
for (auto & variable : variables)
{ {
pStrStage = L"AddWebsocketEnabledToEnvironmentVariables"; auto pNewEntry = std::unique_ptr<ENVIRONMENT_VAR_ENTRY, ENVIRONMENT_VAR_ENTRY_DELETER>(new ENVIRONMENT_VAR_ENTRY());
goto Failure; 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(); CleanUp();
m_pEnvironmentVarTable = NULL;
// no need to free m_pEnvironmentVarTable, as it references to // no need to free m_pEnvironmentVarTable, as it references to
// the same hash table hold by configuration. // the same hash table hold by configuration.
// the hashtable memory will be freed once onfiguration got recycled // the hashtable memory will be freed once onfiguration got recycled

View File

@ -4,6 +4,7 @@
#pragma once #pragma once
#include <random> #include <random>
#include <map>
#define MIN_PORT 1025 #define MIN_PORT 1025
#define MAX_PORT 48000 #define MAX_PORT 48000
@ -33,7 +34,7 @@ public:
_In_ BOOL fWindowsAuthEnabled, _In_ BOOL fWindowsAuthEnabled,
_In_ BOOL fBasicAuthEnabled, _In_ BOOL fBasicAuthEnabled,
_In_ BOOL fAnonymousAuthEnabled, _In_ BOOL fAnonymousAuthEnabled,
_In_ ENVIRONMENT_VAR_HASH* pEnvironmentVariables, _In_ std::map<std::wstring, std::wstring, ignore_case_comparer>& pEnvironmentVariables,
_In_ BOOL fStdoutLogEnabled, _In_ BOOL fStdoutLogEnabled,
_In_ BOOL fWebSocketSupported, _In_ BOOL fWebSocketSupported,
_In_ STRU *pstruStdoutLogFile, _In_ STRU *pstruStdoutLogFile,
@ -290,5 +291,5 @@ private:
HANDLE m_hChildProcessWaitHandles[MAX_ACTIVE_CHILD_PROCESSES]; HANDLE m_hChildProcessWaitHandles[MAX_ACTIVE_CHILD_PROCESSES];
PROCESS_MANAGER *m_pProcessManager; PROCESS_MANAGER *m_pProcessManager;
ENVIRONMENT_VAR_HASH *m_pEnvironmentVarTable ; std::map<std::wstring, std::wstring, ignore_case_comparer> m_pEnvironmentVarTable;
}; };

View File

@ -4,12 +4,11 @@
#pragma once #pragma once
#define HOSTING_STARTUP_ASSEMBLIES_ENV_STR L"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES" #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 HOSTING_STARTUP_ASSEMBLIES_VALUE L"Microsoft.AspNetCore.Server.IISIntegration"
#define ASPNETCORE_IIS_AUTH_ENV_STR L"ASPNETCORE_IIS_HTTPAUTH=" #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_WEBSOCKETS_SUPPORTED_ENV_STR L"ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED"
#define ASPNETCORE_IIS_PHYSICAL_PATH_ENV_STR L"ASPNETCORE_IIS_PHYSICAL_PATH=" #define ASPNETCORE_IIS_PHYSICAL_PATH_ENV_STR L"ASPNETCORE_IIS_PHYSICAL_PATH"
#define ASPNETCORE_HTTPS_PORT_ENV_STR L"ASPNETCORE_HTTPS_PORT=" #define ASPNETCORE_HTTPS_PORT_ENV_STR L"ASPNETCORE_HTTPS_PORT"
#define ASPNETCORE_IIS_AUTH_WINDOWS L"windows;" #define ASPNETCORE_IIS_AUTH_WINDOWS L"windows;"
#define ASPNETCORE_IIS_AUTH_BASIC L"basic;" #define ASPNETCORE_IIS_AUTH_BASIC L"basic;"
#define ASPNETCORE_IIS_AUTH_ANONYMOUS L"anonymous;" #define ASPNETCORE_IIS_AUTH_ANONYMOUS L"anonymous;"

View File

@ -2,6 +2,8 @@
// Licensed under the MIT License. See License.txt in the project root for license information. // Licensed under the MIT License. See License.txt in the project root for license information.
#pragma once #pragma once
#include <map>
#include "Environment.h"
class ENVIRONMENT_VAR_HELPERS class ENVIRONMENT_VAR_HELPERS
{ {
@ -24,422 +26,77 @@ public:
} }
static static
VOID std::map<std::wstring, std::wstring, ignore_case_comparer>
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
InitEnvironmentVariablesTable InitEnvironmentVariablesTable
( (
_In_ ENVIRONMENT_VAR_HASH* pInEnvironmentVarTable, _In_ const std::map<std::wstring, std::wstring, ignore_case_comparer>& pInEnvironmentVarTable,
_In_ BOOL fWindowsAuthEnabled, _In_ BOOL fWindowsAuthEnabled,
_In_ BOOL fBasicAuthEnabled, _In_ BOOL fBasicAuthEnabled,
_In_ BOOL fAnonymousAuthEnabled, _In_ BOOL fAnonymousAuthEnabled,
_In_ BOOL fAddHostingStartup,
_In_ PCWSTR pApplicationPhysicalPath, _In_ PCWSTR pApplicationPhysicalPath,
_In_ PCWSTR pHttpsPort, _In_ PCWSTR pHttpsPort
_Out_ ENVIRONMENT_VAR_HASH** ppEnvironmentVarTable
) )
{ {
HRESULT hr = S_OK; std::map<std::wstring, std::wstring, ignore_case_comparer> environmentVariables = pInEnvironmentVarTable;
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;
pEnvironmentVarTable = new ENVIRONMENT_VAR_HASH(); environmentVariables.insert_or_assign(ASPNETCORE_IIS_PHYSICAL_PATH_ENV_STR, pApplicationPhysicalPath);
if (pHttpsPort)
//
// few environment variables expected, small bucket size for hash table
//
if (FAILED(hr = pEnvironmentVarTable->Initialize(37 /*prime*/)))
{ {
goto Finished; environmentVariables.try_emplace(ASPNETCORE_HTTPS_PORT_ENV_STR, pHttpsPort);
}
// 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);
} }
std::wstring strIisAuthEnvValue;
if (fWindowsAuthEnabled) if (fWindowsAuthEnabled)
{ {
strIisAuthEnvValue.Copy(ASPNETCORE_IIS_AUTH_WINDOWS); strIisAuthEnvValue.append(ASPNETCORE_IIS_AUTH_WINDOWS);
} }
if (fBasicAuthEnabled) if (fBasicAuthEnabled)
{ {
strIisAuthEnvValue.Append(ASPNETCORE_IIS_AUTH_BASIC); strIisAuthEnvValue.append(ASPNETCORE_IIS_AUTH_BASIC);
} }
if (fAnonymousAuthEnabled) 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()) environmentVariables.insert_or_assign(ASPNETCORE_IIS_AUTH_ENV_STR, strIisAuthEnvValue);
{
strIisAuthEnvValue.Copy(ASPNETCORE_IIS_AUTH_NONE);
}
pIISAuthEntry = new ENVIRONMENT_VAR_ENTRY(); if (fAddHostingStartup && environmentVariables.count(HOSTING_STARTUP_ASSEMBLIES_ENV_STR) == 0)
if (FAILED(hr = pIISAuthEntry->Initialize(ASPNETCORE_IIS_AUTH_ENV_STR, strIisAuthEnvValue.QueryStr())) ||
FAILED(hr = pEnvironmentVarTable->InsertRecord(pIISAuthEntry)))
{ {
goto Finished; auto hostingStartupValues = Environment::GetEnvironmentVariableValue(HOSTING_STARTUP_ASSEMBLIES_ENV_STR).value_or(L"");
}
// Compiler is complaining about conversion between PCWSTR and PWSTR here. if (hostingStartupValues.find(HOSTING_STARTUP_ASSEMBLIES_ENV_STR) == std::wstring::npos)
// 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)
{ {
hr = HRESULT_FROM_WIN32(dwError); hostingStartupValues += std::wstring(L";") + HOSTING_STARTUP_ASSEMBLIES_VALUE;
goto Finished;
} }
}
else if (dwResult > strStartupAssemblyEnv.QuerySizeCCH()) environmentVariables.insert_or_assign(HOSTING_STARTUP_ASSEMBLIES_ENV_STR, hostingStartupValues);
{
// 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;
} }
strStartupAssemblyEnv.SyncWithBuffer(); for (auto& environmentVariable : environmentVariables)
if (strStartupAssemblyEnv.IndexOf(HOSTING_STARTUP_ASSEMBLIES_VALUE) == -1)
{ {
if (fFound) environmentVariable.second = Environment::ExpandEnvironmentVariables(environmentVariable.second);
{
strStartupAssemblyEnv.Append(L";");
}
strStartupAssemblyEnv.Append(HOSTING_STARTUP_ASSEMBLIES_VALUE);
} }
// the environment variable was not defined, create it and add to hashtable return environmentVariables;
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;
} }
static static
HRESULT std::map<std::wstring, std::wstring, ignore_case_comparer>
AddWebsocketEnabledToEnvironmentVariables AddWebsocketEnabledToEnvironmentVariables
( (
_Inout_ ENVIRONMENT_VAR_HASH* pInEnvironmentVarTable, _Inout_ const std::map<std::wstring, std::wstring, ignore_case_comparer>& pInEnvironmentVarTable,
_In_ BOOL fWebsocketsEnabled _In_ BOOL fWebsocketsEnabled
) )
{ {
HRESULT hr = S_OK; std::map<std::wstring, std::wstring, ignore_case_comparer> environmentVariables = pInEnvironmentVarTable;
ENVIRONMENT_VAR_ENTRY* pIISWebsocketEntry = NULL; environmentVariables.insert_or_assign(ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED_ENV_STR, fWebsocketsEnabled ? L"true" : L"false");
STACK_STRU(strIISWebsocketEnvValue, 40); return environmentVariables;
// 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;
} }
public:
ENVIRONMENT_VAR_HELPERS();
~ENVIRONMENT_VAR_HELPERS();
}; };

View File

@ -15,13 +15,6 @@ REQUESTHANDLER_CONFIG::~REQUESTHANDLER_CONFIG()
delete[] m_ppStrArguments; delete[] m_ppStrArguments;
m_ppStrArguments = NULL; m_ppStrArguments = NULL;
} }
if (m_pEnvironmentVariables != NULL)
{
m_pEnvironmentVariables->Clear();
delete m_pEnvironmentVariables;
m_pEnvironmentVariables = NULL;
}
} }
HRESULT HRESULT
@ -100,12 +93,7 @@ REQUESTHANDLER_CONFIG::Populate(
IAppHostElement *pWindowsAuthenticationElement = NULL; IAppHostElement *pWindowsAuthenticationElement = NULL;
IAppHostElement *pBasicAuthenticationElement = NULL; IAppHostElement *pBasicAuthenticationElement = NULL;
IAppHostElement *pAnonymousAuthenticationElement = NULL; IAppHostElement *pAnonymousAuthenticationElement = NULL;
IAppHostElement *pEnvVarList = NULL;
IAppHostElement *pEnvVar = NULL;
IAppHostElementCollection *pEnvVarCollection = NULL;
ULONGLONG ullRawTimeSpan = 0; ULONGLONG ullRawTimeSpan = 0;
ENUM_INDEX index;
ENVIRONMENT_VAR_ENTRY* pEntry = NULL;
DWORD dwCounter = 0; DWORD dwCounter = 0;
DWORD dwPosition = 0; DWORD dwPosition = 0;
WCHAR* pszPath = NULL; WCHAR* pszPath = NULL;
@ -114,26 +102,20 @@ REQUESTHANDLER_CONFIG::Populate(
BSTR bstrAnonymousAuthSection = NULL; BSTR bstrAnonymousAuthSection = NULL;
BSTR bstrAspNetCoreSection = 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(); 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()); m_struHttpsPort.Copy(BindingInformation::GetHttpsPort(BindingInformation::Load(source, *pSite)).c_str());
} }
catch (...)
{ m_pEnvironmentVariables = source.GetSection(CS_ASPNETCORE_SECTION)->GetMap(CS_ASPNETCORE_ENVIRONMENT_VARIABLES);
FINISHED_IF_FAILED(OBSERVE_CAUGHT_EXCEPTION()); }
} catch (...)
{
FINISHED_IF_FAILED(OBSERVE_CAUGHT_EXCEPTION());
} }
hr = m_struConfigPath.Copy(pHttpApplication->GetAppConfigPath()); hr = m_struConfigPath.Copy(pHttpApplication->GetAppConfigPath());
@ -397,58 +379,6 @@ REQUESTHANDLER_CONFIG::Populate(
goto Finished; 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: Finished:
if (pAspNetCoreElement != NULL) if (pAspNetCoreElement != NULL)
@ -475,29 +405,5 @@ Finished:
pBasicAuthenticationElement = NULL; 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; return hr;
} }

View File

@ -68,7 +68,7 @@ public:
_Out_ REQUESTHANDLER_CONFIG **ppAspNetCoreConfig _Out_ REQUESTHANDLER_CONFIG **ppAspNetCoreConfig
); );
ENVIRONMENT_VAR_HASH* std::map<std::wstring, std::wstring, ignore_case_comparer>&
QueryEnvironmentVariables( QueryEnvironmentVariables(
VOID VOID
) )
@ -225,7 +225,6 @@ protected:
// //
REQUESTHANDLER_CONFIG() : REQUESTHANDLER_CONFIG() :
m_fStdoutLogEnabled(FALSE), m_fStdoutLogEnabled(FALSE),
m_pEnvironmentVariables(NULL),
m_hostingModel(HOSTING_UNKNOWN), m_hostingModel(HOSTING_UNKNOWN),
m_ppStrArguments(NULL) m_ppStrArguments(NULL)
{ {
@ -257,7 +256,7 @@ protected:
BOOL m_fBasicAuthEnabled; BOOL m_fBasicAuthEnabled;
BOOL m_fAnonymousAuthEnabled; BOOL m_fAnonymousAuthEnabled;
APP_HOSTING_MODEL m_hostingModel; APP_HOSTING_MODEL m_hostingModel;
ENVIRONMENT_VAR_HASH* m_pEnvironmentVariables; std::map<std::wstring, std::wstring, ignore_case_comparer> m_pEnvironmentVariables;
STRU m_struHostFxrLocation; STRU m_struHostFxrLocation;
PWSTR* m_ppStrArguments; PWSTR* m_ppStrArguments;
DWORD m_dwArgc; DWORD m_dwArgc;

View File

@ -2,50 +2,132 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Testing.xunit; using Microsoft.AspNetCore.Testing.xunit;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
{ {
[Collection(IISTestSiteCollection.Name)] [Collection(PublishedSitesCollection.Name)]
public class EnvironmentVariableTests: FixtureLoggedTest
{
private readonly IISTestSiteFixture _fixture;
public EnvironmentVariableTests(IISTestSiteFixture fixture): base(fixture) public class EnvironmentVariableTests: IISFunctionalTestBase
{
private readonly PublishedSitesFixture _fixture;
public EnvironmentVariableTests(PublishedSitesFixture fixture)
{ {
_fixture = fixture; _fixture = fixture;
} }
[ConditionalFact] [ConditionalTheory]
public async Task GetUniqueEnvironmentVariable() [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( Assert.Equal(
"AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative" + expectedValue,
"AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative" + await GetStringAsync(deploymentParameters, "/GetEnvironmentVariable?name=ASPNETCORE_INPROCESS_TESTING_LONG_VALUE"));
"AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative" +
"AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative" +
"AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative" +
"AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative",
await _fixture.Client.GetStringAsync("/CheckEnvironmentLongValueVariable"));
} }
[ConditionalFact] [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] [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"));
} }
} }
} }

View File

@ -45,6 +45,12 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
return result; 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() public override void Dispose()
{ {
StopServer(false); StopServer(false);

View File

@ -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) private async Task ReadAndWriteSynchronously(HttpContext ctx)
{ {
var t2 = Task.Run(() => WriteManyTimesToResponseBody(ctx)); var t2 = Task.Run(() => WriteManyTimesToResponseBody(ctx));

View File

@ -5,12 +5,6 @@
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" /> <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers> </handlers>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" hostingModel="inprocess"> <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> </aspNetCore>
</system.webServer> </system.webServer>
</configuration> </configuration>

View File

@ -134,5 +134,10 @@ namespace TestSite
GetDllDirectory(1024, builder); GetDllDirectory(1024, builder);
await context.Response.WriteAsync(builder.ToString()); await context.Response.WriteAsync(builder.ToString());
} }
private async Task GetEnvironmentVariable(HttpContext ctx)
{
await ctx.Response.WriteAsync(Environment.GetEnvironmentVariable(ctx.Request.Query["name"].ToString()));
}
} }
} }