Skip to content

Commit

Permalink
Merge pull request tjanczuk#310 from dpolivy/xff
Browse files Browse the repository at this point in the history
Support for X-Forwarded-For and X-Forwarded-Proto headers
  • Loading branch information
rramachand21 committed Apr 13, 2014
2 parents 3491ffe + 1a565c7 commit b450139
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 41 deletions.
62 changes: 31 additions & 31 deletions README.md
Expand Up @@ -3,18 +3,18 @@ Hosting node.js applications in IIS on Windows

**Why would I want to do it?**

[Benefits](https://github.com/tjanczuk/iisnode/wiki)
[Benefits](https://github.com/tjanczuk/iisnode/wiki)

**Who uses iisnode?**

[windows azure - benefits](http://blogs.msdn.com/b/hanuk/archive/2012/05/05/top-benefits-of-running-node-js-on-windows-azure.aspx)
[windows azure - get started with node.js](https://www.windowsazure.com/en-us/develop/nodejs/)
[appharbor.com](http://blog.appharbor.com/2012/01/19/announcing-node-js-support)
[discountasp.net](http://discountasp.net/press/2012_06_12_free-webmatrix-v2-rc-hosting-with-nodejs.aspx)
[arvixe.com](http://arvixe.com)
[smarterasp.net](http://www.smarterasp.net/)
[gearhost.com](http://gearhost.com/)
[webecs.com](http://webecs.com/)
[windows azure - benefits](http://blogs.msdn.com/b/hanuk/archive/2012/05/05/top-benefits-of-running-node-js-on-windows-azure.aspx)
[windows azure - get started with node.js](https://www.windowsazure.com/en-us/develop/nodejs/)
[appharbor.com](http://blog.appharbor.com/2012/01/19/announcing-node-js-support)
[discountasp.net](http://discountasp.net/press/2012_06_12_free-webmatrix-v2-rc-hosting-with-nodejs.aspx)
[arvixe.com](http://arvixe.com)
[smarterasp.net](http://www.smarterasp.net/)
[gearhost.com](http://gearhost.com/)
[webecs.com](http://webecs.com/)

**Prerequisites for using**

Expand All @@ -27,7 +27,7 @@ Hosting node.js applications in IIS on Windows
**Installing for IIS 7.x/8.x**

- Install iisnode for IIS 7.x/8.x: [x86](http://go.microsoft.com/?linkid=9784330) or [x64](http://go.microsoft.com/?linkid=9784331) - choose bitness matching your system
- To set up samples, from the administrative command prompt call `%programfiles%\iisnode\setupsamples.bat`
- To set up samples, from the administrative command prompt call `%programfiles%\iisnode\setupsamples.bat`
- Go to `http://localhost/node`

**Installing for IIS Express/WebMatrix**
Expand All @@ -38,20 +38,20 @@ Hosting node.js applications in IIS on Windows

**Howtos**

[the basics](http://tomasz.janczuk.org/2011/08/hosting-nodejs-applications-in-iis-on.html)
[the basics (Pусский перевод)](http://softdroid.net/hosting-nodejs-applications-ru)
[**NEW: websockets**] (http://tomasz.janczuk.org/2012/11/how-to-use-websockets-with-nodejs-apps.html)
[using with express framework](http://tomasz.janczuk.org/2011/08/hosting-express-nodejs-applications-in.html)
[using with URL rewrite module](http://tomasz.janczuk.org/2011/08/using-url-rewriting-with-nodejs.html)
[using with WebMatrix and IIS Express](http://tomasz.janczuk.org/2011/08/developing-nodejs-applications-in.html)
[site templates for WebMatrix](https://github.com/SteveSanderson/Node.js-Site-Templates-for-WebMatrix)
[using with mongodb](http://www.amazedsaint.com/2011/09/creating-10-minute-todo-listing-app-on.html)
[diagnosing problems with ETW traces](http://tomasz.janczuk.org/2011/09/using-event-tracing-for-windows-to.html)
[using with MVC](http://weblogs.asp.net/jgalloway/archive/2011/10/26/using-node-js-in-an-asp-net-mvc-application-with-iisnode.aspx)
[portuguese: node.js no windows: instalando o iisnode](http://vivina.com.br/nodejs-windows-parte-2)
[integrated debugging](http://tomasz.janczuk.org/2011/11/debug-nodejs-applications-on-windows.html)
[pub/sub server using faye](http://weblogs.asp.net/cibrax/archive/2011/12/12/transform-your-iis-into-a-real-time-pub-sub-engine-with-faye-node.aspx)
[appharbor uses iisnode](http://blog.appharbor.com/2012/01/19/announcing-node-js-support)
[the basics](http://tomasz.janczuk.org/2011/08/hosting-nodejs-applications-in-iis-on.html)
[the basics (Pусский перевод)](http://softdroid.net/hosting-nodejs-applications-ru)
[**NEW: websockets**] (http://tomasz.janczuk.org/2012/11/how-to-use-websockets-with-nodejs-apps.html)
[using with express framework](http://tomasz.janczuk.org/2011/08/hosting-express-nodejs-applications-in.html)
[using with URL rewrite module](http://tomasz.janczuk.org/2011/08/using-url-rewriting-with-nodejs.html)
[using with WebMatrix and IIS Express](http://tomasz.janczuk.org/2011/08/developing-nodejs-applications-in.html)
[site templates for WebMatrix](https://github.com/SteveSanderson/Node.js-Site-Templates-for-WebMatrix)
[using with mongodb](http://www.amazedsaint.com/2011/09/creating-10-minute-todo-listing-app-on.html)
[diagnosing problems with ETW traces](http://tomasz.janczuk.org/2011/09/using-event-tracing-for-windows-to.html)
[using with MVC](http://weblogs.asp.net/jgalloway/archive/2011/10/26/using-node-js-in-an-asp-net-mvc-application-with-iisnode.aspx)
[portuguese: node.js no windows: instalando o iisnode](http://vivina.com.br/nodejs-windows-parte-2)
[integrated debugging](http://tomasz.janczuk.org/2011/11/debug-nodejs-applications-on-windows.html)
[pub/sub server using faye](http://weblogs.asp.net/cibrax/archive/2011/12/12/transform-your-iis-into-a-real-time-pub-sub-engine-with-faye-node.aspx)
[appharbor uses iisnode](http://blog.appharbor.com/2012/01/19/announcing-node-js-support)

**Prerequisites for building**

Expand All @@ -62,15 +62,15 @@ Hosting node.js applications in IIS on Windows

**Building**

Build commands should be issued from the build environment set up with `"%programfiles(x86)\Microsoft Visual Studio 11.0\Common7\Tools\VsDevCmd.bat"`, assuming default installation location of Visual Studio 2012 on x64 platform.
Build commands should be issued from the build environment set up with `"%programfiles(x86)%\Microsoft Visual Studio 11.0\Common7\Tools\VsDevCmd.bat"`, assuming default installation location of Visual Studio 2012 on x64 platform.

For x86 build:
For x86 build:

```
msbuild /p:Platform=Win32 src\iisnode\iisnode.sln
```

For x64 build:
For x64 build:

```
msbuild /p:Platform=x64 src\iisnode\iisnode.sln
Expand All @@ -80,7 +80,7 @@ msbuild /p:Platform=x64 src\iisnode\iisnode.sln

- For IIS 7.x/8.0: `build\debug\{x64|x86}\iisnode-full.msi`
- For IIS Express 7.x: `build\debug\x86\iisnode-express.msi`

**Running tests**

- Install for IIS 7.x/8.x (see previous sections)
Expand All @@ -89,6 +89,6 @@ msbuild /p:Platform=x64 src\iisnode\iisnode.sln

**Resources & documentation**

[Releases](https://github.com/tjanczuk/iisnode/wiki/iisnode-releases)
[Wiki](https://github.com/tjanczuk/iisnode/wiki)
[Blog](http://tomasz.janczuk.org)
[Releases](https://github.com/tjanczuk/iisnode/wiki/iisnode-releases)
[Wiki](https://github.com/tjanczuk/iisnode/wiki)
[Blog](http://tomasz.janczuk.org)
39 changes: 33 additions & 6 deletions src/iisnode/chttpprotocol.cpp
Expand Up @@ -46,6 +46,9 @@ PCSTR CHttpProtocol::httpRequestHeaders[] = {
"User-Agent"
};

const PCSTR CHttpProtocol::schemeHttp = "http";
const PCSTR CHttpProtocol::schemeHttps = "https";

HRESULT CHttpProtocol::Append(IHttpContext* context, const char* content, DWORD contentLength, void** buffer, DWORD* bufferLength, DWORD* offset)
{
HRESULT hr;
Expand Down Expand Up @@ -93,7 +96,7 @@ HRESULT CHttpProtocol::SerializeRequestHeaders(CNodeHttpStoredContext* ctx, void
USHORT originalUrlLength;
DWORD remoteHostSize = INET6_ADDRSTRLEN + 1;
char remoteHost[INET6_ADDRSTRLEN + 1];
BOOL addXFF;
BOOL addXFF, addXFP;
char** serverVars;
int serverVarCount;

Expand Down Expand Up @@ -160,11 +163,11 @@ HRESULT CHttpProtocol::SerializeRequestHeaders(CNodeHttpStoredContext* ctx, void

// Unknown headers

if (TRUE == (addXFF = CModuleConfiguration::GetEnableXFF(context)))
if (TRUE == (addXFF = addXFP = CModuleConfiguration::GetEnableXFF(context)))
{
PSOCKADDR addr = request->GetRemoteAddress();
DWORD addrSize = addr->sa_family == AF_INET ? sizeof SOCKADDR_IN : sizeof SOCKADDR_IN6;
ErrorIf(0 != WSAAddressToString(addr, addrSize, NULL, remoteHost, &remoteHostSize), GetLastError());
ErrorIf(0 != GetNameInfo(addr, addrSize, remoteHost, remoteHostSize, NULL, 0, NI_NUMERICHOST), GetLastError());
}

for (int i = 0; i < raw->Headers.UnknownHeaderCount; i++)
Expand All @@ -173,15 +176,20 @@ HRESULT CHttpProtocol::SerializeRequestHeaders(CNodeHttpStoredContext* ctx, void
CheckError(CHttpProtocol::Append(context, ": ", 2, result, &bufferLength, &offset));
CheckError(CHttpProtocol::Append(context, raw->Headers.pUnknownHeaders[i].pRawValue, raw->Headers.pUnknownHeaders[i].RawValueLength, result, &bufferLength, &offset));

if (addXFF && 15 == raw->Headers.pUnknownHeaders[i].NameLength && 0 == strcmpi("X-Forwarded-For", raw->Headers.pUnknownHeaders[i].pName))
if (addXFF && 15 == raw->Headers.pUnknownHeaders[i].NameLength && 0 == _stricmp("X-Forwarded-For", raw->Headers.pUnknownHeaders[i].pName))
{
// augment existing X-Forwarded-For header

CheckError(CHttpProtocol::Append(context, ", ", 2, result, &bufferLength, &offset));
CheckError(CHttpProtocol::Append(context, remoteHost, remoteHostSize - 1, result, &bufferLength, &offset));
CheckError(CHttpProtocol::Append(context, remoteHost, 0, result, &bufferLength, &offset));

addXFF = FALSE;
}
else if (addXFP && 17 == raw->Headers.pUnknownHeaders[i].NameLength && 0 == _stricmp("X-Forwarded-Proto", raw->Headers.pUnknownHeaders[i].pName))
{
// Already exists in incoming headers; don't add a second one
addXFP = FALSE;
}

CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));
}
Expand All @@ -191,10 +199,29 @@ HRESULT CHttpProtocol::SerializeRequestHeaders(CNodeHttpStoredContext* ctx, void
// add a new X-Forwarded-For header

CheckError(CHttpProtocol::Append(context, "X-Forwarded-For: ", 17, result, &bufferLength, &offset));
CheckError(CHttpProtocol::Append(context, remoteHost, remoteHostSize - 1, result, &bufferLength, &offset));
CheckError(CHttpProtocol::Append(context, remoteHost, 0, result, &bufferLength, &offset));
CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));
}

if (addXFP)
{
// Determine the incoming request protocol scheme
PCSTR varValue, varScheme = schemeHttp;
DWORD varValueLength;
if (S_OK == context->GetServerVariable("HTTPS", &varValue, &varValueLength))
{
if (0 == _stricmp("on", varValue))
{
varScheme = schemeHttps;
}
}

// Add the X-Forwarded-Proto header (default is http)
CheckError(CHttpProtocol::Append(context, "X-Forwarded-Proto: ", 19, result, &bufferLength, &offset));
CheckError(CHttpProtocol::Append(context, varScheme, 0, result, &bufferLength, &offset));
CheckError(CHttpProtocol::Append(context, "\r\n", 2, result, &bufferLength, &offset));
}

// promote server variables

CheckError(CModuleConfiguration::GetPromoteServerVars(context, &serverVars, &serverVarCount));
Expand Down
3 changes: 3 additions & 0 deletions src/iisnode/chttpprotocol.h
Expand Up @@ -7,6 +7,9 @@ class CHttpProtocol
{
private:

static const PCSTR schemeHttp;
static const PCSTR schemeHttps;

static PCSTR httpRequestHeaders[HttpHeaderRequestMaximum];
static HRESULT Append(IHttpContext* context, const char* content, DWORD contentLength, void** buffer, DWORD* bufferLength, DWORD* offset);

Expand Down
3 changes: 2 additions & 1 deletion test/functional/tests/118_xff.js
Expand Up @@ -5,5 +5,6 @@ iisnode adds X-Forwarded-For header to HTTP requests when issnode\@enableXFF is
var iisnodeassert = require("iisnodeassert");

iisnodeassert.sequence([
iisnodeassert.get(10000, "/118_xff/hello.js", 200, "Request contains X-Forwarded-For header")
iisnodeassert.get(10000, "/118_xff/hello.js", 200, "Request contains X-Forwarded-For and X-Forwarded-Proto headers", { 'x-echo-x-forwarded-for': '127.0.0.1', 'x-echo-x-forwarded-proto': 'http' }),
iisnodeassert.post(10000, "/118_xff/hello.js", { headers: { 'X-Forwarded-Proto': 'https' }}, 200, "Request contains X-Forwarded-For and X-Forwarded-Proto headers", { 'x-echo-x-forwarded-for': '127.0.0.1', 'x-echo-x-forwarded-proto': 'https' })
]);
7 changes: 4 additions & 3 deletions test/functional/www/118_xff/hello.js
Expand Up @@ -2,13 +2,14 @@ var http = require('http');

http.createServer(function (req, res) {
res.setHeader('Content-Type', 'text/html');
if (req.headers.hasOwnProperty('x-forwarded-for')) {
if (req.headers.hasOwnProperty('x-forwarded-for') && req.headers.hasOwnProperty('x-forwarded-proto')) {
res.setHeader('x-echo-x-forwarded-for', req.headers['x-forwarded-for']);
res.setHeader('x-echo-x-forwarded-proto', req.headers['x-forwarded-proto']);
res.writeHead(200);
res.end('Request contains X-Forwarded-For header');
res.end('Request contains X-Forwarded-For and X-Forwarded-Proto headers');
}
else {
res.writeHead(200);
res.end('Request does not contain X-Forwarded-For header');
}
}).listen(process.env.PORT);
}).listen(process.env.PORT);

0 comments on commit b450139

Please sign in to comment.