Skip to content

Commit

Permalink
fix #179: support for unicode file names
Browse files Browse the repository at this point in the history
  • Loading branch information
tjanczuk committed Jul 11, 2012
1 parent a1a8c26 commit 86564d3
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 114 deletions.
61 changes: 6 additions & 55 deletions src/iisnode/cmoduleconfiguration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -690,39 +690,11 @@ HRESULT CModuleConfiguration::ApplyConfigOverrideKeyValue(IHttpContext* context,
}
else if (0 == strcmpi(keyStart, "nodeProcessCommandLine"))
{
if (config->nodeProcessCommandLine)
{
delete [] config->nodeProcessCommandLine;
config->nodeProcessCommandLine = NULL;
}

ErrorIf(NULL == (config->nodeProcessCommandLine = new char[MAX_PATH]), ERROR_NOT_ENOUGH_MEMORY);
if (valueStart)
{
strcpy(config->nodeProcessCommandLine, valueStart);
}
else
{
strcpy(config->nodeProcessCommandLine, "");
}
CheckError(GetString(valueStart, &config->nodeProcessCommandLine));
}
else if (0 == strcmpi(keyStart, "interceptor"))
{
if (config->interceptor)
{
delete [] config->interceptor;
config->interceptor = NULL;
}

ErrorIf(NULL == (config->interceptor = new char[MAX_PATH]), ERROR_NOT_ENOUGH_MEMORY);
if (valueStart)
{
strcpy(config->interceptor, valueStart);
}
else
{
strcpy(config->interceptor, "");
}
CheckError(GetString(valueStart, &config->interceptor));
}

return S_OK;
Expand Down Expand Up @@ -1036,7 +1008,6 @@ HRESULT CModuleConfiguration::GetConfig(IHttpContext* context, CModuleConfigurat
HRESULT hr;
CModuleConfiguration* c = NULL;
IAppHostElement* section = NULL;
LPWSTR commandLine = NULL;
size_t i;
CheckNull(config);

Expand Down Expand Up @@ -1074,28 +1045,14 @@ HRESULT CModuleConfiguration::GetConfig(IHttpContext* context, CModuleConfigurat
CheckError(GetBOOL(section, L"enableXFF", &c->enableXFF));
CheckError(GetString(section, L"promoteServerVars", &c->promoteServerVarsRaw));
CheckError(GetString(section, L"configOverrides", &c->configOverrides));
CheckError(GetString(section, L"nodeProcessCommandLine", &c->nodeProcessCommandLine));
CheckError(GetString(section, L"interceptor", &c->interceptor));

// debuggerPathSegment

CheckError(GetString(section, L"debuggerPathSegment", &c->debuggerPathSegment));
c->debuggerPathSegmentLength = wcslen(c->debuggerPathSegment);

// nodeProcessCommandLine

CheckError(GetString(section, L"nodeProcessCommandLine", &commandLine));
ErrorIf(NULL == (c->nodeProcessCommandLine = new char[MAX_PATH]), ERROR_NOT_ENOUGH_MEMORY);
ErrorIf(0 != wcstombs_s(&i, c->nodeProcessCommandLine, (size_t)MAX_PATH, commandLine, _TRUNCATE), ERROR_INVALID_PARAMETER);
delete [] commandLine;
commandLine = NULL;

// interceptor

CheckError(GetString(section, L"interceptor", &commandLine));
ErrorIf(NULL == (c->interceptor = new char[MAX_PATH]), ERROR_NOT_ENOUGH_MEMORY);
ErrorIf(0 != wcstombs_s(&i, c->interceptor, (size_t)MAX_PATH, commandLine, _TRUNCATE), ERROR_INVALID_PARAMETER);
delete [] commandLine;
commandLine = NULL;

// apply config setting overrides from the optional YAML configuration file

CheckError(CModuleConfiguration::ApplyYamlConfigOverrides(context, c));
Expand Down Expand Up @@ -1129,12 +1086,6 @@ HRESULT CModuleConfiguration::GetConfig(IHttpContext* context, CModuleConfigurat
section = NULL;
}

if (NULL != commandLine)
{
delete [] commandLine;
commandLine = NULL;
}

if (NULL != c)
{
delete c;
Expand Down Expand Up @@ -1164,12 +1115,12 @@ DWORD CModuleConfiguration::GetNodeProcessCountPerApplication(IHttpContext* ctx)
GETCONFIG(nodeProcessCountPerApplication)
}

LPCTSTR CModuleConfiguration::GetNodeProcessCommandLine(IHttpContext* ctx)
LPWSTR CModuleConfiguration::GetNodeProcessCommandLine(IHttpContext* ctx)
{
GETCONFIG(nodeProcessCommandLine)
}

LPCTSTR CModuleConfiguration::GetInterceptor(IHttpContext* ctx)
LPWSTR CModuleConfiguration::GetInterceptor(IHttpContext* ctx)
{
GETCONFIG(interceptor)
}
Expand Down
8 changes: 4 additions & 4 deletions src/iisnode/cmoduleconfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ class CModuleConfiguration : public IHttpStoredContext

DWORD asyncCompletionThreadCount;
DWORD nodeProcessCountPerApplication;
LPTSTR nodeProcessCommandLine;
LPTSTR interceptor;
LPWSTR nodeProcessCommandLine;
LPWSTR interceptor;
DWORD maxConcurrentRequestsPerProcess;
DWORD maxNamedPipeConnectionRetry;
DWORD namedPipeConnectionRetryDelay;
Expand Down Expand Up @@ -70,8 +70,8 @@ class CModuleConfiguration : public IHttpStoredContext

static DWORD GetAsyncCompletionThreadCount(IHttpContext* ctx);
static DWORD GetNodeProcessCountPerApplication(IHttpContext* ctx);
static LPCTSTR GetNodeProcessCommandLine(IHttpContext* ctx);
static LPCTSTR GetInterceptor(IHttpContext* ctx);
static LPWSTR GetNodeProcessCommandLine(IHttpContext* ctx);
static LPWSTR GetInterceptor(IHttpContext* ctx);
static DWORD GetMaxConcurrentRequestsPerProcess(IHttpContext* ctx);
static DWORD GetMaxNamedPipeConnectionRetry(IHttpContext* ctx);
static DWORD GetNamedPipeConnectionRetryDelay(IHttpContext* ctx);
Expand Down
68 changes: 28 additions & 40 deletions src/iisnode/cnodeprocess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,18 @@ HRESULT CNodeProcess::Initialize(IHttpContext* context)
HRESULT hr;
UUID uuid;
RPC_CSTR suuid = NULL;
LPTSTR fullCommandLine = NULL;
LPCTSTR coreCommandLine;
LPCTSTR interceptor;
LPWSTR fullCommandLine = NULL;
LPCWSTR coreCommandLine;
LPCWSTR interceptor;
PCWSTR scriptName;
size_t coreCommandLineLength, scriptNameLength, scriptNameLengthW, interceptorLength;
PROCESS_INFORMATION processInformation;
DWORD exitCode = S_OK;
LPCH newEnvironment = NULL;
DWORD flags;
HANDLE job;
PWSTR currentDirectory = NULL;
PSTR currentDirectoryA = NULL;
PWSTR scriptTranslated = NULL;
DWORD currentDirectorySize = 0;
DWORD currentDirectorySizeA = 0;
CNodeApplication* app = this->GetProcessManager()->GetApplication();

RtlZeroMemory(&processInformation, sizeof processInformation);
Expand All @@ -80,53 +78,44 @@ HRESULT CNodeProcess::Initialize(IHttpContext* context)
// build the full command line for the node.js process

interceptor = CModuleConfiguration::GetInterceptor(context);
interceptorLength = strlen(interceptor);
coreCommandLine = CModuleConfiguration::GetNodeProcessCommandLine(context);
scriptName = this->GetProcessManager()->GetApplication()->GetScriptName();
coreCommandLineLength = _tcslen(coreCommandLine);
scriptNameLengthW = wcslen(scriptName) + 1;
ErrorIf(0 != wcstombs_s(&scriptNameLength, NULL, 0, scriptName, _TRUNCATE), ERROR_CAN_NOT_COMPLETE);
// allocate memory for command line to allow for debugging options plus interceptor plus spaces and enclosing the script name in quotes
ErrorIf(NULL == (fullCommandLine = new TCHAR[coreCommandLineLength + interceptorLength + scriptNameLength + 256]), ERROR_NOT_ENOUGH_MEMORY);
_tcscpy(fullCommandLine, coreCommandLine);
DWORD offset = 0;
ErrorIf(NULL == (fullCommandLine = new WCHAR[wcslen(coreCommandLine) + wcslen(interceptor) + wcslen(scriptName) + 256]), ERROR_NOT_ENOUGH_MEMORY);
wcscpy(fullCommandLine, coreCommandLine);

// add debug options
if (app->IsDebuggee())
{
char buffer[64];
WCHAR buffer[64];

if (ND_DEBUG_BRK == app->GetDebugCommand())
{
sprintf(buffer, " --debug-brk=%d ", app->GetDebugPort());
swprintf(buffer, L" --debug-brk=%d ", app->GetDebugPort());
}
else if (ND_DEBUG == app->GetDebugCommand())
{
sprintf(buffer, " --debug=%d ", app->GetDebugPort());
swprintf(buffer, L" --debug=%d ", app->GetDebugPort());
}
else
{
CheckError(ERROR_INVALID_PARAMETER);
}

_tcscat(fullCommandLine, buffer);
offset += strlen(buffer);
wcscat(fullCommandLine, buffer);
}

if (!app->IsDebugger())
{
// add interceptor
_tcscat(fullCommandLine, _T(" "));
offset += 1;
_tcscat(fullCommandLine, interceptor);
offset += interceptorLength;
wcscat(fullCommandLine, L" ");
wcscat(fullCommandLine, interceptor);
}

// add application entry point
_tcscat(fullCommandLine, _T(" \""));
offset += 2;
ErrorIf(0 != wcstombs_s(&scriptNameLength, fullCommandLine + coreCommandLineLength + offset, scriptNameLength, scriptName, _TRUNCATE), ERROR_CAN_NOT_COMPLETE);
_tcscat(fullCommandLine, _T("\""));
wcscat(fullCommandLine, L" \"");
wcscat(fullCommandLine, scriptName);
wcscat(fullCommandLine, L"\"");

// create the environment block for the node.js process

Expand All @@ -139,18 +128,17 @@ HRESULT CNodeProcess::Initialize(IHttpContext* context)
// establish the current directory for node.exe process to be the same as the location of the application *.js file
// (in case of the debugger process, it is still the debuggee application file)

currentDirectory = (PWSTR)context->GetScriptTranslated(&currentDirectorySize);
while (currentDirectorySize && currentDirectory[currentDirectorySize] != L'\\' && currentDirectory[currentDirectorySize] != L'/')
scriptTranslated = (PWSTR)context->GetScriptTranslated(&currentDirectorySize);
while (currentDirectorySize && scriptTranslated[currentDirectorySize] != L'\\' && scriptTranslated[currentDirectorySize] != L'/')
currentDirectorySize--;
ErrorIf(0 == (currentDirectorySizeA = WideCharToMultiByte(CP_ACP, 0, currentDirectory, currentDirectorySize, NULL, 0, NULL, NULL)), E_FAIL);
ErrorIf(NULL == (currentDirectoryA = new char[currentDirectorySize + 1]), ERROR_NOT_ENOUGH_MEMORY);
ErrorIf(currentDirectorySizeA != WideCharToMultiByte(CP_ACP, 0, currentDirectory, currentDirectorySize, currentDirectoryA, currentDirectorySizeA, NULL, NULL), E_FAIL);
currentDirectoryA[currentDirectorySizeA] = '\0';
ErrorIf(NULL == (currentDirectory = new WCHAR[wcslen(scriptTranslated) + 1]), ERROR_NOT_ENOUGH_MEMORY);
wcscpy(currentDirectory, scriptTranslated);
currentDirectory[currentDirectorySize] = L'\0';

// create startup info for the node.js process

RtlZeroMemory(&this->startupInfo, sizeof this->startupInfo);
GetStartupInfo(&startupInfo);
GetStartupInfoW(&startupInfo);
CheckError(this->CreateStdHandles(context));

// create process watcher thread in a suspended state
Expand All @@ -172,15 +160,15 @@ HRESULT CNodeProcess::Initialize(IHttpContext* context)
flags |= CREATE_BREAKAWAY_FROM_JOB;
}

if(!CreateProcess(
if(!CreateProcessW(
NULL,
fullCommandLine,
NULL,
NULL,
TRUE,
flags,
newEnvironment,
currentDirectoryA,
currentDirectory,
&this->startupInfo,
&processInformation))
{
Expand Down Expand Up @@ -211,8 +199,8 @@ HRESULT CNodeProcess::Initialize(IHttpContext* context)

// clean up

delete [] currentDirectoryA;
currentDirectoryA = NULL;
delete [] currentDirectory;
currentDirectory = NULL;
delete [] newEnvironment;
newEnvironment = NULL;
delete [] fullCommandLine;
Expand Down Expand Up @@ -245,10 +233,10 @@ HRESULT CNodeProcess::Initialize(IHttpContext* context)
L"iisnode failed to initialize a new node.exe process", WINEVENT_LEVEL_ERROR);
}

if (currentDirectoryA)
if (currentDirectory)
{
delete [] currentDirectoryA;
currentDirectoryA = NULL;
delete [] currentDirectory;
currentDirectory = NULL;
}

if (suuid != NULL)
Expand Down
2 changes: 1 addition & 1 deletion src/iisnode/cnodeprocess.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class CNodeProcess
HANDLE processWatcher;
DWORD maxConcurrentRequestsPerProcess;
BOOL isClosing;
STARTUPINFO startupInfo;
STARTUPINFOW startupInfo;
BOOL hasProcessExited;
OVERLAPPED overlapped;
CConnectionPool connectionPool;
Expand Down
15 changes: 1 addition & 14 deletions src/iisnode/cprotocolbridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,25 +160,12 @@ BOOL CProtocolBridge::SendIisnodeError(IHttpContext* httpCtx, HRESULT hr)
break;

case IISNODE_ERROR_UNABLE_TO_START_NODE_EXE:
LPCTSTR commandLine = CModuleConfiguration::GetNodeProcessCommandLine(httpCtx);
char* errorMessage;
if (NULL == (errorMessage = (char*)httpCtx->AllocateRequestMemory(strlen(commandLine) + 512)))
{
errorMessage =
char* errorMessage =
"The iisnode module is unable to start the node.exe process. Make sure the node.exe executable is available "
"at the location specified in the <a href=""https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config"">"
"system.webServer/iisnode/@nodeProcessCommandLine</a> element of web.config. "
"By default node.exe is expected to be installed in %ProgramFiles%\\nodejs folder on x86 systems and "
"%ProgramFiles(x86)%\\nodejs folder on x64 systems.";
}
else
{
sprintf(errorMessage,
"The iisnode module is unable to start the node.exe process. Make sure the node.exe executable is available "
"at the location specified in the <a href=""https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config"">"
"system.webServer/iisnode/@nodeProcessCommandLine</a> element of web.config. "
"The command line iisnode attempted to run was:<br><br>%s", commandLine);
}

CProtocolBridge::SendSyncResponse(
httpCtx,
Expand Down

0 comments on commit 86564d3

Please sign in to comment.