Merge pull request #310 from dpolivy/xff

Support for X-Forwarded-For and X-Forwarded-Proto headers
This commit is contained in:
Ranjith Ramachandra 2014-04-13 11:55:17 -07:00
Родитель 3491ffefb6 1a565c71e8
Коммит b450139433
5 изменённых файлов: 73 добавлений и 41 удалений

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

@ -62,7 +62,7 @@ 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:

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

@ -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;
@ -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;
@ -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++)
@ -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));
}
@ -191,7 +199,26 @@ 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));
}

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

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

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

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

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

@ -2,10 +2,11 @@ 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);