arnaucube
arnaucube/socketioMEANseedPublic Self-hosted repository
socketioMEANseed/server/node_modules/engine.io-client/lib/transports/websocket.js
server/node_modules/engine.io-client/lib/transports/websocket.jsRaw
  1/**
  2 * Module dependencies.
  3 */
  4
  5var Transport = require('../transport');
  6var parser = require('engine.io-parser');
  7var parseqs = require('parseqs');
  8var inherit = require('component-inherit');
  9var yeast = require('yeast');
 10var debug = require('debug')('engine.io-client:websocket');
 11var BrowserWebSocket = global.WebSocket || global.MozWebSocket;
 12var NodeWebSocket;
 13if (typeof window === 'undefined') {
 14  try {
 15    NodeWebSocket = require('ws');
 16  } catch (e) { }
 17}
 18
 19/**
 20 * Get either the `WebSocket` or `MozWebSocket` globals
 21 * in the browser or try to resolve WebSocket-compatible
 22 * interface exposed by `ws` for Node-like environment.
 23 */
 24
 25var WebSocket = BrowserWebSocket;
 26if (!WebSocket && typeof window === 'undefined') {
 27  WebSocket = NodeWebSocket;
 28}
 29
 30/**
 31 * Module exports.
 32 */
 33
 34module.exports = WS;
 35
 36/**
 37 * WebSocket transport constructor.
 38 *
 39 * @api {Object} connection options
 40 * @api public
 41 */
 42
 43function WS (opts) {
 44  var forceBase64 = (opts && opts.forceBase64);
 45  if (forceBase64) {
 46    this.supportsBinary = false;
 47  }
 48  this.perMessageDeflate = opts.perMessageDeflate;
 49  this.usingBrowserWebSocket = BrowserWebSocket && !opts.forceNode;
 50  if (!this.usingBrowserWebSocket) {
 51    WebSocket = NodeWebSocket;
 52  }
 53  Transport.call(this, opts);
 54}
 55
 56/**
 57 * Inherits from Transport.
 58 */
 59
 60inherit(WS, Transport);
 61
 62/**
 63 * Transport name.
 64 *
 65 * @api public
 66 */
 67
 68WS.prototype.name = 'websocket';
 69
 70/*
 71 * WebSockets support binary
 72 */
 73
 74WS.prototype.supportsBinary = true;
 75
 76/**
 77 * Opens socket.
 78 *
 79 * @api private
 80 */
 81
 82WS.prototype.doOpen = function () {
 83  if (!this.check()) {
 84    // let probe timeout
 85    return;
 86  }
 87
 88  var uri = this.uri();
 89  var protocols = void (0);
 90  var opts = {
 91    agent: this.agent,
 92    perMessageDeflate: this.perMessageDeflate
 93  };
 94
 95  // SSL options for Node.js client
 96  opts.pfx = this.pfx;
 97  opts.key = this.key;
 98  opts.passphrase = this.passphrase;
 99  opts.cert = this.cert;
100  opts.ca = this.ca;
101  opts.ciphers = this.ciphers;
102  opts.rejectUnauthorized = this.rejectUnauthorized;
103  if (this.extraHeaders) {
104    opts.headers = this.extraHeaders;
105  }
106  if (this.localAddress) {
107    opts.localAddress = this.localAddress;
108  }
109
110  try {
111    this.ws = this.usingBrowserWebSocket ? new WebSocket(uri) : new WebSocket(uri, protocols, opts);
112  } catch (err) {
113    return this.emit('error', err);
114  }
115
116  if (this.ws.binaryType === undefined) {
117    this.supportsBinary = false;
118  }
119
120  if (this.ws.supports && this.ws.supports.binary) {
121    this.supportsBinary = true;
122    this.ws.binaryType = 'nodebuffer';
123  } else {
124    this.ws.binaryType = 'arraybuffer';
125  }
126
127  this.addEventListeners();
128};
129
130/**
131 * Adds event listeners to the socket
132 *
133 * @api private
134 */
135
136WS.prototype.addEventListeners = function () {
137  var self = this;
138
139  this.ws.onopen = function () {
140    self.onOpen();
141  };
142  this.ws.onclose = function () {
143    self.onClose();
144  };
145  this.ws.onmessage = function (ev) {
146    self.onData(ev.data);
147  };
148  this.ws.onerror = function (e) {
149    self.onError('websocket error', e);
150  };
151};
152
153/**
154 * Writes data to socket.
155 *
156 * @param {Array} array of packets.
157 * @api private
158 */
159
160WS.prototype.write = function (packets) {
161  var self = this;
162  this.writable = false;
163
164  // encodePacket efficient as it uses WS framing
165  // no need for encodePayload
166  var total = packets.length;
167  for (var i = 0, l = total; i < l; i++) {
168    (function (packet) {
169      parser.encodePacket(packet, self.supportsBinary, function (data) {
170        if (!self.usingBrowserWebSocket) {
171          // always create a new object (GH-437)
172          var opts = {};
173          if (packet.options) {
174            opts.compress = packet.options.compress;
175          }
176
177          if (self.perMessageDeflate) {
178            var len = 'string' === typeof data ? global.Buffer.byteLength(data) : data.length;
179            if (len < self.perMessageDeflate.threshold) {
180              opts.compress = false;
181            }
182          }
183        }
184
185        // Sometimes the websocket has already been closed but the browser didn't
186        // have a chance of informing us about it yet, in that case send will
187        // throw an error
188        try {
189          if (self.usingBrowserWebSocket) {
190            // TypeError is thrown when passing the second argument on Safari
191            self.ws.send(data);
192          } else {
193            self.ws.send(data, opts);
194          }
195        } catch (e) {
196          debug('websocket closed before onclose event');
197        }
198
199        --total || done();
200      });
201    })(packets[i]);
202  }
203
204  function done () {
205    self.emit('flush');
206
207    // fake drain
208    // defer to next tick to allow Socket to clear writeBuffer
209    setTimeout(function () {
210      self.writable = true;
211      self.emit('drain');
212    }, 0);
213  }
214};
215
216/**
217 * Called upon close
218 *
219 * @api private
220 */
221
222WS.prototype.onClose = function () {
223  Transport.prototype.onClose.call(this);
224};
225
226/**
227 * Closes socket.
228 *
229 * @api private
230 */
231
232WS.prototype.doClose = function () {
233  if (typeof this.ws !== 'undefined') {
234    this.ws.close();
235  }
236};
237
238/**
239 * Generates uri for connection.
240 *
241 * @api private
242 */
243
244WS.prototype.uri = function () {
245  var query = this.query || {};
246  var schema = this.secure ? 'wss' : 'ws';
247  var port = '';
248
249  // avoid port if default for schema
250  if (this.port && (('wss' === schema && Number(this.port) !== 443) ||
251    ('ws' === schema && Number(this.port) !== 80))) {
252    port = ':' + this.port;
253  }
254
255  // append timestamp to URI
256  if (this.timestampRequests) {
257    query[this.timestampParam] = yeast();
258  }
259
260  // communicate binary support capabilities
261  if (!this.supportsBinary) {
262    query.b64 = 1;
263  }
264
265  query = parseqs.encode(query);
266
267  // prepend ? to query
268  if (query.length) {
269    query = '?' + query;
270  }
271
272  var ipv6 = this.hostname.indexOf(':') !== -1;
273  return schema + '://' + (ipv6 ? '[' + this.hostname + ']' : this.hostname) + port + this.path + query;
274};
275
276/**
277 * Feature detection for WebSocket.
278 *
279 * @return {Boolean} whether this transport is available.
280 * @api public
281 */
282
283WS.prototype.check = function () {
284  return !!WebSocket && !('__initialize' in WebSocket && this.name === WS.prototype.name);
285};