Merge pull request #216 from CodeRarity/master

Re-emit 'start', 'forward' and 'end' events in RoutingProxy, and fix some hanging issues.
This commit is contained in:
Christian Howe 2012-05-10 09:34:46 -07:00
commit f223ce8b4e
2 changed files with 73 additions and 29 deletions

View File

@ -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'. 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 ## 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. 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.

View File

@ -23,26 +23,26 @@ var RoutingProxy = exports.RoutingProxy = function (options) {
var self = this; var self = this;
options = options || {}; options = options || {};
if (options.router) { if (options.router) {
this.proxyTable = new ProxyTable(options); this.proxyTable = new ProxyTable(options);
this.proxyTable.on('routes', function (routes) { this.proxyTable.on('routes', function (routes) {
self.emit('routes', 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()`. // to `.proxyRequest()` and `.proxyWebSocketRequest()`.
// //
this.proxies = {}; this.proxies = {};
// //
// Setup default target options (such as `https`). // Setup default target options (such as `https`).
// //
this.target = {}; this.target = {};
this.target.https = options.target && options.target.https; this.target.https = options.target && options.target.https;
// //
// Setup other default options to be used for instances of // Setup other default options to be used for instances of
// `HttpProxy` created by this `RoutingProxy` instance. // `HttpProxy` created by this `RoutingProxy` instance.
@ -51,6 +51,18 @@ var RoutingProxy = exports.RoutingProxy = function (options) {
this.https = this.source.https || options.https; this.https = this.source.https || options.https;
this.enable = options.enable; this.enable = options.enable;
this.forward = options.forward; 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) { RoutingProxy.prototype.add = function (options) {
var self = this, var self = this,
key = this._getKey(options); key = this._getKey(options);
// //
// TODO: Consume properties in `options` related to the `ProxyTable`. // TODO: Consume properties in `options` related to the `ProxyTable`.
// //
options.target = options.target || {}; options.target = options.target || {};
options.target.host = options.target.host || options.host; options.target.host = options.target.host || options.host;
options.target.port = options.target.port || options.port; options.target.port = options.target.port || options.port;
options.target.https = this.target && this.target.https || options.target.https = this.target && this.target.https ||
options.target && options.target.https || options.target && options.target.https ||
options.https; options.https;
// //
// Setup options to pass-thru to the new `HttpProxy` instance // 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) { ['https', 'enable', 'forward'].forEach(function (key) {
if (options[key] !== false && self[key]) { if (options[key] !== false && self[key]) {
options[key] = self[key]; options[key] = self[key];
} }
}); });
this.proxies[key] = new HttpProxy(options); this.proxies[key] = new HttpProxy(options);
this.proxies[key].on('proxyError', this.emit.bind(this, 'proxyError')); if (this.listeners('proxyError').length > 0) {
this.proxies[key].on('webSocketProxyError', this.emit.bind(this, 'webSocketProxyError')); 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 () { RoutingProxy.prototype.close = function () {
var self = this; var self = this;
if (this.proxyTable) { if (this.proxyTable) {
// //
// Close the `RoutingTable` associated with // Close the `RoutingTable` associated with
// this instance (if any). // this instance (if any).
// //
this.proxyTable.close(); this.proxyTable.close();
} }
// //
// Close all sockets for all `HttpProxy` object(s) // Close all sockets for all `HttpProxy` object(s)
// associated with this instance. // associated with this instance.
// //
Object.keys(this.proxies).forEach(function (key) { Object.keys(this.proxies).forEach(function (key) {
self.proxies[key].close(); self.proxies[key].close();
@ -160,11 +179,11 @@ RoutingProxy.prototype.proxyRequest = function (req, res, options) {
try { try {
res.writeHead(404); res.writeHead(404);
res.end(); res.end();
} }
catch (er) { catch (er) {
console.error("res.writeHead/res.end error: %s", er.message); console.error("res.writeHead/res.end error: %s", er.message);
} }
return; return;
} }
@ -179,15 +198,14 @@ RoutingProxy.prototype.proxyRequest = function (req, res, options) {
options.port = location.port; options.port = location.port;
options.host = location.host; options.host = location.host;
} }
var key = this._getKey(options), var key = this._getKey(options),
proxy; proxy;
if (!this.proxies[key]) { if (!this.proxies[key]) {
this.add(options); this.add(options);
}
}
proxy = this.proxies[key]; proxy = this.proxies[key];
proxy.proxyRequest(req, res, options.buffer); 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) { RoutingProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options) {
options = options || {}; options = options || {};
if (this.proxyTable && !options.host) { if (this.proxyTable && !options.host) {
location = this.proxyTable.getProxyLocation(req); location = this.proxyTable.getProxyLocation(req);
@ -217,7 +235,7 @@ RoutingProxy.prototype.proxyWebSocketRequest = function (req, socket, head, opti
options.port = location.port; options.port = location.port;
options.host = location.host; options.host = location.host;
} }
var key = this._getKey(options), var key = this._getKey(options),
proxy; proxy;
@ -225,7 +243,7 @@ RoutingProxy.prototype.proxyWebSocketRequest = function (req, socket, head, opti
this.add(options); this.add(options);
} }
proxy = this.proxies[key]; proxy = this.proxies[key];
proxy.proxyWebSocketRequest(req, socket, head, options.buffer); proxy.proxyWebSocketRequest(req, socket, head, options.buffer);
}; };
@ -237,14 +255,14 @@ RoutingProxy.prototype.proxyWebSocketRequest = function (req, socket, head, opti
// combination contained within. // combination contained within.
// //
RoutingProxy.prototype._getKey = function (options) { 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))) { && (!options.target || !options.target.host || !options.target.port))) {
throw new Error('options.host and options.port or options.target are required.'); throw new Error('options.host and options.port or options.target are required.');
return; return;
} }
return [ return [
options.host || options.target.host, options.host || options.target.host,
options.port || options.target.port options.port || options.target.port
].join(':'); ].join(':');
} }