diff --git a/README.md b/README.md index ea0d018..5ae63a3 100644 --- a/README.md +++ b/README.md @@ -217,6 +217,32 @@ proxyServerWithForwarding.listen(80); The forwarding option can be used in conjunction with the proxy table options by simply including both the 'forward' and 'router' properties in the options passed to 'createServer'. +### Listening for proxy events +Sometimes you want to listen to an event on a proxy. For example, you may want to listen to the 'end' event, which represents when the proxy has finished proxying a request. + +``` js +var httpProxy = require('http-proxy'); + +var server = httpProxy.createServer(function (req, res, proxy) { + + var buffer = httpProxy.buffer(req); + + proxy.proxyRequest(req, res, { + host: '127.0.0.1', + port: 9000, + buffer: buffer + }); + +}); + +server.proxy.on('end', function() { + console.log("The request was proxied."); +}); + +server.listen(8000); +``` + +It's important to remember not to listen for events on the proxy object in the function passed to `httpProxy.createServer`. Doing so would add a new listener on every request, which would end up being a disaster. ## Using HTTPS You have all the full flexibility of node-http-proxy offers in HTTPS as well as HTTP. The two basic scenarios are: with a stand-alone proxy server or in conjunction with another HTTPS server. diff --git a/lib/node-http-proxy/routing-proxy.js b/lib/node-http-proxy/routing-proxy.js index a4da67b..b769246 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. @@ -51,6 +51,18 @@ var RoutingProxy = exports.RoutingProxy = function (options) { this.https = this.source.https || options.https; this.enable = options.enable; this.forward = options.forward; + + // + // Listen for 'newListener' events so that we can bind 'proxyError' + // listeners to each HttpProxy's 'proxyError' event. + // + this.on('newListener', function (evt) { + if (evt === 'proxyError' || evt === 'webSocketProxyError') { + Object.keys(self.proxies).forEach(function (key) { + self.proxies[key].on(evt, this.emit.bind(this, evt)); + }); + } + }); }; @@ -68,30 +80,37 @@ 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')); + if (this.listeners('proxyError').length > 0) { + this.proxies[key].on('proxyError', this.emit.bind(this, 'proxyError')); + } + if (this.listeners('webSocketProxyError').length > 0) { + this.proxies[key].on('webSocketProxyError', this.emit.bind(this, 'webSocketProxyError')); + } + this.proxies[key].on('start', this.emit.bind(this, 'start')); + this.proxies[key].on('forward', this.emit.bind(this, 'forward')); + this.proxies[key].on('end', this.emit.bind(this, 'end')); }; // @@ -111,18 +130,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 +179,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 +198,14 @@ 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 +224,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 +235,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 +243,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 +255,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(':'); }