Skip to content

Commit f20b374

Browse files
committed
Merge branch 'master' of github.com:nodejitsu/node-http-proxy
2 parents f086692 + a088efd commit f20b374

38 files changed

+2115
-155
lines changed

README.md

+9-3
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,12 @@ By default, `node-http-proxy` will set a 100 socket limit for all `host:port` pr
363363
1. By passing the `maxSockets` option to `httpProxy.createServer()`
364364
2. By calling `httpProxy.setMaxSockets(n)`, where `n` is the number of sockets you with to use.
365365

366+
## POST requests and buffering
367+
368+
express.bodyParser will interfere with proxying of POST requests (and other methods that have a request
369+
body). With bodyParser active, proxied requests will never send anything to the upstream server, and
370+
the original client will just hang. See https://github.com/nodejitsu/node-http-proxy/issues/180 for options.
371+
366372
## Using node-http-proxy from the command line
367373
When you install this package with npm, a node-http-proxy binary will become available to you. Using this binary is easy with some simple options:
368374

@@ -426,9 +432,9 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
426432
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
427433
428434
[0]: http://nodejitsu.com
429-
[1]: https://github.com/nodejitsu/node-http-proxy/blob/master/examples/web-socket-proxy.js
430-
[2]: https://github.com/nodejitsu/node-http-proxy/blob/master/examples/basic-proxy-https.js
431-
[3]: https://github.com/nodejitsu/node-http-proxy/tree/v0.5.0/examples
435+
[1]: https://github.com/nodejitsu/node-http-proxy/blob/master/examples/websocket/websocket-proxy.js
436+
[2]: https://github.com/nodejitsu/node-http-proxy/blob/master/examples/http/proxy-https-to-http.js
437+
[3]: https://github.com/nodejitsu/node-http-proxy/tree/master/examples
432438
[4]: http://www.ietf.org/rfc/rfc2616.txt
433439
[5]: http://socket.io
434440
[6]: http://github.com/nodejitsu/node-http-proxy/issues

examples/http/proxy-https-to-http.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ var https = require('https'),
3434
var opts = helpers.loadHttps();
3535

3636
//
37-
// Crete the target HTTPS server
37+
// Create the target HTTPS server
3838
//
3939
http.createServer(function (req, res) {
4040
res.writeHead(200, { 'Content-Type': 'text/plain' });
@@ -43,7 +43,7 @@ http.createServer(function (req, res) {
4343
}).listen(8000);
4444

4545
//
46-
// Create the proxy server listening on port 443.
46+
// Create the proxy server listening on port 443
4747
//
4848
httpProxy.createServer(8000, 'localhost', {
4949
https: opts

examples/http/proxy-https-to-https.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ var https = require('https'),
3434
var opts = helpers.loadHttps();
3535

3636
//
37-
// Crete the target HTTPS server
37+
// Create the target HTTPS server
3838
//
3939
https.createServer(opts, function (req, res) {
4040
res.writeHead(200, { 'Content-Type': 'text/plain' });
@@ -43,7 +43,7 @@ https.createServer(opts, function (req, res) {
4343
}).listen(8000);
4444

4545
//
46-
// Create the proxy server listening on port 443.
46+
// Create the proxy server listening on port 443
4747
//
4848
httpProxy.createServer(8000, 'localhost', {
4949
https: opts,

examples/websocket/latent-websocket-proxy.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
2525
*/
2626

27-
var sys = require('sys'),
27+
var util = require('util'),
2828
http = require('http'),
2929
colors = require('colors'),
3030
websocket = require('../../vendor/websocket'),
@@ -55,10 +55,10 @@ server.listen(8080);
5555
//
5656
var socket = io.listen(server);
5757
socket.on('connection', function (client) {
58-
sys.debug('Got websocket connection');
58+
util.debug('Got websocket connection');
5959

6060
client.on('message', function (msg) {
61-
sys.debug('Got message from client: ' + msg);
61+
util.debug('Got message from client: ' + msg);
6262
});
6363

6464
socket.broadcast('from server');
@@ -101,5 +101,5 @@ ws.on('open', function () {
101101
});
102102

103103
ws.on('message', function (msg) {
104-
sys.debug('Got message: ' + utils.decode(msg));
104+
util.debug('Got message: ' + utils.decode(msg));
105105
});

examples/websocket/standalone-websocket-proxy.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
2525
*/
2626

27-
var sys = require('sys'),
27+
var util = require('util'),
2828
http = require('http'),
2929
colors = require('colors'),
3030
websocket = require('../../vendor/websocket'),
@@ -55,10 +55,10 @@ server.listen(8080);
5555
//
5656
var socket = io.listen(server);
5757
socket.on('connection', function (client) {
58-
sys.debug('Got websocket connection');
58+
util.debug('Got websocket connection');
5959

6060
client.on('message', function (msg) {
61-
sys.debug('Got message from client: ' + msg);
61+
util.debug('Got message from client: ' + msg);
6262
});
6363

6464
socket.broadcast('from server');
@@ -97,5 +97,5 @@ ws.on('open', function () {
9797
});
9898

9999
ws.on('message', function (msg) {
100-
sys.debug('Got message: ' + utils.decode(msg));
100+
util.debug('Got message: ' + utils.decode(msg));
101101
});

examples/websocket/websocket-proxy.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
2525
*/
2626

27-
var sys = require('sys'),
27+
var util = require('util'),
2828
http = require('http'),
2929
colors = require('colors'),
3030
websocket = require('../../vendor/websocket'),
@@ -55,10 +55,10 @@ server.listen(8080);
5555
//
5656
var socket = io.listen(server);
5757
socket.on('connection', function (client) {
58-
sys.debug('Got websocket connection');
58+
util.debug('Got websocket connection');
5959

6060
client.on('message', function (msg) {
61-
sys.debug('Got message from client: ' + msg);
61+
util.debug('Got message from client: ' + msg);
6262
});
6363

6464
socket.broadcast('from server');
@@ -80,5 +80,5 @@ ws.on('open', function () {
8080
});
8181

8282
ws.on('message', function (msg) {
83-
sys.debug('Got message: ' + utils.decode(msg));
83+
util.debug('Got message: ' + utils.decode(msg));
8484
});

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

+93-33
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
*/
2626

2727
var events = require('events'),
28+
http = require('http'),
2829
util = require('util'),
2930
httpProxy = require('../node-http-proxy');
3031

@@ -122,17 +123,37 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) {
122123

123124
//
124125
// Add common proxy headers to the request so that they can
125-
// be availible to the proxy target server:
126+
// be availible to the proxy target server. If the proxy is
127+
// part of proxy chain it will append the address:
126128
//
127129
// * `x-forwarded-for`: IP Address of the original request
128130
// * `x-forwarded-proto`: Protocol of the original request
129131
// * `x-forwarded-port`: Port of the original request.
130132
//
131-
132133
if (this.enable.xforward && req.connection && req.socket) {
133-
req.headers['x-forwarded-for'] = req.connection.remoteAddress || req.socket.remoteAddress;
134-
req.headers['x-forwarded-port'] = req.connection.remotePort || req.socket.remotePort;
135-
req.headers['x-forwarded-proto'] = req.connection.pair ? 'https' : 'http';
134+
if (req.headers['x-forwarded-for']){
135+
var addressToAppend = "," + req.connection.remoteAddress || req.socket.remoteAddress;
136+
req.headers['x-forwarded-for'] += addressToAppend;
137+
}
138+
else {
139+
req.headers['x-forwarded-for'] = req.connection.remoteAddress || req.socket.remoteAddress;
140+
}
141+
142+
if (req.headers['x-forwarded-port']){
143+
var portToAppend = "," + req.connection.remotePort || req.socket.remotePort;
144+
req.headers['x-forwarded-port'] += portToAppend;
145+
}
146+
else {
147+
req.headers['x-forwarded-port'] = req.connection.remotePort || req.socket.remotePort;
148+
}
149+
150+
if (req.headers['x-forwarded-proto']){
151+
var protoToAppend = "," + req.connection.pair ? 'https' : 'http';
152+
req.headers['x-forwarded-proto'] += protoToAppend;
153+
}
154+
else {
155+
req.headers['x-forwarded-proto'] = req.connection.pair ? 'https' : 'http';
156+
}
136157
}
137158

138159
//
@@ -213,6 +234,15 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) {
213234
delete response.headers['transfer-encoding'];
214235
}
215236

237+
if ((response.statusCode === 301) || (response.statusCode === 302)) {
238+
if (self.source.https && !self.target.https) {
239+
response.headers.location = response.headers.location.replace(/^http\:/, 'https:');
240+
}
241+
if (self.target.https && !self.source.https) {
242+
response.headers.location = response.headers.location.replace(/^https\:/, 'http:');
243+
}
244+
}
245+
216246
// Set the headers of the client response
217247
res.writeHead(response.statusCode, response.headers);
218248

@@ -271,11 +301,19 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) {
271301
//
272302
reverseProxy.once('error', proxyError);
273303

304+
//
305+
// If `req` is aborted, we abort our `reverseProxy` request as well.
306+
//
307+
req.on('aborted', function () {
308+
reverseProxy.abort();
309+
});
310+
274311
//
275312
// For each data `chunk` received from the incoming
276313
// `req` write it to the `reverseProxy` request.
277314
//
278315
req.on('data', function (chunk) {
316+
279317
if (!errState) {
280318
var flushed = reverseProxy.write(chunk);
281319
if (!flushed) {
@@ -352,16 +390,37 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer)
352390

353391
//
354392
// Add common proxy headers to the request so that they can
355-
// be availible to the proxy target server:
393+
// be availible to the proxy target server. If the proxy is
394+
// part of proxy chain it will append the address:
356395
//
357396
// * `x-forwarded-for`: IP Address of the original request
358397
// * `x-forwarded-proto`: Protocol of the original request
359398
// * `x-forwarded-port`: Port of the original request.
360399
//
361400
if (this.enable.xforward && req.connection && req.connection.socket) {
362-
req.headers['x-forwarded-for'] = req.connection.remoteAddress || req.connection.socket.remoteAddress;
363-
req.headers['x-forwarded-port'] = req.connection.remotePort || req.connection.socket.remotePort;
364-
req.headers['x-forwarded-proto'] = req.connection.pair ? 'https' : 'http';
401+
if (req.headers['x-forwarded-for']){
402+
var addressToAppend = "," + req.connection.remoteAddress || req.connection.socket.remoteAddress;
403+
req.headers['x-forwarded-for'] += addressToAppend;
404+
}
405+
else {
406+
req.headers['x-forwarded-for'] = req.connection.remoteAddress || req.connection.socket.remoteAddress;
407+
}
408+
409+
if (req.headers['x-forwarded-port']){
410+
var portToAppend = "," + req.connection.remotePort || req.connection.socket.remotePort;
411+
req.headers['x-forwarded-port'] += portToAppend;
412+
}
413+
else {
414+
req.headers['x-forwarded-port'] = req.connection.remotePort || req.connection.socket.remotePort;
415+
}
416+
417+
if (req.headers['x-forwarded-proto']){
418+
var protoToAppend = "," + req.connection.pair ? 'wss' : 'ws';
419+
req.headers['x-forwarded-proto'] += protoToAppend;
420+
}
421+
else {
422+
req.headers['x-forwarded-proto'] = req.connection.pair ? 'wss' : 'ws';
423+
}
365424
}
366425

367426
//
@@ -527,11 +586,13 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer)
527586
//
528587
outgoing.host = this.target.host;
529588
outgoing.port = this.target.port;
589+
outgoing.agent = agent;
530590
outgoing.method = 'GET';
531591
outgoing.path = req.url;
532592
outgoing.headers = req.headers;
593+
outgoing.agent = agent;
533594

534-
var reverseProxy = agent.appendMessage(outgoing);
595+
var reverseProxy = this.target.protocol.request(outgoing);
535596

536597
//
537598
// On any errors from the `reverseProxy` emit the
@@ -553,7 +614,6 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer)
553614
// available to the `upgrade` event. This bookkeeping is not tracked anywhere
554615
// in nodejs core and is **very** specific to proxying WebSockets.
555616
//
556-
reverseProxy.agent = agent;
557617
reverseProxy.incoming = {
558618
request: req,
559619
socket: socket,
@@ -568,24 +628,22 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer)
568628
// In addition, it's important to note the closure scope here. Since
569629
// there is no mapping of the socket to the request bound to it.
570630
//
571-
if (!agent._events || agent._events['upgrade'].length === 0) {
572-
agent.on('upgrade', function (_, remoteSocket, head) {
573-
//
574-
// Prepare the socket for the reverseProxy request and begin to
575-
// stream data between the two sockets. Here it is important to
576-
// note that `remoteSocket._httpMessage === reverseProxy`.
577-
//
578-
_socket(remoteSocket, true);
579-
onUpgrade(remoteSocket._httpMessage, remoteSocket);
580-
});
581-
}
631+
reverseProxy.on('upgrade', function (_, remoteSocket, head) {
632+
//
633+
// Prepare the socket for the reverseProxy request and begin to
634+
// stream data between the two sockets. Here it is important to
635+
// note that `remoteSocket._httpMessage === reverseProxy`.
636+
//
637+
_socket(remoteSocket, true);
638+
onUpgrade(remoteSocket._httpMessage, remoteSocket);
639+
});
582640

583641
//
584642
// If the reverseProxy connection has an underlying socket,
585643
// then execute the WebSocket handshake.
586644
//
587-
if (typeof reverseProxy.socket !== 'undefined') {
588-
reverseProxy.socket.on('data', function handshake (data) {
645+
reverseProxy.once('socket', function (revSocket) {
646+
revSocket.on('data', function handshake (data) {
589647
//
590648
// Ok, kind of harmfull part of code. Socket.IO sends a hash
591649
// at the end of handshake if protocol === 76, but we need
@@ -618,12 +676,12 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer)
618676
socket.write(sdata);
619677
var flushed = socket.write(data);
620678
if (!flushed) {
621-
reverseProxy.socket.pause();
679+
revSocket.pause();
622680
socket.once('drain', function () {
623-
try { reverseProxy.socket.resume() }
681+
try { revSocket.resume() }
624682
catch (er) { console.error("reverseProxy.socket.resume error: %s", er.message) }
625683
});
626-
684+
627685
//
628686
// Force the `drain` event in 100ms if it hasn't
629687
// happened on its own.
@@ -638,7 +696,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer)
638696
// Remove data listener on socket error because the
639697
// 'handshake' has failed.
640698
//
641-
reverseProxy.socket.removeListener('data', handshake);
699+
revSocket.removeListener('data', handshake);
642700
return proxyError(ex);
643701
}
644702

@@ -648,9 +706,9 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer)
648706
//
649707
// Remove data listener now that the 'handshake' is complete
650708
//
651-
reverseProxy.socket.removeListener('data', handshake);
709+
revSocket.removeListener('data', handshake);
652710
});
653-
}
711+
});
654712

655713
reverseProxy.on('error', proxyError);
656714

@@ -689,9 +747,11 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, buffer)
689747
HttpProxy.prototype.close = function () {
690748
[this.forward, this.target].forEach(function (proxy) {
691749
if (proxy && proxy.agent) {
692-
proxy.agent.sockets.forEach(function (socket) {
693-
socket.end();
694-
});
750+
for (var host in proxy.agent.sockets) {
751+
proxy.agent.sockets[host].forEach(function (socket) {
752+
socket.end();
753+
});
754+
}
695755
}
696756
});
697757
};

0 commit comments

Comments
 (0)