diff --git a/lib/node-http-proxy.js b/lib/node-http-proxy.js index 9f3521c..7043e83 100644 --- a/lib/node-http-proxy.js +++ b/lib/node-http-proxy.js @@ -530,24 +530,30 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options } } - function onUpgrade(reverseProxy) { + function onUpgrade(out, reverseProxy) { + if (!out) { + reverseProxy.end(); + socket.end(); + return; + } + var listeners = {}; // We're now connected to the server, so lets change server socket reverseProxy.on('data', listeners._r_data = function(data) { // Pass data to client - if (socket.writable) { + if (out.incoming.socket.writable) { try { - socket.write(data); + out.incoming.socket.write(data); } catch (e) { - socket.end(); + out.incoming.socket.end(); reverseProxy.end(); } } }); - socket.on('data', listeners._data = function(data) { + out.incoming.socket.on('data', listeners._data = function(data) { // Pass data from client to server try { reverseProxy.write(data); @@ -562,13 +568,13 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options function detach() { reverseProxy.removeListener('close', listeners._r_close); reverseProxy.removeListener('data', listeners._r_data); - socket.removeListener('data', listeners._data); - socket.removeListener('close', listeners._close); + out.incoming.socket.removeListener('data', listeners._data); + out.incoming.socket.removeListener('close', listeners._close); } // Hook disconnections reverseProxy.on('end', listeners._r_close = function() { - socket.end(); + out.incoming.socket.end(); detach(); }); @@ -592,27 +598,47 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options outgoing = { host: options.host, port: options.port, - agent: agent, method: 'GET', path: req.url, - headers: req.headers + headers: req.headers, }; // Make the outgoing WebSocket request - var request = http.request(outgoing, function () { }); - - // Not disconnect on update - agent.on('upgrade', function(request, remoteSocket, head) { - // Prepare socket - _socket(remoteSocket, true); + var request = agent.appendMessage(outgoing); - // Emit event - onUpgrade(remoteSocket); - }); + // + // Here we set the incoming `req`, `socket` and `head` data to the outgoing + // request so that we can reuse this data later on in the closure scope + // 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 = { + request: req, + socket: socket, + head: head + }; + + // + // If the agent for this particular `host` and `port` combination + // is not already listening for the `upgrade` event, then do so once. + // This will force us not to disconnect. + // + // In addition, it's important to note the closure scope here. Since + // there is no mapping of the + // + if (!agent._events || agent._events['upgrade'].length === 0) { + agent.on('upgrade', function (out, remoteSocket, head) { + // Prepare socket + _socket(remoteSocket, true); + + // Emit event + onUpgrade(remoteSocket._httpMessage, remoteSocket); + }); + } - var handshake; if (typeof request.socket !== 'undefined') { - request.socket.on('data', handshake = function(data) { + request.socket.on('data', function handshake (data) { // Handshaking // Ok, kind of harmfull part of code