source: Dev/trunk/src/server/util/simple-http-proxy.js @ 470

Last change on this file since 470 was 470, checked in by hendrikvanantwerpen, 12 years ago

Reorganized app and fixed some style issues.

Was looking for a bug where the proxy would not forward requests to the
database. This is somehow magically resolved now.

File size: 3.5 KB
Line 
1
2/**
3 * Module dependencies
4 */
5var url = require('url'),
6    join = require('path').join,
7    protocols = {
8        http: require('http'),
9        https: require('https')
10    };
11
12module.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};
Note: See TracBrowser for help on using the repository browser.