var http = require('http'), https = require('https'), util = require('util'), common = require('../common'), passes = exports; /*! * 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 * */ var passes = exports; [ /** * WebSocket requests must have the `GET` method and * the `upgrade:websocket` header * * @param {ClientRequest} Req Request object * @param {Socket} Websocket * * @api private */ 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 */ 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 */ function stream(req, socket, options, head, server, clb) { 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) ); // 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.end(); }); 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); var writeHead = [ 'HTTP/1.1 101 Switching Protocols' ]; for(var i in proxyRes.headers) { if (util.isArray(proxyRes.headers[i])) { var a = proxyRes.headers[i]; var len = a.length; for (var x = 0; x < len; x++) { writeHead.push(i + ": " + a[x]); } } else { writeHead.push(i + ": " + proxyRes.headers[i]); } } socket.write(writeHead.join('\r\n') + '\r\n\r\n'); 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(); } } ] // <-- .forEach(function(func) { passes[func.name] = func; });