| var http   = require('http'), | 
|     https  = require('https'), | 
|     common = require('../common'); | 
|   | 
| /*! | 
|  * Array of passes. | 
|  * | 
|  * A `pass` is just a function that is executed on `req, socket, options` | 
|  * so that you can easily add new checks while still keeping the base | 
|  * flexible. | 
|  */ | 
|   | 
| /* | 
|  * Websockets Passes | 
|  * | 
|  */ | 
|   | 
|   | 
| module.exports = { | 
|   /** | 
|    * WebSocket requests must have the `GET` method and | 
|    * the `upgrade:websocket` header | 
|    * | 
|    * @param {ClientRequest} Req Request object | 
|    * @param {Socket} Websocket | 
|    * | 
|    * @api private | 
|    */ | 
|   | 
|   checkMethodAndHeader : function checkMethodAndHeader(req, socket) { | 
|     if (req.method !== 'GET' || !req.headers.upgrade) { | 
|       socket.destroy(); | 
|       return true; | 
|     } | 
|   | 
|     if (req.headers.upgrade.toLowerCase() !== 'websocket') { | 
|       socket.destroy(); | 
|       return true; | 
|     } | 
|   }, | 
|   | 
|   /** | 
|    * Sets `x-forwarded-*` headers if specified in config. | 
|    * | 
|    * @param {ClientRequest} Req Request object | 
|    * @param {Socket} Websocket | 
|    * @param {Object} Options Config object passed to the proxy | 
|    * | 
|    * @api private | 
|    */ | 
|   | 
|   XHeaders : function XHeaders(req, socket, options) { | 
|     if(!options.xfwd) return; | 
|   | 
|     var values = { | 
|       for  : req.connection.remoteAddress || req.socket.remoteAddress, | 
|       port : common.getPort(req), | 
|       proto: common.hasEncryptedConnection(req) ? 'wss' : 'ws' | 
|     }; | 
|   | 
|     ['for', 'port', 'proto'].forEach(function(header) { | 
|       req.headers['x-forwarded-' + header] = | 
|         (req.headers['x-forwarded-' + header] || '') + | 
|         (req.headers['x-forwarded-' + header] ? ',' : '') + | 
|         values[header]; | 
|     }); | 
|   }, | 
|   | 
|   /** | 
|    * Does the actual proxying. Make the request and upgrade it | 
|    * send the Switching Protocols request and pipe the sockets. | 
|    * | 
|    * @param {ClientRequest} Req Request object | 
|    * @param {Socket} Websocket | 
|    * @param {Object} Options Config object passed to the proxy | 
|    * | 
|    * @api private | 
|    */ | 
|   stream : function stream(req, socket, options, head, server, clb) { | 
|   | 
|     var createHttpHeader = function(line, headers) { | 
|       return Object.keys(headers).reduce(function (head, key) { | 
|         var value = headers[key]; | 
|   | 
|         if (!Array.isArray(value)) { | 
|           head.push(key + ': ' + value); | 
|           return head; | 
|         } | 
|   | 
|         for (var i = 0; i < value.length; i++) { | 
|           head.push(key + ': ' + value[i]); | 
|         } | 
|         return head; | 
|       }, [line]) | 
|       .join('\r\n') + '\r\n\r\n'; | 
|     } | 
|   | 
|     common.setupSocket(socket); | 
|   | 
|     if (head && head.length) socket.unshift(head); | 
|   | 
|   | 
|     var proxyReq = (common.isSSL.test(options.target.protocol) ? https : http).request( | 
|       common.setupOutgoing(options.ssl || {}, options, req) | 
|     ); | 
|   | 
|     // Enable developers to modify the proxyReq before headers are sent | 
|     if (server) { server.emit('proxyReqWs', proxyReq, req, socket, options, head); } | 
|   | 
|     // Error Handler | 
|     proxyReq.on('error', onOutgoingError); | 
|     proxyReq.on('response', function (res) { | 
|       // if upgrade event isn't going to happen, close the socket | 
|       if (!res.upgrade) { | 
|         socket.write(createHttpHeader('HTTP/' + res.httpVersion + ' ' + res.statusCode + ' ' + res.statusMessage, res.headers)); | 
|         res.pipe(socket); | 
|       } | 
|     }); | 
|   | 
|     proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) { | 
|       proxySocket.on('error', onOutgoingError); | 
|   | 
|       // Allow us to listen when the websocket has completed | 
|       proxySocket.on('end', function () { | 
|         server.emit('close', proxyRes, proxySocket, proxyHead); | 
|       }); | 
|   | 
|       // The pipe below will end proxySocket if socket closes cleanly, but not | 
|       // if it errors (eg, vanishes from the net and starts returning | 
|       // EHOSTUNREACH). We need to do that explicitly. | 
|       socket.on('error', function () { | 
|         proxySocket.end(); | 
|       }); | 
|   | 
|       common.setupSocket(proxySocket); | 
|   | 
|       if (proxyHead && proxyHead.length) proxySocket.unshift(proxyHead); | 
|   | 
|       // | 
|       // Remark: Handle writing the headers to the socket when switching protocols | 
|       // Also handles when a header is an array | 
|       // | 
|       socket.write(createHttpHeader('HTTP/1.1 101 Switching Protocols', proxyRes.headers)); | 
|   | 
|       proxySocket.pipe(socket).pipe(proxySocket); | 
|   | 
|       server.emit('open', proxySocket); | 
|       server.emit('proxySocket', proxySocket);  //DEPRECATED. | 
|     }); | 
|   | 
|     return proxyReq.end(); // XXX: CHECK IF THIS IS THIS CORRECT | 
|   | 
|     function onOutgoingError(err) { | 
|       if (clb) { | 
|         clb(err, req, socket); | 
|       } else { | 
|         server.emit('error', err, req, socket); | 
|       } | 
|       socket.end(); | 
|     } | 
|   } | 
| }; |