Skip to content

Commit f223ce8

Browse files
committed
Merge pull request #216 from CodeRarity/master
Re-emit 'start', 'forward' and 'end' events in RoutingProxy, and fix some hanging issues.
2 parents 27316e2 + b26b434 commit f223ce8

File tree

2 files changed

+73
-29
lines changed

2 files changed

+73
-29
lines changed

README.md

+26
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,32 @@ proxyServerWithForwarding.listen(80);
217217

218218
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'.
219219

220+
### Listening for proxy events
221+
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.
222+
223+
``` js
224+
var httpProxy = require('http-proxy');
225+
226+
var server = httpProxy.createServer(function (req, res, proxy) {
227+
228+
var buffer = httpProxy.buffer(req);
229+
230+
proxy.proxyRequest(req, res, {
231+
host: '127.0.0.1',
232+
port: 9000,
233+
buffer: buffer
234+
});
235+
236+
});
237+
238+
server.proxy.on('end', function() {
239+
console.log("The request was proxied.");
240+
});
241+
242+
server.listen(8000);
243+
```
244+
245+
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.
220246

221247
## Using HTTPS
222248
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.

lib/node-http-proxy/routing-proxy.js

+47-29
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,26 @@ var RoutingProxy = exports.RoutingProxy = function (options) {
2323

2424
var self = this;
2525
options = options || {};
26-
26+
2727
if (options.router) {
2828
this.proxyTable = new ProxyTable(options);
2929
this.proxyTable.on('routes', function (routes) {
3030
self.emit('routes', routes);
3131
});
3232
}
33-
33+
3434
//
35-
// Create a set of `HttpProxy` objects to be used later on calls
35+
// Create a set of `HttpProxy` objects to be used later on calls
3636
// to `.proxyRequest()` and `.proxyWebSocketRequest()`.
3737
//
3838
this.proxies = {};
39-
39+
4040
//
4141
// Setup default target options (such as `https`).
4242
//
4343
this.target = {};
4444
this.target.https = options.target && options.target.https;
45-
45+
4646
//
4747
// Setup other default options to be used for instances of
4848
// `HttpProxy` created by this `RoutingProxy` instance.
@@ -51,6 +51,18 @@ var RoutingProxy = exports.RoutingProxy = function (options) {
5151
this.https = this.source.https || options.https;
5252
this.enable = options.enable;
5353
this.forward = options.forward;
54+
55+
//
56+
// Listen for 'newListener' events so that we can bind 'proxyError'
57+
// listeners to each HttpProxy's 'proxyError' event.
58+
//
59+
this.on('newListener', function (evt) {
60+
if (evt === 'proxyError' || evt === 'webSocketProxyError') {
61+
Object.keys(self.proxies).forEach(function (key) {
62+
self.proxies[key].on(evt, this.emit.bind(this, evt));
63+
});
64+
}
65+
});
5466
};
5567

5668

@@ -68,30 +80,37 @@ util.inherits(RoutingProxy, events.EventEmitter);
6880
RoutingProxy.prototype.add = function (options) {
6981
var self = this,
7082
key = this._getKey(options);
71-
83+
7284
//
7385
// TODO: Consume properties in `options` related to the `ProxyTable`.
7486
//
7587
options.target = options.target || {};
7688
options.target.host = options.target.host || options.host;
7789
options.target.port = options.target.port || options.port;
78-
options.target.https = this.target && this.target.https ||
79-
options.target && options.target.https ||
90+
options.target.https = this.target && this.target.https ||
91+
options.target && options.target.https ||
8092
options.https;
81-
93+
8294
//
8395
// Setup options to pass-thru to the new `HttpProxy` instance
84-
// for the specified `options.host` and `options.port` pair.
96+
// for the specified `options.host` and `options.port` pair.
8597
//
8698
['https', 'enable', 'forward'].forEach(function (key) {
8799
if (options[key] !== false && self[key]) {
88100
options[key] = self[key];
89101
}
90102
});
91-
103+
92104
this.proxies[key] = new HttpProxy(options);
93-
this.proxies[key].on('proxyError', this.emit.bind(this, 'proxyError'));
94-
this.proxies[key].on('webSocketProxyError', this.emit.bind(this, 'webSocketProxyError'));
105+
if (this.listeners('proxyError').length > 0) {
106+
this.proxies[key].on('proxyError', this.emit.bind(this, 'proxyError'));
107+
}
108+
if (this.listeners('webSocketProxyError').length > 0) {
109+
this.proxies[key].on('webSocketProxyError', this.emit.bind(this, 'webSocketProxyError'));
110+
}
111+
this.proxies[key].on('start', this.emit.bind(this, 'start'));
112+
this.proxies[key].on('forward', this.emit.bind(this, 'forward'));
113+
this.proxies[key].on('end', this.emit.bind(this, 'end'));
95114
};
96115

97116
//
@@ -111,18 +130,18 @@ RoutingProxy.prototype.remove = function (options) {
111130
//
112131
RoutingProxy.prototype.close = function () {
113132
var self = this;
114-
133+
115134
if (this.proxyTable) {
116135
//
117-
// Close the `RoutingTable` associated with
136+
// Close the `RoutingTable` associated with
118137
// this instance (if any).
119138
//
120139
this.proxyTable.close();
121140
}
122-
141+
123142
//
124143
// Close all sockets for all `HttpProxy` object(s)
125-
// associated with this instance.
144+
// associated with this instance.
126145
//
127146
Object.keys(this.proxies).forEach(function (key) {
128147
self.proxies[key].close();
@@ -160,11 +179,11 @@ RoutingProxy.prototype.proxyRequest = function (req, res, options) {
160179
try {
161180
res.writeHead(404);
162181
res.end();
163-
}
182+
}
164183
catch (er) {
165184
console.error("res.writeHead/res.end error: %s", er.message);
166185
}
167-
186+
168187
return;
169188
}
170189

@@ -179,15 +198,14 @@ RoutingProxy.prototype.proxyRequest = function (req, res, options) {
179198
options.port = location.port;
180199
options.host = location.host;
181200
}
182-
201+
183202
var key = this._getKey(options),
184203
proxy;
185-
204+
186205
if (!this.proxies[key]) {
187206
this.add(options);
188-
189-
}
190-
207+
}
208+
191209
proxy = this.proxies[key];
192210
proxy.proxyRequest(req, res, options.buffer);
193211
};
@@ -206,7 +224,7 @@ RoutingProxy.prototype.proxyRequest = function (req, res, options) {
206224
//
207225
RoutingProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options) {
208226
options = options || {};
209-
227+
210228
if (this.proxyTable && !options.host) {
211229
location = this.proxyTable.getProxyLocation(req);
212230

@@ -217,15 +235,15 @@ RoutingProxy.prototype.proxyWebSocketRequest = function (req, socket, head, opti
217235
options.port = location.port;
218236
options.host = location.host;
219237
}
220-
238+
221239
var key = this._getKey(options),
222240
proxy;
223241

224242
if (!this.proxies[key]) {
225243
this.add(options);
226244
}
227245

228-
proxy = this.proxies[key];
246+
proxy = this.proxies[key];
229247
proxy.proxyWebSocketRequest(req, socket, head, options.buffer);
230248
};
231249

@@ -237,14 +255,14 @@ RoutingProxy.prototype.proxyWebSocketRequest = function (req, socket, head, opti
237255
// combination contained within.
238256
//
239257
RoutingProxy.prototype._getKey = function (options) {
240-
if (!options || ((!options.host || !options.port)
258+
if (!options || ((!options.host || !options.port)
241259
&& (!options.target || !options.target.host || !options.target.port))) {
242260
throw new Error('options.host and options.port or options.target are required.');
243261
return;
244262
}
245263

246264
return [
247-
options.host || options.target.host,
265+
options.host || options.target.host,
248266
options.port || options.target.port
249267
].join(':');
250268
}

0 commit comments

Comments
 (0)