From 76580c292a152c0007352a9d383f59e48993cd03 Mon Sep 17 00:00:00 2001 From: indexzero Date: Thu, 19 May 2011 01:33:03 -0400 Subject: [PATCH] [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 --- lib/node-http-proxy.js | 111 +++++++++++++++++++++++------------------ 1 file changed, 63 insertions(+), 48 deletions(-) diff --git a/lib/node-http-proxy.js b/lib/node-http-proxy.js index d95bfdd..938e9bf 100644 --- a/lib/node-http-proxy.js +++ b/lib/node-http-proxy.js @@ -543,9 +543,9 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options } } - function onUpgrade(out, reverseProxy) { - if (!out) { - reverseProxy.end(); + function onUpgrade(reverseProxy, proxySocket) { + if (!reverseProxy) { + proxySocket.end(); socket.end(); return; } @@ -553,46 +553,46 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options var listeners = {}; // We're now connected to the server, so lets change server socket - reverseProxy.on('data', listeners._r_data = function(data) { + proxySocket.on('data', listeners._r_data = function(data) { // Pass data to client - if (out.incoming.socket.writable) { + if (reverseProxy.incoming.socket.writable) { try { - out.incoming.socket.write(data); + reverseProxy.incoming.socket.write(data); } catch (e) { - out.incoming.socket.end(); - reverseProxy.end(); + reverseProxy.incoming.socket.end(); + proxySocket.end(); } } }); - out.incoming.socket.on('data', listeners._data = function(data) { + reverseProxy.incoming.socket.on('data', listeners._data = function(data) { // Pass data from client to server try { - reverseProxy.write(data); + proxySocket.write(data); } catch (e) { - reverseProxy.end(); + proxySocket.end(); socket.end(); } }); // Detach event listeners from reverseProxy function detach() { - reverseProxy.removeListener('end', listeners._r_close); - reverseProxy.removeListener('data', listeners._r_data); - out.incoming.socket.removeListener('data', listeners._data); - out.incoming.socket.removeListener('end', listeners._close); + proxySocket.removeListener('end', listeners._r_close); + proxySocket.removeListener('data', listeners._r_data); + reverseProxy.incoming.socket.removeListener('data', listeners._data); + reverseProxy.incoming.socket.removeListener('end', listeners._close); } // Hook disconnections - reverseProxy.on('end', listeners._r_close = function() { - out.incoming.socket.end(); + proxySocket.on('end', listeners._r_close = function() { + reverseProxy.incoming.socket.end(); detach(); }); - out.incoming.socket.on('end', listeners._close = function() { - reverseProxy.end(); + reverseProxy.incoming.socket.on('end', listeners._close = function() { + proxySocket.end(); detach(); }); }; @@ -620,7 +620,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options }; // Make the outgoing WebSocket request - var request = agent.appendMessage(outgoing); + var reverseProxy = agent.appendMessage(outgoing); // // Here we set the incoming `req`, `socket` and `head` data to the outgoing @@ -628,8 +628,8 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options // available to the `upgrade` event. This bookkeeping is not tracked anywhere // in nodejs core and is **very** specific to proxying WebSockets. // - request.agent = agent; - request.incoming = { + reverseProxy.agent = agent; + reverseProxy.incoming = { request: req, socket: socket, head: head @@ -644,69 +644,84 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options // there is no mapping of the // if (!agent._events || agent._events['upgrade'].length === 0) { - agent.on('upgrade', function (out, remoteSocket, head) { - // Prepare socket + agent.on('upgrade', function (_, remoteSocket, head) { + // + // Prepare the socket for the reverseProxy request and begin to + // stream data between the two sockets + // _socket(remoteSocket, true); - - // Emit event onUpgrade(remoteSocket._httpMessage, remoteSocket); }); } - if (typeof request.socket !== 'undefined') { - request.socket.on('data', function handshake (data) { - // Handshaking - - // Ok, kind of harmfull part of code - // Socket.IO is sending hash at the end of handshake - // If protocol = 76 - // But we need to replace 'host' and 'origin' in response - // So we split data to printable data and to non-printable - // (Non-printable will come after double-CRLF) + // + // If the reverseProxy connection has an underlying socket, + // then behing the handshake. + // + if (typeof reverseProxy.socket !== 'undefined') { + reverseProxy.socket.on('data', function handshake (data) { + // + // Ok, kind of harmfull part of code. Socket.IO sends a hash + // at the end of handshake if protocol === 76, but we need + // to replace 'host' and 'origin' in response so we split + // data to printable data and to non-printable. (Non-printable + // will come after double-CRLF). + // var sdata = data.toString(); - // Get Printable + // Get the Printable data sdata = sdata.substr(0, sdata.search(CRLF + CRLF)); - // Get Non-Printable + // Get the Non-Printable data data = data.slice(Buffer.byteLength(sdata), data.length); - // Replace host and origin + // Replace the host and origin headers in the Printable data sdata = sdata.replace(remoteHost, options.host) .replace(remoteHost, options.host); try { - // Write printable + // + // Write the printable and non-printable data to the socket + // from the original incoming request. + // socket.write(sdata); - - // Write non-printable socket.write(data); } catch (e) { - request.end(); + reverseProxy.end(); socket.end(); } // Catch socket errors socket.on('error', function() { - request.end(); + reverseProxy.end(); + socket.end(); }); // Remove data listener now that the 'handshake' is complete - request.socket.removeListener('data', handshake); + reverseProxy.socket.removeListener('data', handshake); }); } + + reverseProxy.on('error', function (err) { + reverseProxy.end(); + socket.end(); + }); - // Write upgrade-head try { - request.write(head); + // + // Attempt to write the upgrade-head to the reverseProxy request. + // + reverseProxy.write(head); } catch (ex) { - request.end(); + reverseProxy.end(); socket.end(); } + // // If we have been passed buffered data, resume it. + // if (options.buffer && !errState) { options.buffer.resume(); }