From f0917a3f97e8df2d58252f14c15ec54369c969ae Mon Sep 17 00:00:00 2001 From: indexzero Date: Fri, 29 Jul 2011 22:26:00 -0400 Subject: [PATCH] [minor] Style updates and whitespace cleaning for consistency --- examples/body-decoder.js | 35 +++- examples/gzip-middleware.js | 14 +- examples/url-middleware.js | 53 ++++++- examples/web-socket-proxy.js | 1 + lib/node-http-proxy.js | 299 ++++++++++++++++++----------------- 5 files changed, 242 insertions(+), 160 deletions(-) diff --git a/examples/body-decoder.js b/examples/body-decoder.js index e4a3267..23ae96d 100644 --- a/examples/body-decoder.js +++ b/examples/body-decoder.js @@ -1,11 +1,34 @@ -#!/usr/local/bin/node +/* + body-decoder.js: Example of body-decoder middleware with node-http-proxy + + Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ var httpProxy = require('http-proxy'), http = require('http'), util = require('util'), colors = require('colors'); - exports.bodyMod = function () { console.log('middleware has been started.'.green); return function (req, res, next) { @@ -16,16 +39,22 @@ exports.bodyMod = function () { console.log('ON DATA') total += data; }); + req.on('end', function () { console.log('ON END') console.log(total); + // // This line, uncommented, hangs forever. // proxy.proxyRequest(req, res, { port: 9000, host: 'localhost' }); // The following also hangs forever. // next.proxyRequest(req, res, { port: 9000, host: 'localhost' }); - }) + // + }); + + // // The following fires just fine. //proxy.proxyRequest(req, res, { port: 9000, host: 'localhost' }); + // console.log('request proxied...'.blue); } } diff --git a/examples/gzip-middleware.js b/examples/gzip-middleware.js index 2aae822..856e2f6 100644 --- a/examples/gzip-middleware.js +++ b/examples/gzip-middleware.js @@ -1,5 +1,5 @@ /* - gzip-middleware.js: Basic example of middleware in node-http-proxy + gzip-middleware.js: Basic example of `connect-gzip` middleware in node-http-proxy Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, Marak Squires, & Dominic Tarr. @@ -32,7 +32,6 @@ var util = require('util'), // // Basic Http Proxy Server // - httpProxy.createServer( require('connect-gzip').gzip({ matchType: /.?/ }), 9000, 'localhost' @@ -41,12 +40,11 @@ httpProxy.createServer( // // Target Http Server // -http.createServer( - function (req, res) { - res.writeHead(200, { 'Content-Type': 'text/plain' }); - res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2)); - res.end(); - }).listen(9000); +http.createServer(function (req, res) { + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2)); + res.end(); +}).listen(9000); util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); diff --git a/examples/url-middleware.js b/examples/url-middleware.js index 96f4b81..920a477 100644 --- a/examples/url-middleware.js +++ b/examples/url-middleware.js @@ -1,3 +1,29 @@ +/* + url-middleware.js: Example of a simple url routing middleware for node-http-proxy + + Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + var util = require('util'), colors = require('colors'), http = require('http'), @@ -10,13 +36,18 @@ var util = require('util'), // function matcher (url, dest) { + // // First, turn the URL into a regex. // NOTE: Turning user input directly into a Regular Expression is NOT SAFE. + // var r = new RegExp(url.replace(/\//, '\\/')); + + // // This next block of code may look a little confusing. // It returns a closure (anonymous function) for each URL to be matched, // storing them in an array - on each request, if the URL matches one that has // a function stored for it, the function will be called. + // return function (url) { var m = r(url) if (!m) { @@ -24,7 +55,10 @@ function matcher (url, dest) { } var path = url.slice(m[0].length); console.log('proxy:', url, '->', dest); - return {url: path, dest: dest}; + return { + url: path, + dest: dest + }; } } @@ -61,26 +95,29 @@ exports.urls = function (urls) { } } +// // Now we set up our proxy. +// httpProxy.createServer( + // // This is where our middlewares go, with any options desired - in this case, // the list of routes/URLs and their destinations. + // exports.urls({ '/hello': { port: 9000, host: 'localhost' }, '/charlie': { port: 80, host: 'charlieistheman.com' }, '/google': { port: 80, host: 'google.com' } - }) + }); ).listen(8000); // // Target Http Server (to listen for requests on 'localhost') // -http.createServer( - function (req, res) { - res.writeHead(200, { 'Content-Type': 'text/plain' }); - res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2)); - res.end(); - }).listen(9000); +http.createServer(function (req, res) { + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2)); + res.end(); +}).listen(9000); // And finally, some colored startup output. util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); diff --git a/examples/web-socket-proxy.js b/examples/web-socket-proxy.js index d948988..d7a8efa 100644 --- a/examples/web-socket-proxy.js +++ b/examples/web-socket-proxy.js @@ -47,6 +47,7 @@ var server = http.createServer(function (req, res) { res.writeHead(200); res.end(); }); + server.listen(8080); // diff --git a/lib/node-http-proxy.js b/lib/node-http-proxy.js index d7bdf2a..150d484 100644 --- a/lib/node-http-proxy.js +++ b/lib/node-http-proxy.js @@ -1,7 +1,7 @@ /* node-http-proxy.js: http proxy for node.js - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Marak Squires, Fedor Indutny + Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Marak Squires, Fedor Indutny Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -51,16 +51,16 @@ var _agents = {}; // function _getAgent (host, port, secure) { var Agent, id = [host, port].join(':'); - + if (!port) { port = secure ? 443 : 80; } - + if (!_agents[id]) { Agent = secure ? https.Agent : http.Agent; - _agents[id] = new Agent({ - host: host, + _agents[id] = new Agent({ + host: host, port: port, maxSockets: maxSockets }); @@ -70,17 +70,17 @@ function _getAgent (host, port, secure) { } // -// ### function _getProtocol (secure, outgoing) +// ### function _getProtocol (secure, outgoing) // #### @secure {Object|boolean} Settings for `https` // #### @outgoing {Object} Outgoing request options -// Returns the appropriate protocol based on the settings in +// Returns the appropriate protocol based on the settings in // `secure`. If the protocol is `https` this function will update // the options in `outgoing` as appropriate by adding `ca`, `key`, // and `cert` if they exist in `secure`. // function _getProtocol (secure, outgoing) { var protocol = secure ? https : http; - + if (typeof secure === 'object') { outgoing = outgoing || {}; ['ca', 'cert', 'key'].forEach(function (prop) { @@ -89,7 +89,7 @@ function _getProtocol (secure, outgoing) { } }) } - + return protocol; } @@ -117,25 +117,27 @@ exports.setMaxSockets = function (value) { // stack // adapted from https://github.com/creationix/stack // - function stack (middlewares, proxy) { var handle; middlewares.reverse().forEach(function (layer) { - var child = handle; handle = function (req, res) { var next = function (err) { - if (err) { - throw err; - //TODO: figure out where to send errors. - //return error(req, res, err); - } - child(req, res); + if (err) { + throw err; + // + // TODO: figure out where to send errors. + // return error(req, res, err); + // } + child(req, res); + } + next.__proto__ = proxy; layer(req, res, next); }; }); + return handle; } @@ -152,48 +154,60 @@ function stack (middlewares, proxy) { // * `httpPRoxy.createServer(function (req, res, proxy) { ... })` // exports.createServer = function () { - var args = Array.prototype.slice.call(arguments), - callback, - options = {}, port, host, forward, silent, proxy, server, middleware = []; - + var args = Array.prototype.slice.call(arguments), + callback, forward, + port, host, + proxy, server, + options = {}, + middleware = [], + silent; + args.forEach(function (arg) { - switch (typeof arg) { case 'string': host = arg; break; case 'number': port = arg; break; case 'function': middleware.push(arg); break; case 'object': options = arg; break; }; - }); var proxy = new HttpProxy(options); - if (port && host) { - // - // If we have a target host and port for the request - // then proxy to the specified location. - // - handler = function (req, res) { - proxy.proxyRequest(req, res, { - port: port, - host: host - }); - } - if(middleware.length) middleware.push(handler) - } - else if (proxy.proxyTable) { - // - // If the proxy is configured with a ProxyTable - // instance then use that before failing. - // - handler = function (req, res) { - proxy.proxyRequest(req, res); - } - if(middleware.length) middleware.push(handler) + if (port && host) { + // + // If we have a target host and port for the request + // then proxy to the specified location. + // + handler = function (req, res) { + proxy.proxyRequest(req, res, { + port: port, + host: host + }); } - if(middleware.length) handler = stack(middleware, proxy); + if (middleware.length) { + middleware.push(handler); + } + } + else if (proxy.proxyTable) { + // + // If the proxy is configured with a ProxyTable + // instance then use that before failing. + // + handler = function (req, res) { + proxy.proxyRequest(req, res); + } + + if (middleware.length) { + middleware.push(handler); + } + } + + if (middleware.length) { + //handler = callback = middleware.shift() + //else if (middleware.length) + handler = callback = stack(middleware, proxy); + } if (!handler) { // @@ -202,37 +216,36 @@ exports.createServer = function () { throw new Error('Cannot proxy without port, host, or router.') } - server = options.https + server = options.https ? https.createServer(options.https, handler) : http.createServer(handler); server.on('close', function () { proxy.close(); }); - + proxy.on('routes', function (routes) { server.emit('routes', routes); }); if (!callback) { - // WebSocket support: if callback is empty tunnel + // WebSocket support: if callback is empty tunnel // websocket request automatically server.on('upgrade', function (req, socket, head) { // Tunnel websocket requests too - proxy.proxyWebSocketRequest(req, socket, head, { port: port, host: host }); }); } - + // // Set the proxy on the server so it is available // to the consumer of the server // server.proxy = proxy; - + return server; }; @@ -253,23 +266,23 @@ exports.createServer = function () { // host: 'localhost', // port: 9001 // } -// } +// } // var HttpProxy = exports.HttpProxy = function (options) { events.EventEmitter.call(this); - + var self = this; options = options || {}; - + // // Setup basic proxying options // this.https = options.https; this.forward = options.forward; this.target = options.target || {}; - + // - // Setup additional options for WebSocket proxying. When forcing + // Setup additional options for WebSocket proxying. When forcing // the WebSocket handshake to change the `sec-websocket-location` // and `sec-websocket-origin` headers `options.source` **MUST** // be provided or the operation will fail with an `origin mismatch` @@ -277,7 +290,7 @@ var HttpProxy = exports.HttpProxy = function (options) { // this.source = options.source || { host: 'localhost', port: 8000 }; this.changeOrigin = options.changeOrigin || false; - + if (options.router) { this.proxyTable = new ProxyTable(options.router, options.silent, options.hostnameOnly); this.proxyTable.on('routes', function (routes) { @@ -290,10 +303,10 @@ var HttpProxy = exports.HttpProxy = function (options) { util.inherits(HttpProxy, events.EventEmitter); // -// ### function buffer (obj) +// ### function buffer (obj) // #### @obj {Object} Object to pause events from // Buffer `data` and `end` events from the given `obj`. -// Consumers of HttpProxy performing async tasks +// Consumers of HttpProxy performing async tasks // __must__ utilize this utility, to re-emit data once // the async operation has completed, otherwise these // __events will be lost.__ @@ -303,9 +316,9 @@ util.inherits(HttpProxy, events.EventEmitter); // httpProxy.proxyRequest(req, res, host, port, buffer); // }); // -// __Attribution:__ This approach is based heavily on +// __Attribution:__ This approach is based heavily on // [Connect](https://github.com/senchalabs/connect/blob/master/lib/utils.js#L157). -// However, this is not a big leap from the implementation in node-http-proxy < 0.4.0. +// However, this is not a big leap from the implementation in node-http-proxy < 0.4.0. // This simply chooses to manage the scope of the events on a new Object literal as opposed to // [on the HttpProxy instance](https://github.com/nodejitsu/node-http-proxy/blob/v0.3.1/lib/node-http-proxy.js#L154). // @@ -337,10 +350,12 @@ HttpProxy.prototype.buffer = function (obj) { // // ### function close () // Frees the resources associated with this instance, -// if they exist. +// if they exist. // HttpProxy.prototype.close = function () { - if (this.proxyTable) this.proxyTable.close(); + if (this.proxyTable) { + this.proxyTable.close(); + } }; // @@ -357,18 +372,18 @@ HttpProxy.prototype.close = function () { // HttpProxy.prototype.proxyRequest = function (req, res, options) { var self = this, errState = false, location, outgoing, protocol, reverseProxy; - + // // Create an empty options hash if none is passed. - // If default options have been passed to the constructor + // If default options have been passed to the constructor // of this instance, use them by default. // options = options || {}; options.host = options.host || this.target.host; options.port = options.port || this.target.port; - options.enableXForwarded = + options.enableXForwarded = (undefined === options.enableXForwarded ? true : options.enableXForwarded); - + // // Check the proxy table for this instance to see if we need // to get the proxy location for the request supplied. We will @@ -377,7 +392,7 @@ HttpProxy.prototype.proxyRequest = function (req, res, options) { // if (this.proxyTable && !options.host) { location = this.proxyTable.getProxyLocation(req); - + // // If no location is returned from the ProxyTable instance // then respond with `404` since we do not have a valid proxy target. @@ -386,38 +401,38 @@ HttpProxy.prototype.proxyRequest = function (req, res, options) { res.writeHead(404); return res.end(); } - + // // When using the ProxyTable in conjunction with an HttpProxy instance // only the following arguments are valid: - // + // // * `proxy.proxyRequest(req, res, { host: 'localhost' })`: This will be skipped // * `proxy.proxyRequest(req, res, { buffer: buffer })`: Buffer will get updated appropriately - // * `proxy.proxyRequest(req, res)`: Options will be assigned appropriately. + // * `proxy.proxyRequest(req, res)`: Options will be assigned appropriately. // options.port = location.port; options.host = location.host; } - + // - // Add common proxy headers to the request so that they can + // Add common proxy headers to the request so that they can // be availible to the proxy target server: - // + // // * `x-forwarded-for`: IP Address of the original request // * `x-forwarded-proto`: Protocol of the original request - // * `x-forwarded-port`: Port of the original request. + // * `x-forwarded-port`: Port of the original request. // - if (options.enableXForwarded == true) { + if (options.enableXForwarded === true) { req.headers['x-forwarded-for'] = req.connection.remoteAddress || req.connection.socket.remoteAddress; req.headers['x-forwarded-port'] = req.connection.remotePort || req.connection.socket.remotePort; req.headers['x-forwarded-proto'] = res.connection.pair ? 'https' : 'http'; } - + // // Emit the `start` event indicating that we have begun the proxy operation. // this.emit('start', req, res, options); - + // // If forwarding is enabled for this instance, foward proxy the // specified request to the address provided in `this.forward` @@ -426,16 +441,16 @@ HttpProxy.prototype.proxyRequest = function (req, res, options) { this.emit('forward', req, res, this.forward); this._forwardRequest(req); } - + // // #### function proxyError (err) // #### @err {Error} Error contacting the proxy target - // Short-circuits `res` in the event of any error when + // Short-circuits `res` in the event of any error when // contacting the proxy target at `host` / `port`. // function proxyError(err) { errState = true; - + // // Emit an `error` event, allowing the application to use custom // error handling. The error handler should end the response. @@ -458,10 +473,10 @@ HttpProxy.prototype.proxyRequest = function (req, res, options) { res.write('An error has occurred: ' + JSON.stringify(err)); } } - + res.end(); } - + outgoing = { host: options.host, port: options.port, @@ -470,12 +485,12 @@ HttpProxy.prototype.proxyRequest = function (req, res, options) { path: req.url, headers: req.headers }; - + protocol = _getProtocol(options.https || this.target.https, outgoing); - + // Open new HTTP request to internal resource with will act as a reverse proxy pass reverseProxy = protocol.request(outgoing, function (response) { - + // Process the `reverseProxy` `response` when it's received. if (response.headers.connection) { if (req.headers.connection) response.headers.connection = req.headers.connection; @@ -507,17 +522,17 @@ HttpProxy.prototype.proxyRequest = function (req, res, options) { if (!errState) { reverseProxy.removeListener('error', proxyError); res.end(); - + // Emit the `end` event now that we have completed proxying self.emit('end', req, res); } }); }); - + // Handle 'error' events from the `reverseProxy`. reverseProxy.once('error', proxyError); - - // For each data `chunk` received from the incoming + + // For each data `chunk` received from the incoming // `req` write it to the `reverseProxy` request. req.on('data', function (chunk) { if (!errState) { @@ -526,8 +541,8 @@ HttpProxy.prototype.proxyRequest = function (req, res, options) { }); // - // When the incoming `req` ends, end the corresponding `reverseProxy` - // request unless we have entered an error state. + // When the incoming `req` ends, end the corresponding `reverseProxy` + // request unless we have entered an error state. // req.on('end', function () { if (!errState) { @@ -540,7 +555,7 @@ HttpProxy.prototype.proxyRequest = function (req, res, options) { options.buffer.resume(); } }; - + // // ### @private function _forwardRequest (req) // #### @req {ServerRequest} Incoming HTTP Request to proxy. @@ -552,7 +567,7 @@ HttpProxy.prototype._forwardRequest = function (req) { port = this.forward.port; host = this.forward.host; - + outgoing = { host: host, port: port, @@ -561,13 +576,13 @@ HttpProxy.prototype._forwardRequest = function (req) { path: req.url, headers: req.headers }; - + // Force the `connection` header to be 'close' until // node.js core re-implements 'keep-alive'. outgoing.headers['connection'] = 'close'; - + protocol = _getProtocol(this.forward.https, outgoing); - + // Open new HTTP request to internal resource with will act as a reverse proxy pass forwardProxy = protocol.request(outgoing, function (response) { // @@ -575,10 +590,10 @@ HttpProxy.prototype._forwardRequest = function (req) { // Remark (indexzero): We will eventually emit a 'forward' event here for performance tuning. // }); - + // Add a listener for the connection timeout event. // - // Remark: Ignoring this error in the event + // Remark: Ignoring this error in the event // forward target doesn't exist. // forwardProxy.once('error', function (err) { }); @@ -596,7 +611,7 @@ HttpProxy.prototype._forwardRequest = function (req) { // // ### function proxyWebSocketRequest (req, socket, head, options) -// #### @req {ServerRequest} Websocket request to proxy. +// #### @req {ServerRequest} Websocket request to proxy. // #### @socket {net.Socket} Socket for the underlying HTTP request // #### @head {string} Headers for the Websocket request. // #### @options {Object} Options to use when proxying this request. @@ -607,28 +622,30 @@ HttpProxy.prototype._forwardRequest = function (req) { // options.https {Object|boolean} Settings for https. // HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options) { - var self = this, + var self = this, listeners = {}, - errState = false, + errState = false, CRLF = '\r\n', outgoing; options = options || {}; options.host = options.host || this.target.host; options.port = options.port || this.target.port; - + if (this.proxyTable && !options.host) { location = this.proxyTable.getProxyLocation(req); - + if (!location) { res.writeHead(404); return res.end(); } + options.port = location.port; options.host = location.host; } + // - // WebSocket requests must have the `GET` method and + // WebSocket requests must have the `GET` method and // the `upgrade:websocket` header // if (req.method !== 'GET' || req.headers.upgrade.toLowerCase() !== 'websocket') { @@ -637,7 +654,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options // return; } - + // // Helper function for setting appropriate socket values: // 1. Turn of all bufferings @@ -654,14 +671,14 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options else if (socket.pair.cleartext.socket.setKeepAlive) { socket.pair.cleartext.socket.setKeepAlive(true, 0); } - } + } else { socket.setEncoding('utf8'); } } - + // - // On `upgrade` from the Agent socket, listen to + // On `upgrade` from the Agent socket, listen to // the appropriate events. // function onUpgrade (reverseProxy, proxySocket) { @@ -670,7 +687,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options socket.end(); return; } - + // // Any incoming data on this WebSocket to the proxy target // will be written to the `reverseProxy` socket. @@ -680,7 +697,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options try { self.emit('websocket:outgoing', req, socket, head, data); reverseProxy.incoming.socket.write(data); - } + } catch (e) { reverseProxy.incoming.socket.end(); proxySocket.end(); @@ -696,15 +713,15 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options try { self.emit('websocket:incoming', reverseProxy, reverseProxy.incoming, head, data); proxySocket.write(data); - } + } catch (e) { proxySocket.end(); socket.end(); } }); - + // - // Helper function to detach all event listeners + // Helper function to detach all event listeners // from `reverseProxy` and `proxySocket`. // function detach() { @@ -715,19 +732,19 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options } // - // If the incoming `proxySocket` socket closes, then - // detach all event listeners. + // If the incoming `proxySocket` socket closes, then + // detach all event listeners. // proxySocket.on('end', listeners.onIncomingClose = function() { reverseProxy.incoming.socket.end(); detach(); - + // Emit the `end` event now that we have completed proxying self.emit('websocket:end', req, socket, head); }); // - // If the `reverseProxy` socket closes, then detach all + // If the `reverseProxy` socket closes, then detach all // event listeners. // reverseProxy.incoming.socket.on('end', listeners.onOutgoingClose = function() { @@ -738,12 +755,12 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options // Setup the incoming client socket. _socket(socket); - + function getPort (port) { port = port || 80; return port - 80 === 0 ? '' : ':' + port } - + // // Get the protocol, and host for this request and create an instance // of `http.Agent` or `https.Agent` from the pool managed by `node-http-proxy`. @@ -758,7 +775,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options req.headers.host = remoteHost; req.headers.origin = protocolName + '://' + remoteHost; } - + // // Make the outgoing WebSocket request // @@ -772,7 +789,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options var reverseProxy = agent.appendMessage(outgoing); // - // On any errors from the `reverseProxy` emit the + // On any errors from the `reverseProxy` emit the // `webSocketProxyError` and close the appropriate // connections. // @@ -781,14 +798,14 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options if (self.emit('webSocketProxyError', req, socket, head)) { return; } - + socket.end(); } // // 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 + // available to the `upgrade` event. This bookkeeping is not tracked anywhere // in nodejs core and is **very** specific to proxying WebSockets. // reverseProxy.agent = agent; @@ -797,27 +814,27 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options 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. + // 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 + // there is no mapping of the // if (!agent._events || agent._events['upgrade'].length === 0) { agent.on('upgrade', function (_, remoteSocket, head) { // - // Prepare the socket for the reverseProxy request and begin to - // stream data between the two sockets. Here it is important to + // Prepare the socket for the reverseProxy request and begin to + // stream data between the two sockets. Here it is important to // note that `remoteSocket._httpMessage === reverseProxy`. // _socket(remoteSocket, true); onUpgrade(remoteSocket._httpMessage, remoteSocket); }); } - + // // If the reverseProxy connection has an underlying socket, // then execute the WebSocket handshake. @@ -826,9 +843,9 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options 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 + // 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(); @@ -838,7 +855,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options // Get the Non-Printable data data = data.slice(Buffer.byteLength(sdata), data.length); - + if (self.https && !self.target.https) { // // If the proxy server is running HTTPS but the client is running @@ -850,12 +867,12 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options try { // // Write the printable and non-printable data to the socket - // from the original incoming request. - // + // from the original incoming request. + // self.emit('websocket:handshake', req, socket, head, sdata, data); socket.write(sdata); socket.write(data); - } + } catch (ex) { proxyError(ex) } @@ -867,7 +884,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options reverseProxy.socket.removeListener('data', handshake); }); } - + reverseProxy.on('error', proxyError); try { @@ -875,11 +892,11 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options // Attempt to write the upgrade-head to the reverseProxy request. // reverseProxy.write(head); - } + } catch (ex) { proxyError(ex); } - + // // If we have been passed buffered data, resume it. //