fix #87: provide access to iis server variables to the node.js application

This commit is contained in:
Tomasz Janczuk 2012-01-11 11:50:37 -08:00
Родитель b5f955727b
Коммит 6e68c03e5b
12 изменённых файлов: 204 добавлений и 6 удалений

Просмотреть файл

@ -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>

Просмотреть файл

@ -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>

Просмотреть файл

@ -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));

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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);

Просмотреть файл

@ -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" />
@ -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" />

Просмотреть файл

@ -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">
@ -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" />

Просмотреть файл

@ -125,6 +125,10 @@ console.log('Application started at location ' + process.env.PORT);</pre>
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;
@ -152,6 +156,7 @@ console.log('Application started at location ' + process.env.PORT);</pre>
devErrorsEnabled="true"
flushResponse="false"
enableXFF="false"
promoteServerVars=""
/&gt;
&lt;!--

Просмотреть файл

@ -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"
-->
@ -119,6 +123,7 @@
devErrorsEnabled="true"
flushResponse="false"
enableXFF="false"
promoteServerVars=""
/>
<!--

Просмотреть файл

@ -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")
]);

Просмотреть файл

@ -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);

Просмотреть файл

@ -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>