Skip to content

Commit 2b9e09b

Browse files
isaacsindexzero
authored andcommitted
Add flow control
Not in the "async/fibers/coro" sense of flow control, but in the TCP backpressure sense. Pause the stream when a write isn't flushed, and then resume it once the writable stream drains.
1 parent 967884c commit 2b9e09b

File tree

1 file changed

+46
-8
lines changed

1 file changed

+46
-8
lines changed

Diff for: lib/node-http-proxy.js

+46-8
Original file line numberDiff line numberDiff line change
@@ -539,16 +539,23 @@ HttpProxy.prototype.proxyRequest = function (req, res, options) {
539539
response.on('data', function (chunk) {
540540
if (req.method !== 'HEAD' && res.writable) {
541541
try {
542-
res.write(chunk);
542+
var flushed = res.write(chunk);
543543
} catch (er) {
544544
console.error("res.write error: %s", er.message);
545545
try {
546546
res.end();
547547
} catch (er) {
548548
console.error("res.end error: %s", er.message);
549549
}
550+
return;
550551
}
551552
}
553+
if (!flushed) {
554+
response.pause();
555+
res.once('drain', function () {
556+
response.resume();
557+
});
558+
}
552559
});
553560

554561
// When the `reverseProxy` `response` ends, end the
@@ -578,7 +585,13 @@ HttpProxy.prototype.proxyRequest = function (req, res, options) {
578585
// `req` write it to the `reverseProxy` request.
579586
req.on('data', function (chunk) {
580587
if (!errState) {
581-
reverseProxy.write(chunk);
588+
var flushed = reverseProxy.write(chunk);
589+
if (!flushed) {
590+
req.pause();
591+
reverseProxy.once('drain', function () {
592+
req.resume();
593+
});
594+
}
582595
}
583596
});
584597

@@ -646,7 +659,13 @@ HttpProxy.prototype._forwardRequest = function (req) {
646659

647660
// Chunk the client request body as chunks from the proxied request come in
648661
req.on('data', function (chunk) {
649-
forwardProxy.write(chunk);
662+
var flushed = forwardProxy.write(chunk);
663+
if (!flushed) {
664+
req.pause();
665+
forwardProxy.once('drain', function () {
666+
req.resume();
667+
});
668+
}
650669
})
651670

652671
// At the end of the client request, we are going to stop the proxied request
@@ -741,7 +760,13 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options
741760
if (reverseProxy.incoming.socket.writable) {
742761
try {
743762
self.emit('websocket:outgoing', req, socket, head, data);
744-
reverseProxy.incoming.socket.write(data);
763+
var flushed = reverseProxy.incoming.socket.write(data);
764+
if (!flushed) {
765+
proxySocket.pause();
766+
reverseProxy.incoming.socket.once('drain', function () {
767+
proxySocket.resume();
768+
});
769+
}
745770
}
746771
catch (e) {
747772
detach();
@@ -758,7 +783,13 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options
758783
reverseProxy.incoming.socket.on('data', listeners.onOutgoing = function(data) {
759784
try {
760785
self.emit('websocket:incoming', reverseProxy, reverseProxy.incoming, head, data);
761-
proxySocket.write(data);
786+
var flushed = proxySocket.write(data);
787+
if (!flushed) {
788+
reverseProxy.incoming.socket.pause();
789+
proxySocket.once('drain', function () {
790+
reverseProxy.incoming.socket.resume();
791+
});
792+
}
762793
}
763794
catch (e) {
764795
detach();
@@ -918,7 +949,14 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options
918949
//
919950
self.emit('websocket:handshake', req, socket, head, sdata, data);
920951
socket.write(sdata);
921-
socket.write(data);
952+
var flushed = socket.write(data);
953+
if (!flushed) {
954+
reverseProxy.socket.pause();
955+
socket.once('drain', function () {
956+
reverseProxy.socket.resume();
957+
});
958+
}
959+
922960
}
923961
catch (ex) {
924962
proxyError(ex)
@@ -935,9 +973,9 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options
935973
reverseProxy.on('error', proxyError);
936974

937975
try {
938-
//
939976
// Attempt to write the upgrade-head to the reverseProxy request.
940-
//
977+
// This is small, and there's only ever one of it.
978+
// No need for pause/resume.
941979
reverseProxy.write(head);
942980
}
943981
catch (ex) {

0 commit comments

Comments
 (0)