Skip to content

Commit

Permalink
fix #87: provide access to iis server variables to the node.js applic…
Browse files Browse the repository at this point in the history
…ation
  • Loading branch information
tjanczuk committed Jan 11, 2012
1 parent b5f9557 commit 6e68c03
Show file tree
Hide file tree
Showing 12 changed files with 204 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/config/iisnode_schema.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,6 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/
<attribute name="flushResponse" type="bool" defaultValue="false"/>
<attribute name="watchedFiles" type="string" defaultValue="*.js"/>
<attribute name="enableXFF" type="bool" defaultValue="false"/>
<attribute name="promoteServerVars" type="string" defaultValue=""/>
</sectionSchema>
</configSchema>
1 change: 1 addition & 0 deletions src/config/iisnode_schema_x64.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,6 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/
<attribute name="flushResponse" type="bool" defaultValue="false"/>
<attribute name="watchedFiles" type="string" defaultValue="*.js"/>
<attribute name="enableXFF" type="bool" defaultValue="false"/>
<attribute name="promoteServerVars" type="string" defaultValue=""/>
</sectionSchema>
</configSchema>
23 changes: 22 additions & 1 deletion src/iisnode/chttpprotocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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));
Expand Down
116 changes: 111 additions & 5 deletions src/iisnode/cmoduleconfiguration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -518,6 +600,12 @@ HRESULT CModuleConfiguration::GetConfig(IHttpContext* context, CModuleConfigurat
commandLine = NULL;
}

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

if (NULL != c)
{
delete c;
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -705,3 +793,21 @@ HRESULT CModuleConfiguration::GetDebugPortRange(IHttpContext* ctx, DWORD* start,

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;
}
3 changes: 3 additions & 0 deletions src/iisnode/cmoduleconfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ class CModuleConfiguration : public IHttpStoredContext
DWORD maxNamedPipeConnectionPoolSize;
DWORD maxNamedPipePooledConnectionAge;
BOOL enableXFF;
char** promoteServerVars;
int promoteServerVarsCount;

static IHttpServer* server;
static HTTP_MODULE_ID moduleId;
Expand Down Expand Up @@ -78,6 +80,7 @@ class CModuleConfiguration : public IHttpStoredContext
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);

Expand Down
6 changes: 6 additions & 0 deletions src/iisnode/iisnode.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,8 @@ copy /y $(ProjectDir)\..\config\* $(ProjectDir)\..\..\build\$(Configuration)\$(P
<None Include="..\..\test\functional\tests\115_customheaders.js" />
<None Include="..\..\test\functional\tests\116_configerror.js" />
<None Include="..\..\test\functional\tests\117_autoupdate_dependency.bat" />
<None Include="..\..\test\functional\tests\118_xff.js" />
<None Include="..\..\test\functional\tests\119_servervars.js" />
<None Include="..\..\test\functional\tests\200_samples.bat" />
<None Include="..\..\test\functional\tests\node_modules\iisnodeassert.js" />
<None Include="..\..\test\functional\tests\parts\106_autoupdate_first.js" />
Expand Down Expand Up @@ -298,6 +300,10 @@ copy /y $(ProjectDir)\..\config\* $(ProjectDir)\..\..\build\$(Configuration)\$(P
<None Include="..\..\test\functional\www\117_autoupdate_dependency\hello_first.js" />
<None Include="..\..\test\functional\www\117_autoupdate_dependency\hello_second.js" />
<None Include="..\..\test\functional\www\117_autoupdate_dependency\web.config" />
<None Include="..\..\test\functional\www\118_xff\hello.js" />
<None Include="..\..\test\functional\www\118_xff\web.config" />
<None Include="..\..\test\functional\www\119_servervars\hello.js" />
<None Include="..\..\test\functional\www\119_servervars\web.config" />
<None Include="..\..\test\performance\client.bat" />
<None Include="..\..\test\performance\localRun.bat" />
<None Include="..\..\test\performance\readme.txt" />
Expand Down
24 changes: 24 additions & 0 deletions src/iisnode/iisnode.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@
<Filter Include="Tests\functional\www\117_autoupdate_dependency">
<UniqueIdentifier>{ac86a901-4e59-4b58-82ce-a7674d8c587c}</UniqueIdentifier>
</Filter>
<Filter Include="Tests\functional\www\118_xff">
<UniqueIdentifier>{dd3b1edf-b406-49ff-988a-4b417fe9ce3c}</UniqueIdentifier>
</Filter>
<Filter Include="Tests\functional\www\119_servervars">
<UniqueIdentifier>{4595469d-4085-4631-836b-08584244a9e7}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
Expand Down Expand Up @@ -528,6 +534,24 @@
<None Include="..\..\test\functional\www\117_autoupdate_dependency\web.config">
<Filter>Tests\functional\www\117_autoupdate_dependency</Filter>
</None>
<None Include="..\..\test\functional\tests\118_xff.js">
<Filter>Tests\functional\tests</Filter>
</None>
<None Include="..\..\test\functional\www\118_xff\hello.js">
<Filter>Tests\functional\www\118_xff</Filter>
</None>
<None Include="..\..\test\functional\www\118_xff\web.config">
<Filter>Tests\functional\www\118_xff</Filter>
</None>
<None Include="..\..\test\functional\tests\119_servervars.js">
<Filter>Tests\functional\tests</Filter>
</None>
<None Include="..\..\test\functional\www\119_servervars\hello.js">
<Filter>Tests\functional\www\119_servervars</Filter>
</None>
<None Include="..\..\test\functional\www\119_servervars\web.config">
<Filter>Tests\functional\www\119_servervars</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="iisnode.rc" />
Expand Down
5 changes: 5 additions & 0 deletions src/samples/configuration/readme.htm
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ <h2>
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-&lt;server_variable_name&gt; 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"

--&gt;

Expand Down Expand Up @@ -152,6 +156,7 @@ <h2>
devErrorsEnabled="true"
flushResponse="false"
enableXFF="false"
promoteServerVars=""
/&gt;

&lt;!--
Expand Down
5 changes: 5 additions & 0 deletions src/samples/configuration/web.config
Original file line number Diff line number Diff line change
Expand Up @@ -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-<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"

-->

Expand Down Expand Up @@ -119,6 +123,7 @@
devErrorsEnabled="true"
flushResponse="false"
enableXFF="false"
promoteServerVars=""
/>

<!--
Expand Down
9 changes: 9 additions & 0 deletions test/functional/tests/119_servervars.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
Server variables specified in the iisnode\@promoteServerVars configuration section are promoted to X-iisnode-* headers
*/

var iisnodeassert = require("iisnodeassert");

iisnodeassert.sequence([
iisnodeassert.get(10000, "/119_servervars/hello.js", 200, "x-iisnode-request_method: GET")
]);
6 changes: 6 additions & 0 deletions test/functional/www/119_servervars/hello.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
var http = require('http');

http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end('x-iisnode-request_method: ' + req.headers['x-iisnode-request_method']);
}).listen(process.env.PORT);
11 changes: 11 additions & 0 deletions test/functional/www/119_servervars/web.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<configuration>
<system.webServer>

<handlers>
<add name="iisnode" path="hello.js" verb="*" modules="iisnode" />
</handlers>

<iisnode promoteServerVars="REQUEST_METHOD,AUTH_USER" />

</system.webServer>
</configuration>

0 comments on commit 6e68c03

Please sign in to comment.