From d21fb640141cf0801a6e064a804259a299553d79 Mon Sep 17 00:00:00 2001 From: Dan Polivy Date: Thu, 21 Nov 2013 17:04:07 -0800 Subject: [PATCH] Map HTTPS server variable to X-Forwarded-Proto header In express.js, "trust proxy" mode allows is to properly handle the scenario of being behind a proxy server, while still properly exposing the client IP/protocol from the request object. The enableXFF configuration option for iisnode propagates the X-Forwarded-For header, but not X-Forwarded-Proto. This commit adds the X-Forwarded-Proto header as well, in scenarios where enableXFF is true. For details, see: https://github.com/tjanczuk/iisnode/issues/265 --- src/iisnode/chttpprotocol.cpp | 19 +++++++++++++++++++ test/functional/tests/118_xff.js | 2 +- test/functional/www/118_xff/hello.js | 7 ++++--- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/iisnode/chttpprotocol.cpp b/src/iisnode/chttpprotocol.cpp index 5d220ae..cb83335 100644 --- a/src/iisnode/chttpprotocol.cpp +++ b/src/iisnode/chttpprotocol.cpp @@ -46,6 +46,9 @@ PCSTR CHttpProtocol::httpRequestHeaders[] = { "User-Agent" }; +static const PCSTR schemeHttp = "http"; +static const PCSTR schemeHttps = "https"; + HRESULT CHttpProtocol::Append(IHttpContext* context, const char* content, DWORD contentLength, void** buffer, DWORD* bufferLength, DWORD* offset) { HRESULT hr; @@ -165,6 +168,22 @@ HRESULT CHttpProtocol::SerializeRequestHeaders(CNodeHttpStoredContext* ctx, void 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()); + + // Determine the incoming request protocol scheme + PCSTR varValue, varScheme = schemeHttp; + DWORD varValueLength; + if (S_OK == context->GetServerVariable("HTTPS", &varValue, &varValueLength)) + { + if (0 == strcmpi("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)); } for (int i = 0; i < raw->Headers.UnknownHeaderCount; i++) diff --git a/test/functional/tests/118_xff.js b/test/functional/tests/118_xff.js index 4d765b1..7055007 100644 --- a/test/functional/tests/118_xff.js +++ b/test/functional/tests/118_xff.js @@ -5,5 +5,5 @@ 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") ]); \ No newline at end of file diff --git a/test/functional/www/118_xff/hello.js b/test/functional/www/118_xff/hello.js index 16a24cb..36e1324 100644 --- a/test/functional/www/118_xff/hello.js +++ b/test/functional/www/118_xff/hello.js @@ -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); \ No newline at end of file +}).listen(process.env.PORT); \ No newline at end of file