diff --git a/lib/node-http-proxy/http-proxy.js b/lib/node-http-proxy/http-proxy.js index bd8434a65..c73efbe83 100644 --- a/lib/node-http-proxy/http-proxy.js +++ b/lib/node-http-proxy/http-proxy.js @@ -52,14 +52,14 @@ var HttpProxy = exports.HttpProxy = function (options) { if (!options || !options.target) { throw new Error('Both `options` and `options.target` are required.'); } - + events.EventEmitter.call(this); - + var self = this; // - // Setup basic proxying options: - // + // Setup basic proxying options: + // // * forward {Object} Options for a forward-proxy (if-any) // * target {Object} Options for the **sole** proxy target of this instance // @@ -69,23 +69,23 @@ var HttpProxy = exports.HttpProxy = function (options) { // // Setup the necessary instances instance variables for // the `target` and `forward` `host:port` combinations - // used by this instance. + // used by this instance. // // * agent {http[s].Agent} Agent to be used by this instance. // * protocol {http|https} Core node.js module to make requests with. // * base {Object} Base object to create when proxying containing any https settings. - // + // function setupProxy (key) { self[key].agent = httpProxy._getAgent(self[key]); self[key].protocol = httpProxy._getProtocol(self[key]); - self[key].base = httpProxy._getBase(self[key]); + self[key].base = httpProxy._getBase(self[key]); } - + setupProxy('target'); - if (this.forward) { - setupProxy('forward'); + if (this.forward) { + setupProxy('forward'); } - + // // Setup opt-in features // @@ -103,7 +103,7 @@ var HttpProxy = exports.HttpProxy = function (options) { // this.source = options.source || { host: 'localhost', port: 8000 }; this.source.https = this.source.https || options.https; - this.changeOrigin = options.changeOrigin || false; + this.changeOrigin = options.changeOrigin || false; }; // Inherit from events.EventEmitter @@ -116,14 +116,14 @@ util.inherits(HttpProxy, events.EventEmitter); // #### @buffer {Object} Result from `httpProxy.buffer(req)` // HttpProxy.prototype.proxyRequest = function (req, res, buffer) { - var self = this, + var self = this, errState = false, outgoing = new(this.target.base), reverseProxy; // // Add common proxy headers to the request so that they can - // be availible to the proxy target server. If the proxy is + // be availible to the proxy target server. If the proxy is // part of proxy chain it will append the address: // // * `x-forwarded-for`: IP Address of the original request @@ -134,7 +134,7 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) { if (req.headers['x-forwarded-for']){ var addressToAppend = "," + req.connection.remoteAddress || req.socket.remoteAddress; req.headers['x-forwarded-for'] += addressToAppend; - } + } else { req.headers['x-forwarded-for'] = req.connection.remoteAddress || req.socket.remoteAddress; } @@ -142,7 +142,7 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) { if (req.headers['x-forwarded-port']){ var portToAppend = "," + req.connection.remotePort || req.socket.remotePort; req.headers['x-forwarded-port'] += portToAppend; - } + } else { req.headers['x-forwarded-port'] = req.connection.remotePort || req.socket.remotePort; } @@ -150,7 +150,7 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) { if (req.headers['x-forwarded-proto']){ var protoToAppend = "," + req.connection.pair ? 'https' : 'http'; req.headers['x-forwarded-proto'] += protoToAppend; - } + } else { req.headers['x-forwarded-proto'] = req.connection.pair ? 'https' : 'http'; } @@ -217,7 +217,15 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) { outgoing.headers = req.headers; // - // Open new HTTP request to internal resource with will act + // If the changeOrigin option is specified, change the + // origin of the host header to the target URL! Please + // don't revert this without documenting it! + // + if(this.changeOrigin) + outgoing.headers.host = this.target.host + ':' + this.target.port; + + // + // Open new HTTP request to internal resource with will act // as a reverse proxy pass // reverseProxy = this.target.protocol.request(outgoing, function (response) { @@ -286,10 +294,10 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) { ended = true if (!errState) { reverseProxy.removeListener('error', proxyError); - + try { res.end() } catch (ex) { console.error("res.end error: %s", ex.message) } - + // Emit the `end` event now that we have completed proxying self.emit('end', req, res); } @@ -313,19 +321,19 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) { // `req` write it to the `reverseProxy` request. // req.on('data', function (chunk) { - + if (!errState) { var flushed = reverseProxy.write(chunk); if (!flushed) { req.pause(); reverseProxy.once('drain', function () { - try { req.resume() } + try { req.resume() } catch (er) { console.error("req.resume error: %s", er.message) } }); - + // // Force the `drain` event in 100ms if it hasn't - // happened on its own. + // happened on its own. // setTimeout(function () { reverseProxy.emit('drain'); @@ -367,7 +375,7 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) { // #### @socket {net.Socket} Socket for the underlying HTTP request // #### @head {string} Headers for the Websocket request. // #### @buffer {Object} Result from `httpProxy.buffer(req)` -// Performs a WebSocket proxy operation to the location specified by +// Performs a WebSocket proxy operation to the location specified by // `this.target`. // HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer) { @@ -387,10 +395,10 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer) // return socket.destroy(); } - + // // Add common proxy headers to the request so that they can - // be availible to the proxy target server. If the proxy is + // be availible to the proxy target server. If the proxy is // part of proxy chain it will append the address: // // * `x-forwarded-for`: IP Address of the original request @@ -401,7 +409,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer) if (req.headers['x-forwarded-for']){ var addressToAppend = "," + req.connection.remoteAddress || req.connection.socket.remoteAddress; req.headers['x-forwarded-for'] += addressToAppend; - } + } else { req.headers['x-forwarded-for'] = req.connection.remoteAddress || req.connection.socket.remoteAddress; } @@ -409,7 +417,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer) if (req.headers['x-forwarded-port']){ var portToAppend = "," + req.connection.remotePort || req.connection.socket.remotePort; req.headers['x-forwarded-port'] += portToAppend; - } + } else { req.headers['x-forwarded-port'] = req.connection.remotePort || req.connection.socket.remotePort; } @@ -417,7 +425,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer) if (req.headers['x-forwarded-proto']){ var protoToAppend = "," + req.connection.pair ? 'wss' : 'ws'; req.headers['x-forwarded-proto'] += protoToAppend; - } + } else { req.headers['x-forwarded-proto'] = req.connection.pair ? 'wss' : 'ws'; } @@ -432,7 +440,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer) function _socket(socket, keepAlive) { socket.setTimeout(0); socket.setNoDelay(true); - + if (keepAlive) { if (socket.setKeepAlive) { socket.setKeepAlive(true, 0); @@ -445,7 +453,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer) socket.setEncoding('utf8'); } } - + // // Setup the incoming client socket. // @@ -474,13 +482,13 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer) if (!flushed) { proxySocket.pause(); reverseProxy.incoming.socket.once('drain', function () { - try { proxySocket.resume() } + try { proxySocket.resume() } catch (er) { console.error("proxySocket.resume error: %s", er.message) } }); - + // // Force the `drain` event in 100ms if it hasn't - // happened on its own. + // happened on its own. // setTimeout(function () { reverseProxy.incoming.socket.emit('drain'); @@ -506,13 +514,13 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer) if (!flushed) { reverseProxy.incoming.socket.pause(); proxySocket.once('drain', function () { - try { reverseProxy.incoming.socket.resume() } + try { reverseProxy.incoming.socket.resume() } catch (er) { console.error("reverseProxy.incoming.socket.resume error: %s", er.message) } }); - + // // Force the `drain` event in 100ms if it hasn't - // happened on its own. + // happened on its own. // setTimeout(function () { proxySocket.emit('drain'); @@ -572,7 +580,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer) protocolName = this.target.https ? 'https' : 'http', portUri = getPort(this.source.port), remoteHost = this.target.host + portUri; - + // // Change headers (if requested). // @@ -591,7 +599,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer) outgoing.path = req.url; outgoing.headers = req.headers; outgoing.agent = agent; - + var reverseProxy = this.target.protocol.request(outgoing); // @@ -678,13 +686,13 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer) if (!flushed) { revSocket.pause(); socket.once('drain', function () { - try { revSocket.resume() } + try { revSocket.resume() } catch (er) { console.error("reverseProxy.socket.resume error: %s", er.message) } }); // // Force the `drain` event in 100ms if it hasn't - // happened on its own. + // happened on its own. // setTimeout(function () { socket.emit('drain'); @@ -693,7 +701,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer) } catch (ex) { // - // Remove data listener on socket error because the + // Remove data listener on socket error because the // 'handshake' has failed. // revSocket.removeListener('data', handshake); @@ -714,8 +722,8 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer) try { // - // Attempt to write the upgrade-head to the reverseProxy - // request. This is small, and there's only ever one of + // Attempt to write the upgrade-head to the reverseProxy + // request. This is small, and there's only ever one of // it; no need for pause/resume. // // XXX This is very wrong and should be fixed in node's core @@ -763,7 +771,7 @@ HttpProxy.prototype.close = function () { // by `this.forward` ignoring errors and the subsequent response. // HttpProxy.prototype._forwardRequest = function (req) { - var self = this, + var self = this, outgoing = new(this.forward.base), forwardProxy; @@ -778,7 +786,7 @@ HttpProxy.prototype._forwardRequest = function (req) { outgoing.headers = req.headers; // - // Open new HTTP request to internal resource with will + // Open new HTTP request to internal resource with will // act as a reverse proxy pass. // forwardProxy = this.forward.protocol.request(outgoing, function (response) { @@ -805,13 +813,13 @@ HttpProxy.prototype._forwardRequest = function (req) { if (!flushed) { req.pause(); forwardProxy.once('drain', function () { - try { req.resume() } + try { req.resume() } catch (er) { console.error("req.resume error: %s", er.message) } }); // // Force the `drain` event in 100ms if it hasn't - // happened on its own. + // happened on its own. // setTimeout(function () { forwardProxy.emit('drain'); @@ -820,7 +828,7 @@ HttpProxy.prototype._forwardRequest = function (req) { }); // - // At the end of the client request, we are going to + // At the end of the client request, we are going to // stop the proxied request // req.on('end', function () { diff --git a/lib/node-http-proxy/proxy-table.js b/lib/node-http-proxy/proxy-table.js index 9035ab8da..e926901cc 100644 --- a/lib/node-http-proxy/proxy-table.js +++ b/lib/node-http-proxy/proxy-table.js @@ -138,13 +138,13 @@ ProxyTable.prototype.getProxyLocation = function (req) { var route = this.routes[i]; if (target.match(route.route)) { var pathSegments = route.path.split('/'); - + if (pathSegments.length > 1) { // don't include the proxytable path segments in the proxied request url pathSegments = new RegExp("/" + pathSegments.slice(1).join('/')); req.url = req.url.replace(pathSegments, ''); } - + var location = route.target.split(':'), host = location[0], port = location.length === 1 ? 80 : location[1]; diff --git a/lib/node-http-proxy/routing-proxy.js b/lib/node-http-proxy/routing-proxy.js index a4da67be3..c522bbc23 100644 --- a/lib/node-http-proxy/routing-proxy.js +++ b/lib/node-http-proxy/routing-proxy.js @@ -23,26 +23,26 @@ var RoutingProxy = exports.RoutingProxy = function (options) { var self = this; options = options || {}; - + if (options.router) { this.proxyTable = new ProxyTable(options); this.proxyTable.on('routes', function (routes) { self.emit('routes', routes); }); } - + // - // Create a set of `HttpProxy` objects to be used later on calls + // Create a set of `HttpProxy` objects to be used later on calls // to `.proxyRequest()` and `.proxyWebSocketRequest()`. // this.proxies = {}; - + // // Setup default target options (such as `https`). // this.target = {}; this.target.https = options.target && options.target.https; - + // // Setup other default options to be used for instances of // `HttpProxy` created by this `RoutingProxy` instance. @@ -68,27 +68,27 @@ util.inherits(RoutingProxy, events.EventEmitter); RoutingProxy.prototype.add = function (options) { var self = this, key = this._getKey(options); - + // // TODO: Consume properties in `options` related to the `ProxyTable`. // options.target = options.target || {}; options.target.host = options.target.host || options.host; options.target.port = options.target.port || options.port; - options.target.https = this.target && this.target.https || - options.target && options.target.https || + options.target.https = this.target && this.target.https || + options.target && options.target.https || options.https; - + // // Setup options to pass-thru to the new `HttpProxy` instance - // for the specified `options.host` and `options.port` pair. + // for the specified `options.host` and `options.port` pair. // ['https', 'enable', 'forward'].forEach(function (key) { if (options[key] !== false && self[key]) { options[key] = self[key]; } }); - + this.proxies[key] = new HttpProxy(options); this.proxies[key].on('proxyError', this.emit.bind(this, 'proxyError')); this.proxies[key].on('webSocketProxyError', this.emit.bind(this, 'webSocketProxyError')); @@ -111,18 +111,18 @@ RoutingProxy.prototype.remove = function (options) { // RoutingProxy.prototype.close = function () { var self = this; - + if (this.proxyTable) { // - // Close the `RoutingTable` associated with + // Close the `RoutingTable` associated with // this instance (if any). // this.proxyTable.close(); } - + // // Close all sockets for all `HttpProxy` object(s) - // associated with this instance. + // associated with this instance. // Object.keys(this.proxies).forEach(function (key) { self.proxies[key].close(); @@ -160,11 +160,11 @@ RoutingProxy.prototype.proxyRequest = function (req, res, options) { try { res.writeHead(404); res.end(); - } + } catch (er) { console.error("res.writeHead/res.end error: %s", er.message); } - + return; } @@ -179,15 +179,15 @@ RoutingProxy.prototype.proxyRequest = function (req, res, options) { options.port = location.port; options.host = location.host; } - + var key = this._getKey(options), proxy; - + if (!this.proxies[key]) { this.add(options); - - } - + + } + proxy = this.proxies[key]; proxy.proxyRequest(req, res, options.buffer); }; @@ -206,7 +206,7 @@ RoutingProxy.prototype.proxyRequest = function (req, res, options) { // RoutingProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options) { options = options || {}; - + if (this.proxyTable && !options.host) { location = this.proxyTable.getProxyLocation(req); @@ -217,7 +217,7 @@ RoutingProxy.prototype.proxyWebSocketRequest = function (req, socket, head, opti options.port = location.port; options.host = location.host; } - + var key = this._getKey(options), proxy; @@ -225,7 +225,7 @@ RoutingProxy.prototype.proxyWebSocketRequest = function (req, socket, head, opti this.add(options); } - proxy = this.proxies[key]; + proxy = this.proxies[key]; proxy.proxyWebSocketRequest(req, socket, head, options.buffer); }; @@ -237,14 +237,14 @@ RoutingProxy.prototype.proxyWebSocketRequest = function (req, socket, head, opti // combination contained within. // RoutingProxy.prototype._getKey = function (options) { - if (!options || ((!options.host || !options.port) + if (!options || ((!options.host || !options.port) && (!options.target || !options.target.host || !options.target.port))) { throw new Error('options.host and options.port or options.target are required.'); return; } return [ - options.host || options.target.host, + options.host || options.target.host, options.port || options.target.port ].join(':'); }