From 6e68c03e5b1fd8c9214e8eebc56c7e684bdf8b8d Mon Sep 17 00:00:00 2001 From: Tomasz Janczuk Date: Wed, 11 Jan 2012 11:50:37 -0800 Subject: [PATCH] fix #87: provide access to iis server variables to the node.js application --- src/config/iisnode_schema.xml | 1 + src/config/iisnode_schema_x64.xml | 1 + src/iisnode/chttpprotocol.cpp | 23 +++- src/iisnode/cmoduleconfiguration.cpp | 116 +++++++++++++++++- src/iisnode/cmoduleconfiguration.h | 3 + src/iisnode/iisnode.vcxproj | 6 + src/iisnode/iisnode.vcxproj.filters | 24 ++++ src/samples/configuration/readme.htm | 5 + src/samples/configuration/web.config | 5 + test/functional/tests/119_servervars.js | 9 ++ test/functional/www/119_servervars/hello.js | 6 + test/functional/www/119_servervars/web.config | 11 ++ 12 files changed, 204 insertions(+), 6 deletions(-) create mode 100644 test/functional/tests/119_servervars.js create mode 100644 test/functional/www/119_servervars/hello.js create mode 100644 test/functional/www/119_servervars/web.config diff --git a/src/config/iisnode_schema.xml b/src/config/iisnode_schema.xml index c5e83dc..d4f1c59 100644 --- a/src/config/iisnode_schema.xml +++ b/src/config/iisnode_schema.xml @@ -52,5 +52,6 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + diff --git a/src/config/iisnode_schema_x64.xml b/src/config/iisnode_schema_x64.xml index ca2fb6f..13971dd 100644 --- a/src/config/iisnode_schema_x64.xml +++ b/src/config/iisnode_schema_x64.xml @@ -52,5 +52,6 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + diff --git a/src/iisnode/chttpprotocol.cpp b/src/iisnode/chttpprotocol.cpp index 7efb9c0..a04193e 100644 --- a/src/iisnode/chttpprotocol.cpp +++ b/src/iisnode/chttpprotocol.cpp @@ -94,6 +94,8 @@ HRESULT CHttpProtocol::SerializeRequestHeaders(CNodeHttpStoredContext* ctx, void DWORD remoteHostSize = INET6_ADDRSTRLEN + 1; char remoteHost[INET6_ADDRSTRLEN + 1]; BOOL addXFF; + char** serverVars; + int serverVarCount; CheckNull(ctx); CheckNull(result); @@ -107,7 +109,8 @@ HRESULT CHttpProtocol::SerializeRequestHeaders(CNodeHttpStoredContext* ctx, void IHttpRequest* request = context->GetRequest(); HTTP_REQUEST* raw = request->GetRawHttpRequest(); USHORT major, minor; - char tmp[256]; + const int tmpSize = 256; + char tmp[tmpSize]; PCSTR method = request->GetHttpMethod(); ErrorIf(NULL == (*result = context->AllocateRequestMemory(bufferLength)), ERROR_NOT_ENOUGH_MEMORY); @@ -192,6 +195,24 @@ HRESULT CHttpProtocol::SerializeRequestHeaders(CNodeHttpStoredContext* ctx, void CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset)); } + // promote server variables + + CheckError(CModuleConfiguration::GetPromoteServerVars(context, &serverVars, &serverVarCount)); + while (serverVarCount) + { + serverVarCount--; + PCSTR varValue; + DWORD varValueLength; + if (S_OK == context->GetServerVariable(serverVars[serverVarCount], &varValue, &varValueLength)) + { + CheckError(CHttpProtocol::Append(context, "X-iisnode-", 10, result, &bufferLength, &offset)); + CheckError(CHttpProtocol::Append(context, serverVars[serverVarCount], 0, result, &bufferLength, &offset)); + CheckError(CHttpProtocol::Append(context, ": ", 2, result, &bufferLength, &offset)); + CheckError(CHttpProtocol::Append(context, varValue, varValueLength, result, &bufferLength, &offset)); + CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset)); + } + } + // CRLF CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset)); diff --git a/src/iisnode/cmoduleconfiguration.cpp b/src/iisnode/cmoduleconfiguration.cpp index 0f623a4..7637ee4 100644 --- a/src/iisnode/cmoduleconfiguration.cpp +++ b/src/iisnode/cmoduleconfiguration.cpp @@ -7,7 +7,7 @@ HTTP_MODULE_ID CModuleConfiguration::moduleId = NULL; CModuleConfiguration::CModuleConfiguration() : nodeProcessCommandLine(NULL), logDirectoryNameSuffix(NULL), debuggerPathSegment(NULL), debugPortRange(NULL), debugPortStart(0), debugPortEnd(0), node_env(NULL), watchedFiles(NULL), - enableXFF(FALSE) + enableXFF(FALSE), promoteServerVars(NULL) { } @@ -42,6 +42,20 @@ CModuleConfiguration::~CModuleConfiguration() delete this->watchedFiles; this->watchedFiles = NULL; } + + if (NULL != this->promoteServerVars) + { + for (int i = 0; i < this->promoteServerVarsCount; i++) + { + if (this->promoteServerVars[i]) + { + delete [] this->promoteServerVars[i]; + } + } + + delete [] this->promoteServerVars; + this->promoteServerVars = NULL; + } } HRESULT CModuleConfiguration::Initialize(IHttpServer* server, HTTP_MODULE_ID moduleId) @@ -430,7 +444,10 @@ HRESULT CModuleConfiguration::GetConfig(IHttpContext* context, CModuleConfigurat IAppHostElement* section = NULL; LPWSTR commandLine = NULL; size_t i; - + size_t varLength; + LPWSTR serverVars = NULL; + LPWSTR start, end; + wchar_t terminator; CheckNull(config); *config = (CModuleConfiguration*)context->GetMetadata()->GetModuleContextContainer()->GetModuleContext(moduleId); @@ -461,15 +478,80 @@ HRESULT CModuleConfiguration::GetConfig(IHttpContext* context, CModuleConfigurat CheckError(GetBOOL(section, L"debuggingEnabled", &c->debuggingEnabled)); CheckError(GetString(section, L"node_env", &c->node_env)); CheckError(GetString(section, L"debuggerPortRange", &c->debugPortRange)); + CheckError(GetString(section, L"watchedFiles", &c->watchedFiles)); + CheckError(GetBOOL(section, L"enableXFF", &c->enableXFF)); + + // 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; - CheckError(GetString(section, L"watchedFiles", &c->watchedFiles)); - CheckError(GetBOOL(section, L"enableXFF", &c->enableXFF)); + + // promoteServerVars + + CheckError(GetString(section, L"promoteServerVars", &serverVars)); + if (*serverVars == L'\0') + { + c->promoteServerVarsCount = 0; + } + else + { + // determine number of server variables + + c->promoteServerVarsCount = 1; + start = serverVars; + while (*start) + { + if (L',' == *start) + { + c->promoteServerVarsCount++; + } + + start++; + } + + // tokenize server variable names (comma delimited list) + + ErrorIf(NULL == (c->promoteServerVars = new char*[c->promoteServerVarsCount]), ERROR_NOT_ENOUGH_MEMORY); + RtlZeroMemory(c->promoteServerVars, c->promoteServerVarsCount * sizeof(char*)); + + i = 0; + end = serverVars; + while (*end) + { + start = end; + while (*end && L',' != *end) + { + end++; + } + + if (start != end) + { + terminator = *end; + *end = L'\0'; + ErrorIf(0 != wcstombs_s(&varLength, NULL, 0, start, _TRUNCATE), ERROR_CAN_NOT_COMPLETE); + ErrorIf(NULL == (c->promoteServerVars[i] = new char[varLength]), ERROR_NOT_ENOUGH_MEMORY); + ErrorIf(0 != wcstombs_s(&varLength, c->promoteServerVars[i], varLength, start, _TRUNCATE), ERROR_CAN_NOT_COMPLETE); + i++; + *end = terminator; + } + + if (*end) + { + end++; + } + } + } + + delete [] serverVars; + serverVars = NULL; section->Release(); section = NULL; @@ -518,6 +600,12 @@ Error: commandLine = NULL; } + if (NULL != serverVars) + { + delete [] serverVars; + serverVars = NULL; + } + if (NULL != c) { delete c; @@ -670,7 +758,7 @@ HRESULT CModuleConfiguration::GetDebugPortRange(IHttpContext* ctx, DWORD* start, CheckNull(end); CModuleConfiguration* c = NULL; - GetConfig(ctx, &c); + CheckError(GetConfig(ctx, &c)); if (0 == c->debugPortStart) { @@ -705,3 +793,21 @@ Error: return hr; } + +HRESULT CModuleConfiguration::GetPromoteServerVars(IHttpContext* ctx, char*** vars, int* count) +{ + HRESULT hr; + + CheckNull(vars); + CheckNull(count); + + CModuleConfiguration* c = NULL; + CheckError(GetConfig(ctx, &c)); + + *vars = c->promoteServerVars; + *count = c->promoteServerVarsCount; + + return S_OK; +Error: + return hr; +} diff --git a/src/iisnode/cmoduleconfiguration.h b/src/iisnode/cmoduleconfiguration.h index 23ed30f..6b62c0b 100644 --- a/src/iisnode/cmoduleconfiguration.h +++ b/src/iisnode/cmoduleconfiguration.h @@ -35,6 +35,8 @@ private: DWORD maxNamedPipeConnectionPoolSize; DWORD maxNamedPipePooledConnectionAge; BOOL enableXFF; + char** promoteServerVars; + int promoteServerVarsCount; static IHttpServer* server; static HTTP_MODULE_ID moduleId; @@ -78,6 +80,7 @@ public: static DWORD GetMaxNamedPipeConnectionPoolSize(IHttpContext* ctx); static DWORD GetMaxNamedPipePooledConnectionAge(IHttpContext* ctx); static BOOL GetEnableXFF(IHttpContext* ctx); + static HRESULT GetPromoteServerVars(IHttpContext* ctx, char*** vars, int* count); static HRESULT CreateNodeEnvironment(IHttpContext* ctx, DWORD debugPort, PCH namedPipe, PCH* env); diff --git a/src/iisnode/iisnode.vcxproj b/src/iisnode/iisnode.vcxproj index 487bfa3..6f0dca8 100644 --- a/src/iisnode/iisnode.vcxproj +++ b/src/iisnode/iisnode.vcxproj @@ -251,6 +251,8 @@ copy /y $(ProjectDir)\..\config\* $(ProjectDir)\..\..\build\$(Configuration)\$(P + + @@ -298,6 +300,10 @@ copy /y $(ProjectDir)\..\config\* $(ProjectDir)\..\..\build\$(Configuration)\$(P + + + + diff --git a/src/iisnode/iisnode.vcxproj.filters b/src/iisnode/iisnode.vcxproj.filters index 0641a00..8ca6b3a 100644 --- a/src/iisnode/iisnode.vcxproj.filters +++ b/src/iisnode/iisnode.vcxproj.filters @@ -120,6 +120,12 @@ {ac86a901-4e59-4b58-82ce-a7674d8c587c} + + {dd3b1edf-b406-49ff-988a-4b417fe9ce3c} + + + {4595469d-4085-4631-836b-08584244a9e7} + @@ -528,6 +534,24 @@ Tests\functional\www\117_autoupdate_dependency + + Tests\functional\tests + + + Tests\functional\www\118_xff + + + Tests\functional\www\118_xff + + + Tests\functional\tests + + + Tests\functional\www\119_servervars + + + Tests\functional\www\119_servervars + diff --git a/src/samples/configuration/readme.htm b/src/samples/configuration/readme.htm index 97c1513..5bb0e66 100644 --- a/src/samples/configuration/readme.htm +++ b/src/samples/configuration/readme.htm @@ -125,6 +125,10 @@ console.log('Application started at location ' + process.env.PORT); CPU cost but may improve latency in streaming scenarios * enableXFF - controls whether iisnode adds or modifies the X-Forwarded-For request HTTP header with the IP address of the remote host + + * promoteServerVars - comma delimited list of IIS server variables that will be propagated to the node.exe process in the form of + x-iisnode-<server_variable_name> HTTP request headers; for a list of IIS server variables available see + http://msdn.microsoft.com/en-us/library/ms524602(v=vs.90).aspx; for example "AUTH_USER,AUTH_TYPE" --> @@ -152,6 +156,7 @@ console.log('Application started at location ' + process.env.PORT); devErrorsEnabled="true" flushResponse="false" enableXFF="false" + promoteServerVars="" /> <!-- diff --git a/src/samples/configuration/web.config b/src/samples/configuration/web.config index a85e16c..36465d4 100644 --- a/src/samples/configuration/web.config +++ b/src/samples/configuration/web.config @@ -91,6 +91,10 @@ CPU cost but may improve latency in streaming scenarios * enableXFF - controls whether iisnode adds or modifies the X-Forwarded-For request HTTP header with the IP address of the remote host + + * promoteServerVars - comma delimited list of IIS server variables that will be propagated to the node.exe process in the form of + x-iisnode- HTTP request headers; for a list of IIS server variables available see + http://msdn.microsoft.com/en-us/library/ms524602(v=vs.90).aspx; for example "AUTH_USER,AUTH_TYPE" --> @@ -119,6 +123,7 @@ devErrorsEnabled="true" flushResponse="false" enableXFF="false" + promoteServerVars="" />