[464] | 1 | |
---|
| 2 | /** |
---|
| 3 | * Module dependencies |
---|
| 4 | */ |
---|
[470] | 5 | var url = require('url'), |
---|
| 6 | join = require('path').join, |
---|
| 7 | protocols = { |
---|
[464] | 8 | http: require('http'), |
---|
| 9 | https: require('https') |
---|
| 10 | }; |
---|
| 11 | |
---|
| 12 | module.exports = function(endpoint, opts) { |
---|
| 13 | opts = opts || {}; |
---|
| 14 | |
---|
| 15 | var parsedUrl = url.parse(endpoint); |
---|
| 16 | |
---|
| 17 | return function simpleHttpProxy(req, res, next) { |
---|
| 18 | // Get our forwarding info |
---|
| 19 | var hostInfo = req.headers.host.split(":"); |
---|
| 20 | |
---|
| 21 | // Remove the host header |
---|
| 22 | delete req.headers.host; |
---|
| 23 | |
---|
| 24 | // Optionally delete cookie |
---|
| 25 | if (opts.cookies === false) { |
---|
| 26 | delete req.headers.cookie; |
---|
| 27 | } |
---|
| 28 | |
---|
| 29 | // Should we keep the trailing slash? |
---|
| 30 | var trailingSlash = req.originalUrl[req.originalUrl.length-1] === "/"; |
---|
| 31 | |
---|
| 32 | // Setup the options |
---|
| 33 | var options = { |
---|
| 34 | hostname: parsedUrl.hostname, |
---|
| 35 | auth: parsedUrl.auth, |
---|
| 36 | port: parsedUrl.port, |
---|
| 37 | headers: req.headers, |
---|
| 38 | path: join(parsedUrl.pathname, trailingSlash ? req.url : req.url.substring(1)), |
---|
| 39 | method: req.method |
---|
| 40 | }; |
---|
| 41 | |
---|
| 42 | // Enable forwarding headers |
---|
| 43 | if(opts.xforward) { |
---|
| 44 | // Get the path at which the middleware is mounted |
---|
| 45 | var resPath = req.originalUrl.replace(req.url, ""); |
---|
| 46 | |
---|
| 47 | // We'll need to add a / if it's not on there |
---|
| 48 | if (resPath.indexOf("/") !== 0) { |
---|
| 49 | resPath = join("/", resPath); |
---|
| 50 | } |
---|
| 51 | |
---|
| 52 | // Pass along our headers |
---|
| 53 | options.headers[opts.xforward.proto || "x-forwarded-proto"] = req.connection.encrypted ? "https" : "http"; |
---|
| 54 | options.headers[opts.xforward.host || "x-forwarded-host"] = hostInfo[0]; |
---|
| 55 | options.headers[opts.xforward.path || "x-forwarded-path"] = resPath; |
---|
| 56 | |
---|
| 57 | if (hostInfo[1]) { |
---|
| 58 | options.headers[opts.xforward.port || "x-forwarded-port"] = hostInfo[1]; |
---|
| 59 | } |
---|
| 60 | } |
---|
| 61 | |
---|
| 62 | /** |
---|
| 63 | * Hack for nginx backends where node, by default, sends no 'content-length' |
---|
| 64 | * header if no data is sent with the request and sets the 'transfer-encoding' |
---|
| 65 | * to 'chunked'. Nginx will then send a 411 because the body contains a '0' |
---|
| 66 | * which is the length of the chunk |
---|
| 67 | * |
---|
| 68 | * GET /proxy |
---|
| 69 | * transfer-encoding: chunked |
---|
| 70 | * |
---|
| 71 | * 0 |
---|
| 72 | * |
---|
| 73 | */ |
---|
| 74 | if( ["POST", "DELETE"].indexOf(req.method) !== -1 && options.headers['transfer-encoding'] !== 'chunked') { |
---|
| 75 | options.headers['content-length'] = options.headers['content-length'] || '0'; |
---|
| 76 | } |
---|
| 77 | |
---|
| 78 | // Make the request with the correct protocol |
---|
| 79 | var request = protocols[(parsedUrl.protocol || 'http').replace(":", "")].request(options, function(response) { |
---|
| 80 | |
---|
| 81 | // Send down the statusCode and headers |
---|
| 82 | res.writeHead(response.statusCode, response.headers); |
---|
| 83 | |
---|
| 84 | // Pipe the response |
---|
| 85 | response.pipe(res); |
---|
| 86 | }); |
---|
| 87 | |
---|
| 88 | // Handle any timeouts that occur |
---|
| 89 | request.setTimeout(opts.timeout || 10000, function() { |
---|
| 90 | // Clean up the socket |
---|
| 91 | // TODO is there a better way to do this? There's a 'socket hang up' error being emitted... |
---|
| 92 | request.setSocketKeepAlive(false); |
---|
| 93 | request.socket.destroy(); |
---|
| 94 | |
---|
| 95 | // Pass down the error |
---|
| 96 | var err = new Error("Proxy to '"+endpoint+"' timed out"); |
---|
| 97 | request.emit("error", err); |
---|
| 98 | }); |
---|
| 99 | |
---|
| 100 | // Pipe the client request upstream |
---|
| 101 | req.pipe(request); |
---|
| 102 | |
---|
| 103 | // Pass on our errors |
---|
| 104 | request.on('error', next); |
---|
| 105 | }; |
---|
| 106 | }; |
---|