Add a flag to set current directory in ANCM InProc (#4369)

This commit is contained in:
Pavel Krymets 2018-12-06 15:19:47 -08:00 committed by GitHub
parent 50ea144c57
commit 24e17eadca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 157 additions and 21 deletions

View File

@ -23,6 +23,7 @@
#define CS_ASPNETCORE_HOSTING_MODEL_INPROCESS L"inprocess"
#define CS_ASPNETCORE_HOSTING_MODEL L"hostingModel"
#define CS_ASPNETCORE_HANDLER_SETTINGS L"handlerSettings"
#define CS_ASPNETCORE_HANDLER_SET_CURRENT_DIRECTORY L"setCurrentDirectory"
#define CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE L"disableStartUpErrorPage"
#define CS_ENABLED L"enabled"

View File

@ -60,3 +60,52 @@ Environment::GetEnvironmentVariableValue(const std::wstring & str)
return expandedStr;
}
std::wstring Environment::GetCurrentDirectoryValue()
{
DWORD requestedSize = GetCurrentDirectory(0, nullptr);
if (requestedSize == 0)
{
throw std::system_error(GetLastError(), std::system_category(), "GetCurrentDirectory");
}
std::wstring expandedStr;
do
{
expandedStr.resize(requestedSize);
requestedSize = GetCurrentDirectory(requestedSize, expandedStr.data());
if (requestedSize == 0)
{
throw std::system_error(GetLastError(), std::system_category(), "GetCurrentDirectory");
}
} while (expandedStr.size() != requestedSize + 1);
expandedStr.resize(requestedSize);
return expandedStr;
}
std::wstring Environment::GetDllDirectoryValue()
{
DWORD requestedSize = GetDllDirectory(0, nullptr);
if (requestedSize == 0)
{
throw std::system_error(GetLastError(), std::system_category(), "GetDllDirectory");
}
std::wstring expandedStr;
do
{
expandedStr.resize(requestedSize);
requestedSize = GetDllDirectory(requestedSize, expandedStr.data());
// 0 might be returned if GetDllDirectory is empty
if (requestedSize == 0 && GetLastError() != 0)
{
throw std::system_error(GetLastError(), std::system_category(), "GetDllDirectory");
}
} while (expandedStr.size() != requestedSize + 1);
expandedStr.resize(requestedSize);
return expandedStr;
}

View File

@ -16,5 +16,9 @@ public:
std::wstring ExpandEnvironmentVariables(const std::wstring & str);
static
std::optional<std::wstring> GetEnvironmentVariableValue(const std::wstring & str);
static
std::wstring GetCurrentDirectoryValue();
static
std::wstring GetDllDirectoryValue();
};

View File

@ -53,6 +53,10 @@ InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSourc
m_struStdoutLogFile = aspNetCoreSection->GetRequiredString(CS_ASPNETCORE_STDOUT_LOG_FILE);
m_fDisableStartUpErrorPage = aspNetCoreSection->GetRequiredBool(CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE);
m_environmentVariables = aspNetCoreSection->GetKeyValuePairs(CS_ASPNETCORE_ENVIRONMENT_VARIABLES);
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"false"), L"true");
m_dwStartupTimeLimitInMS = aspNetCoreSection->GetRequiredLong(CS_ASPNETCORE_PROCESS_STARTUP_TIME_LIMIT) * 1000;
m_dwShutdownTimeLimitInMS = aspNetCoreSection->GetRequiredLong(CS_ASPNETCORE_PROCESS_SHUTDOWN_TIME_LIMIT) * 1000;

View File

@ -40,6 +40,12 @@ public:
return m_fDisableStartUpErrorPage;
}
bool
QuerySetCurrentDirectory() const
{
return m_fSetCurrentDirectory;
}
bool
QueryWindowsAuthEnabled() const
{
@ -87,7 +93,7 @@ public:
}
InProcessOptions(const ConfigurationSource &configurationSource);
static
HRESULT InProcessOptions::Create(
IHttpServer& pServer,
@ -100,6 +106,7 @@ private:
std::wstring m_struStdoutLogFile;
bool m_fStdoutLogEnabled;
bool m_fDisableStartUpErrorPage;
bool m_fSetCurrentDirectory;
bool m_fWindowsAuthEnabled;
bool m_fBasicAuthEnabled;
bool m_fAnonymousAuthEnabled;

View File

@ -11,6 +11,7 @@
#include "resources.h"
#include "EventLog.h"
#include "ModuleHelpers.h"
#include "Environment.h"
IN_PROCESS_APPLICATION* IN_PROCESS_APPLICATION::s_Application = NULL;
@ -218,6 +219,25 @@ IN_PROCESS_APPLICATION::ExecuteApplication()
// set the callbacks
s_Application = this;
if (m_pConfig->QuerySetCurrentDirectory())
{
auto dllDirectory = Environment::GetDllDirectoryValue();
auto currentDirectory = Environment::GetCurrentDirectoryValue();
LOG_INFOF(L"Initial Dll directory: '%s', current directory: '%s'", dllDirectory.c_str(), currentDirectory.c_str());
// If DllDirectory wasn't set change it to previous current directory value
if (dllDirectory.empty())
{
LOG_LAST_ERROR_IF(!SetDllDirectory(currentDirectory.c_str()));
LOG_INFOF(L"Setting dll directory to %s", currentDirectory.c_str());
}
LOG_LAST_ERROR_IF(!SetCurrentDirectory(this->QueryApplicationPhysicalPath().c_str()));
LOG_INFOF(L"Setting current directory to %s", this->QueryApplicationPhysicalPath().c_str());
}
//Start CLR thread
m_clrThread = std::thread(ClrThreadEntryPoint, context);
@ -405,6 +425,7 @@ 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
@ -422,6 +443,7 @@ IN_PROCESS_APPLICATION::SetEnvironmentVariablesOnWorkerProcess()
m_pConfig->QueryWindowsAuthEnabled(),
m_pConfig->QueryBasicAuthEnabled(),
m_pConfig->QueryAnonymousAuthEnabled(),
QueryApplicationPhysicalPath().c_str(),
&pHashTable));
table.reset(pHashTable);

View File

@ -785,6 +785,7 @@ SERVER_PROCESS::StartProcess(
m_fWindowsAuthEnabled,
m_fBasicAuthEnabled,
m_fAnonymousAuthEnabled,
m_struAppFullPath.QueryStr(),
&pHashTable)))
{
pStrStage = L"InitEnvironmentVariablesTable";

View File

@ -8,6 +8,7 @@
#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_IIS_AUTH_WINDOWS L"windows;"
#define ASPNETCORE_IIS_AUTH_BASIC L"basic;"
#define ASPNETCORE_IIS_AUTH_ANONYMOUS L"anonymous;"

View File

@ -191,6 +191,7 @@ public:
_In_ BOOL fWindowsAuthEnabled,
_In_ BOOL fBasicAuthEnabled,
_In_ BOOL fAnonymousAuthEnabled,
_In_ PCWSTR pApplicationPhysicalPath,
_Out_ ENVIRONMENT_VAR_HASH** ppEnvironmentVarTable
)
{
@ -201,6 +202,7 @@ public:
STACK_STRU(strStartupAssemblyEnv, 1024);
ENVIRONMENT_VAR_ENTRY* pHostingEntry = NULL;
ENVIRONMENT_VAR_ENTRY* pIISAuthEntry = NULL;
ENVIRONMENT_VAR_ENTRY* pIISPathEntry = NULL;
ENVIRONMENT_VAR_HASH* pEnvironmentVarTable = NULL;
pEnvironmentVarTable = new ENVIRONMENT_VAR_HASH();
@ -213,7 +215,7 @@ public:
goto Finished;
}
// copy the envirable hash table (from configuration) to a temp one as we may need to remove elements
// 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())
{
@ -222,6 +224,22 @@ public:
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;
}
pEnvironmentVarTable->FindKey((PWSTR)ASPNETCORE_IIS_AUTH_ENV_STR, &pIISAuthEntry);
if (pIISAuthEntry != NULL)
{
@ -259,7 +277,7 @@ public:
}
// Compiler is complaining about conversion between PCWSTR and PWSTR here.
// Explictly casting.
// Explictly casting.
pEnvironmentVarTable->FindKey((PWSTR)HOSTING_STARTUP_ASSEMBLIES_NAME, &pHostingEntry);
if (pHostingEntry != NULL)
{

View File

@ -20,14 +20,14 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
}
[ConditionalFact]
[RequiresIIS(IISCapability.ShutdownToken)]
[RequiresNewHandler]
public async Task HostingEnvironmentIsCorrect()
{
Assert.Equal(
$"ContentRootPath {_fixture.DeploymentResult.ContentRoot}" + Environment.NewLine +
$"WebRootPath {_fixture.DeploymentResult.ContentRoot}\\wwwroot" + Environment.NewLine +
$"CurrentDirectory {Path.GetDirectoryName(_fixture.DeploymentResult.HostProcess.MainModule.FileName)}",
await _fixture.Client.GetStringAsync("/HostingEnvironment"));
Assert.Equal(_fixture.DeploymentResult.ContentRoot, await _fixture.Client.GetStringAsync("/ContentRootPath"));
Assert.Equal(_fixture.DeploymentResult.ContentRoot + "\\wwwroot", await _fixture.Client.GetStringAsync("/WebRootPath"));
Assert.Equal(Path.GetDirectoryName(_fixture.DeploymentResult.HostProcess.MainModule.FileName), await _fixture.Client.GetStringAsync("/CurrentDirectory"));
Assert.Equal(_fixture.DeploymentResult.ContentRoot + "\\", await _fixture.Client.GetStringAsync("/BaseDirectory"));
Assert.Equal(_fixture.DeploymentResult.ContentRoot + "\\", await _fixture.Client.GetStringAsync("/ASPNETCORE_IIS_PHYSICAL_PATH"));
}
}
}

View File

@ -449,6 +449,23 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
return dictionary;
}
[ConditionalFact]
[RequiresNewHandler]
public async Task SetCurrentDirectoryHandlerSettingWorks()
{
var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
deploymentParameters.HandlerSettings["SetCurrentDirectory"] = "true";
var deploymentResult = await DeployAsync(deploymentParameters);
Assert.Equal(deploymentResult.ContentRoot, await deploymentResult.HttpClient.GetStringAsync("/ContentRootPath"));
Assert.Equal(deploymentResult.ContentRoot + "\\wwwroot", await deploymentResult.HttpClient.GetStringAsync("/WebRootPath"));
Assert.Equal(deploymentResult.ContentRoot, await deploymentResult.HttpClient.GetStringAsync("/CurrentDirectory"));
Assert.Equal(deploymentResult.ContentRoot + "\\", await deploymentResult.HttpClient.GetStringAsync("/BaseDirectory"));
Assert.Equal(deploymentResult.ContentRoot + "\\", await deploymentResult.HttpClient.GetStringAsync("/ASPNETCORE_IIS_PHYSICAL_PATH"));
Assert.Equal(Path.GetDirectoryName(deploymentResult.HostProcess.MainModule.FileName), await deploymentResult.HttpClient.GetStringAsync("/DllDirectory"));
}
private static void MoveApplication(
IISDeploymentParameters parameters,
string subdirectory)

View File

@ -3,6 +3,7 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
@ -68,11 +69,9 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
Assert.Equal("null", responseText);
Assert.Equal(
$"ContentRootPath {deploymentResult.ContentRoot}" + Environment.NewLine +
$"WebRootPath {deploymentResult.ContentRoot}\\wwwroot" + Environment.NewLine +
$"CurrentDirectory {deploymentResult.ContentRoot}",
await deploymentResult.HttpClient.GetStringAsync("/HostingEnvironment"));
Assert.Equal(deploymentResult.ContentRoot, await deploymentResult.HttpClient.GetStringAsync("/ContentRootPath"));
Assert.Equal(deploymentResult.ContentRoot + "\\wwwroot", await deploymentResult.HttpClient.GetStringAsync("/WebRootPath"));
Assert.Equal(deploymentResult.ContentRoot, await deploymentResult.HttpClient.GetStringAsync("/CurrentDirectory"));
var expectedDll = variant.AncmVersion == AncmVersion.AspNetCoreModule ? "aspnetcore.dll" : "aspnetcorev2.dll";
Assert.Contains(deploymentResult.HostProcess.Modules.OfType<ProcessModule>(), m=> m.FileName.Contains(expectedDll));

View File

@ -4,6 +4,8 @@
using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
@ -21,14 +23,15 @@ namespace TestSite
serviceCollection.AddResponseCompression();
}
private async Task HostingEnvironment(HttpContext ctx)
{
var hostingEnv = ctx.RequestServices.GetService<IHostingEnvironment>();
private async Task ContentRootPath(HttpContext ctx) => await ctx.Response.WriteAsync(ctx.RequestServices.GetService<IHostingEnvironment>().ContentRootPath);
await ctx.Response.WriteAsync("ContentRootPath " + hostingEnv.ContentRootPath + Environment.NewLine);
await ctx.Response.WriteAsync("WebRootPath " + hostingEnv.WebRootPath + Environment.NewLine);
await ctx.Response.WriteAsync("CurrentDirectory " + Environment.CurrentDirectory);
}
private async Task WebRootPath(HttpContext ctx) => await ctx.Response.WriteAsync(ctx.RequestServices.GetService<IHostingEnvironment>().WebRootPath);
private async Task CurrentDirectory(HttpContext ctx) => await ctx.Response.WriteAsync(Environment.CurrentDirectory);
private async Task BaseDirectory(HttpContext ctx) => await ctx.Response.WriteAsync(AppContext.BaseDirectory);
private async Task ASPNETCORE_IIS_PHYSICAL_PATH(HttpContext ctx) => await ctx.Response.WriteAsync(Environment.GetEnvironmentVariable("ASPNETCORE_IIS_PHYSICAL_PATH"));
private async Task ConsoleWrite(HttpContext ctx)
{
@ -113,5 +116,15 @@ namespace TestSite
await context.Response.Body.WriteAsync(new byte[100], 0, 100);
});
}
[DllImport("kernel32.dll")]
static extern uint GetDllDirectory(uint nBufferLength, [Out] StringBuilder lpBuffer);
private async Task DllDirectory(HttpContext context)
{
var builder = new StringBuilder(1024);
GetDllDirectory(1024, builder);
await context.Response.WriteAsync(builder.ToString());
}
}
}