arnaucube
arnaucube/socketioMEANseedPublic Self-hosted repository
socketioMEANseed/www/node_modules/http-proxy/lib/http-proxy/passes/ws-incoming.js
www/node_modules/http-proxy/lib/http-proxy/passes/ws-incoming.jsRaw
  1var http   = require('http'),
  2    https  = require('https'),
  3    common = require('../common');
  4
  5/*!
  6 * Array of passes.
  7 *
  8 * A `pass` is just a function that is executed on `req, socket, options`
  9 * so that you can easily add new checks while still keeping the base
 10 * flexible.
 11 */
 12
 13/*
 14 * Websockets Passes
 15 *
 16 */
 17
 18
 19module.exports = {
 20  /**
 21   * WebSocket requests must have the `GET` method and
 22   * the `upgrade:websocket` header
 23   *
 24   * @param {ClientRequest} Req Request object
 25   * @param {Socket} Websocket
 26   *
 27   * @api private
 28   */
 29
 30  checkMethodAndHeader : function checkMethodAndHeader(req, socket) {
 31    if (req.method !== 'GET' || !req.headers.upgrade) {
 32      socket.destroy();
 33      return true;
 34    }
 35
 36    if (req.headers.upgrade.toLowerCase() !== 'websocket') {
 37      socket.destroy();
 38      return true;
 39    }
 40  },
 41
 42  /**
 43   * Sets `x-forwarded-*` headers if specified in config.
 44   *
 45   * @param {ClientRequest} Req Request object
 46   * @param {Socket} Websocket
 47   * @param {Object} Options Config object passed to the proxy
 48   *
 49   * @api private
 50   */
 51
 52  XHeaders : function XHeaders(req, socket, options) {
 53    if(!options.xfwd) return;
 54
 55    var values = {
 56      for  : req.connection.remoteAddress || req.socket.remoteAddress,
 57      port : common.getPort(req),
 58      proto: common.hasEncryptedConnection(req) ? 'wss' : 'ws'
 59    };
 60
 61    ['for', 'port', 'proto'].forEach(function(header) {
 62      req.headers['x-forwarded-' + header] =
 63        (req.headers['x-forwarded-' + header] || '') +
 64        (req.headers['x-forwarded-' + header] ? ',' : '') +
 65        values[header];
 66    });
 67  },
 68
 69  /**
 70   * Does the actual proxying. Make the request and upgrade it
 71   * send the Switching Protocols request and pipe the sockets.
 72   *
 73   * @param {ClientRequest} Req Request object
 74   * @param {Socket} Websocket
 75   * @param {Object} Options Config object passed to the proxy
 76   *
 77   * @api private
 78   */
 79  stream : function stream(req, socket, options, head, server, clb) {
 80    common.setupSocket(socket);
 81
 82    if (head && head.length) socket.unshift(head);
 83
 84
 85    var proxyReq = (common.isSSL.test(options.target.protocol) ? https : http).request(
 86      common.setupOutgoing(options.ssl || {}, options, req)
 87    );
 88
 89    // Enable developers to modify the proxyReq before headers are sent
 90    if (server) { server.emit('proxyReqWs', proxyReq, req, socket, options, head); }
 91
 92    // Error Handler
 93    proxyReq.on('error', onOutgoingError);
 94    proxyReq.on('response', function (res) {
 95      // if upgrade event isn't going to happen, close the socket
 96      if (!res.upgrade) socket.end();
 97    });
 98
 99    proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) {
100      proxySocket.on('error', onOutgoingError);
101
102      // Allow us to listen when the websocket has completed
103      proxySocket.on('end', function () {
104        server.emit('close', proxyRes, proxySocket, proxyHead);
105      });
106
107      // The pipe below will end proxySocket if socket closes cleanly, but not
108      // if it errors (eg, vanishes from the net and starts returning
109      // EHOSTUNREACH). We need to do that explicitly.
110      socket.on('error', function () {
111        proxySocket.end();
112      });
113
114      common.setupSocket(proxySocket);
115
116      if (proxyHead && proxyHead.length) proxySocket.unshift(proxyHead);
117
118      //
119      // Remark: Handle writing the headers to the socket when switching protocols
120      // Also handles when a header is an array
121      //
122      socket.write(
123        Object.keys(proxyRes.headers).reduce(function (head, key) {
124          var value = proxyRes.headers[key];
125
126          if (!Array.isArray(value)) {
127            head.push(key + ': ' + value);
128            return head;
129          }
130
131          for (var i = 0; i < value.length; i++) {
132            head.push(key + ': ' + value[i]);
133          }
134          return head;
135        }, ['HTTP/1.1 101 Switching Protocols'])
136        .join('\r\n') + '\r\n\r\n'
137      );
138
139      proxySocket.pipe(socket).pipe(proxySocket);
140
141      server.emit('open', proxySocket);
142      server.emit('proxySocket', proxySocket);  //DEPRECATED.
143    });
144
145    return proxyReq.end(); // XXX: CHECK IF THIS IS THIS CORRECT
146
147    function onOutgoingError(err) {
148      if (clb) {
149        clb(err, req, socket);
150      } else {
151        server.emit('error', err, req, socket);
152      }
153      socket.end();
154    }
155  }
156};