Skip to content

Instantly share code, notes, and snippets.

@ntpz
Created November 27, 2018 05:41
Show Gist options
  • Save ntpz/d45cf44c4ece355d356f526d004a6990 to your computer and use it in GitHub Desktop.
Save ntpz/d45cf44c4ece355d356f526d004a6990 to your computer and use it in GitHub Desktop.
Node.js request forwarder
/*
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