Created
November 27, 2018 05:41
-
-
Save ntpz/d45cf44c4ece355d356f526d004a6990 to your computer and use it in GitHub Desktop.
Node.js request forwarder
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
node.js request forwarder | |
Usage: | |
const express = require('express'); | |
const passthrough = require('./passthrough'); | |
const app = express(); | |
app.enable('trust proxy'); | |
app.use('/proxy', passthrough); | |
*/ | |
const url = require('url'), | |
http = require('http'), | |
https = require('https'); | |
module.exports = function(req, res, next) { | |
req.pause(); | |
const options = makeOptions(req), | |
proxyUrl = `${req.protocol}://${req.headers['x-forwarded-host']}${req.baseUrl}/`, // requires app.enable('trust proxy'); to work properly | |
respHandler = function(serverResponse) { | |
return serverRespHandler(serverResponse, res, proxyUrl); | |
}, | |
connector = (options.protocol == 'https:' ? https : http).request(options, respHandler); | |
req.pipe(connector, {end:true}); | |
req.resume(); | |
} | |
function makeOptions(req) { | |
const reqUrl = req.url.substr(1), | |
options = url.parse(reqUrl); | |
options.headers = req.headers; | |
options.method = req.method; | |
options.agent = false; | |
options.headers['host'] = options.host; | |
return options; | |
} | |
function absLocation(loc, req) { | |
if(loc.toLowerCase().substr(0,4) == 'http') { | |
return loc; | |
} | |
return new url.URL(loc, `${req.url.substr(1)}`).href; | |
} | |
function serverRespHandler(serverResponse, res, proxyUrl) { | |
serverResponse.pause(); | |
serverResponse.headers['access-control-allow-origin'] = '*'; | |
switch (serverResponse.statusCode) { | |
// pass through. we're not too smart here... | |
case 200: case 201: case 202: case 203: case 204: case 205: case 206: | |
case 304: | |
case 400: case 401: case 402: case 403: case 404: case 405: | |
case 406: case 407: case 408: case 409: case 410: case 411: | |
case 412: case 413: case 414: case 415: case 416: case 417: case 418: | |
res.writeHeader(serverResponse.statusCode, serverResponse.headers); | |
serverResponse.pipe(res, {end:true}); | |
serverResponse.resume(); | |
break; | |
// fix host and pass through | |
case 301: | |
case 302: | |
case 303: | |
case 307: | |
case 308: | |
const redirectTo = absLocation(serverResponse.headers['location'], res.req); | |
serverResponse.headers['location'] = proxyUrl + redirectTo; | |
console.log('\t-> Redirecting to ', serverResponse.headers['location']); | |
res.writeHeader(serverResponse.statusCode, serverResponse.headers); | |
serverResponse.pipe(res, {end:true}); | |
serverResponse.resume(); | |
break; | |
// error everything else | |
default: | |
let stringifiedHeaders = JSON.stringify(serverResponse.headers, null, 4); | |
serverResponse.resume(); | |
res.writeHeader(500, {'content-type': 'text/plain'}); | |
res.end(`Error ${serverResponse.statusCode}\n${stringifiedHeaders}`); | |
break; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment