Skip to content

Commit 76580c2

Browse files
committed
[fix doc] Add error handler to reverseProxy request when proxying WebSockets to prevent unhandled ParseError. Rename some variables in proxyWebSocketRequest to make the code more readable
1 parent acacc05 commit 76580c2

File tree

1 file changed

+63
-48
lines changed

1 file changed

+63
-48
lines changed

lib/node-http-proxy.js

+63-48
Original file line numberDiff line numberDiff line change
@@ -543,56 +543,56 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options
543543
}
544544
}
545545

546-
function onUpgrade(out, reverseProxy) {
547-
if (!out) {
548-
reverseProxy.end();
546+
function onUpgrade(reverseProxy, proxySocket) {
547+
if (!reverseProxy) {
548+
proxySocket.end();
549549
socket.end();
550550
return;
551551
}
552552

553553
var listeners = {};
554554

555555
// We're now connected to the server, so lets change server socket
556-
reverseProxy.on('data', listeners._r_data = function(data) {
556+
proxySocket.on('data', listeners._r_data = function(data) {
557557
// Pass data to client
558-
if (out.incoming.socket.writable) {
558+
if (reverseProxy.incoming.socket.writable) {
559559
try {
560-
out.incoming.socket.write(data);
560+
reverseProxy.incoming.socket.write(data);
561561
}
562562
catch (e) {
563-
out.incoming.socket.end();
564-
reverseProxy.end();
563+
reverseProxy.incoming.socket.end();
564+
proxySocket.end();
565565
}
566566
}
567567
});
568568

569-
out.incoming.socket.on('data', listeners._data = function(data) {
569+
reverseProxy.incoming.socket.on('data', listeners._data = function(data) {
570570
// Pass data from client to server
571571
try {
572-
reverseProxy.write(data);
572+
proxySocket.write(data);
573573
}
574574
catch (e) {
575-
reverseProxy.end();
575+
proxySocket.end();
576576
socket.end();
577577
}
578578
});
579579

580580
// Detach event listeners from reverseProxy
581581
function detach() {
582-
reverseProxy.removeListener('end', listeners._r_close);
583-
reverseProxy.removeListener('data', listeners._r_data);
584-
out.incoming.socket.removeListener('data', listeners._data);
585-
out.incoming.socket.removeListener('end', listeners._close);
582+
proxySocket.removeListener('end', listeners._r_close);
583+
proxySocket.removeListener('data', listeners._r_data);
584+
reverseProxy.incoming.socket.removeListener('data', listeners._data);
585+
reverseProxy.incoming.socket.removeListener('end', listeners._close);
586586
}
587587

588588
// Hook disconnections
589-
reverseProxy.on('end', listeners._r_close = function() {
590-
out.incoming.socket.end();
589+
proxySocket.on('end', listeners._r_close = function() {
590+
reverseProxy.incoming.socket.end();
591591
detach();
592592
});
593593

594-
out.incoming.socket.on('end', listeners._close = function() {
595-
reverseProxy.end();
594+
reverseProxy.incoming.socket.on('end', listeners._close = function() {
595+
proxySocket.end();
596596
detach();
597597
});
598598
};
@@ -620,16 +620,16 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options
620620
};
621621

622622
// Make the outgoing WebSocket request
623-
var request = agent.appendMessage(outgoing);
623+
var reverseProxy = agent.appendMessage(outgoing);
624624

625625
//
626626
// Here we set the incoming `req`, `socket` and `head` data to the outgoing
627627
// request so that we can reuse this data later on in the closure scope
628628
// available to the `upgrade` event. This bookkeeping is not tracked anywhere
629629
// in nodejs core and is **very** specific to proxying WebSockets.
630630
//
631-
request.agent = agent;
632-
request.incoming = {
631+
reverseProxy.agent = agent;
632+
reverseProxy.incoming = {
633633
request: req,
634634
socket: socket,
635635
head: head
@@ -644,69 +644,84 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options
644644
// there is no mapping of the
645645
//
646646
if (!agent._events || agent._events['upgrade'].length === 0) {
647-
agent.on('upgrade', function (out, remoteSocket, head) {
648-
// Prepare socket
647+
agent.on('upgrade', function (_, remoteSocket, head) {
648+
//
649+
// Prepare the socket for the reverseProxy request and begin to
650+
// stream data between the two sockets
651+
//
649652
_socket(remoteSocket, true);
650-
651-
// Emit event
652653
onUpgrade(remoteSocket._httpMessage, remoteSocket);
653654
});
654655
}
655656

656-
if (typeof request.socket !== 'undefined') {
657-
request.socket.on('data', function handshake (data) {
658-
// Handshaking
659-
660-
// Ok, kind of harmfull part of code
661-
// Socket.IO is sending hash at the end of handshake
662-
// If protocol = 76
663-
// But we need to replace 'host' and 'origin' in response
664-
// So we split data to printable data and to non-printable
665-
// (Non-printable will come after double-CRLF)
657+
//
658+
// If the reverseProxy connection has an underlying socket,
659+
// then behing the handshake.
660+
//
661+
if (typeof reverseProxy.socket !== 'undefined') {
662+
reverseProxy.socket.on('data', function handshake (data) {
663+
//
664+
// Ok, kind of harmfull part of code. Socket.IO sends a hash
665+
// at the end of handshake if protocol === 76, but we need
666+
// to replace 'host' and 'origin' in response so we split
667+
// data to printable data and to non-printable. (Non-printable
668+
// will come after double-CRLF).
669+
//
666670
var sdata = data.toString();
667671

668-
// Get Printable
672+
// Get the Printable data
669673
sdata = sdata.substr(0, sdata.search(CRLF + CRLF));
670674

671-
// Get Non-Printable
675+
// Get the Non-Printable data
672676
data = data.slice(Buffer.byteLength(sdata), data.length);
673677

674-
// Replace host and origin
678+
// Replace the host and origin headers in the Printable data
675679
sdata = sdata.replace(remoteHost, options.host)
676680
.replace(remoteHost, options.host);
677681

678682
try {
679-
// Write printable
683+
//
684+
// Write the printable and non-printable data to the socket
685+
// from the original incoming request.
686+
//
680687
socket.write(sdata);
681-
682-
// Write non-printable
683688
socket.write(data);
684689
}
685690
catch (e) {
686-
request.end();
691+
reverseProxy.end();
687692
socket.end();
688693
}
689694

690695
// Catch socket errors
691696
socket.on('error', function() {
692-
request.end();
697+
reverseProxy.end();
698+
socket.end();
693699
});
694700

695701
// Remove data listener now that the 'handshake' is complete
696-
request.socket.removeListener('data', handshake);
702+
reverseProxy.socket.removeListener('data', handshake);
697703
});
698704
}
705+
706+
reverseProxy.on('error', function (err) {
707+
reverseProxy.end();
708+
socket.end();
709+
});
699710

700-
// Write upgrade-head
701711
try {
702-
request.write(head);
712+
//
713+
// Attempt to write the upgrade-head to the reverseProxy request.
714+
//
715+
reverseProxy.write(head);
703716
}
704717
catch (ex) {
705-
request.end();
718+
reverseProxy.end();
706719
socket.end();
707720
}
708721

722+
//
709723
// If we have been passed buffered data, resume it.
724+
//
710725
if (options.buffer && !errState) {
711726
options.buffer.resume();
712727
}

0 commit comments

Comments
 (0)