From 67fdec20726e48ba3a934cb25bb30d47ec4a4f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yaroslav=20De=20La=20Pe=C3=B1a=20Smirnov?= Date: Wed, 29 Nov 2017 11:44:34 +0300 Subject: Initial commit, version 0.5.3 --- .../engine.io-client/lib/transports/websocket.js | 286 +++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 node_modules/engine.io-client/lib/transports/websocket.js (limited to 'node_modules/engine.io-client/lib/transports/websocket.js') diff --git a/node_modules/engine.io-client/lib/transports/websocket.js b/node_modules/engine.io-client/lib/transports/websocket.js new file mode 100644 index 0000000..de14ba0 --- /dev/null +++ b/node_modules/engine.io-client/lib/transports/websocket.js @@ -0,0 +1,286 @@ +/** + * Module dependencies. + */ + +var Transport = require('../transport'); +var parser = require('engine.io-parser'); +var parseqs = require('parseqs'); +var inherit = require('component-inherit'); +var yeast = require('yeast'); +var debug = require('debug')('engine.io-client:websocket'); +var BrowserWebSocket = global.WebSocket || global.MozWebSocket; +var NodeWebSocket; +if (typeof window === 'undefined') { + try { + NodeWebSocket = require('ws'); + } catch (e) { } +} + +/** + * Get either the `WebSocket` or `MozWebSocket` globals + * in the browser or try to resolve WebSocket-compatible + * interface exposed by `ws` for Node-like environment. + */ + +var WebSocket = BrowserWebSocket; +if (!WebSocket && typeof window === 'undefined') { + WebSocket = NodeWebSocket; +} + +/** + * Module exports. + */ + +module.exports = WS; + +/** + * WebSocket transport constructor. + * + * @api {Object} connection options + * @api public + */ + +function WS (opts) { + var forceBase64 = (opts && opts.forceBase64); + if (forceBase64) { + this.supportsBinary = false; + } + this.perMessageDeflate = opts.perMessageDeflate; + this.usingBrowserWebSocket = BrowserWebSocket && !opts.forceNode; + this.protocols = opts.protocols; + if (!this.usingBrowserWebSocket) { + WebSocket = NodeWebSocket; + } + Transport.call(this, opts); +} + +/** + * Inherits from Transport. + */ + +inherit(WS, Transport); + +/** + * Transport name. + * + * @api public + */ + +WS.prototype.name = 'websocket'; + +/* + * WebSockets support binary + */ + +WS.prototype.supportsBinary = true; + +/** + * Opens socket. + * + * @api private + */ + +WS.prototype.doOpen = function () { + if (!this.check()) { + // let probe timeout + return; + } + + var uri = this.uri(); + var protocols = this.protocols; + var opts = { + agent: this.agent, + perMessageDeflate: this.perMessageDeflate + }; + + // SSL options for Node.js client + opts.pfx = this.pfx; + opts.key = this.key; + opts.passphrase = this.passphrase; + opts.cert = this.cert; + opts.ca = this.ca; + opts.ciphers = this.ciphers; + opts.rejectUnauthorized = this.rejectUnauthorized; + if (this.extraHeaders) { + opts.headers = this.extraHeaders; + } + if (this.localAddress) { + opts.localAddress = this.localAddress; + } + + try { + this.ws = this.usingBrowserWebSocket ? (protocols ? new WebSocket(uri, protocols) : new WebSocket(uri)) : new WebSocket(uri, protocols, opts); + } catch (err) { + return this.emit('error', err); + } + + if (this.ws.binaryType === undefined) { + this.supportsBinary = false; + } + + if (this.ws.supports && this.ws.supports.binary) { + this.supportsBinary = true; + this.ws.binaryType = 'nodebuffer'; + } else { + this.ws.binaryType = 'arraybuffer'; + } + + this.addEventListeners(); +}; + +/** + * Adds event listeners to the socket + * + * @api private + */ + +WS.prototype.addEventListeners = function () { + var self = this; + + this.ws.onopen = function () { + self.onOpen(); + }; + this.ws.onclose = function () { + self.onClose(); + }; + this.ws.onmessage = function (ev) { + self.onData(ev.data); + }; + this.ws.onerror = function (e) { + self.onError('websocket error', e); + }; +}; + +/** + * Writes data to socket. + * + * @param {Array} array of packets. + * @api private + */ + +WS.prototype.write = function (packets) { + var self = this; + this.writable = false; + + // encodePacket efficient as it uses WS framing + // no need for encodePayload + var total = packets.length; + for (var i = 0, l = total; i < l; i++) { + (function (packet) { + parser.encodePacket(packet, self.supportsBinary, function (data) { + if (!self.usingBrowserWebSocket) { + // always create a new object (GH-437) + var opts = {}; + if (packet.options) { + opts.compress = packet.options.compress; + } + + if (self.perMessageDeflate) { + var len = 'string' === typeof data ? global.Buffer.byteLength(data) : data.length; + if (len < self.perMessageDeflate.threshold) { + opts.compress = false; + } + } + } + + // Sometimes the websocket has already been closed but the browser didn't + // have a chance of informing us about it yet, in that case send will + // throw an error + try { + if (self.usingBrowserWebSocket) { + // TypeError is thrown when passing the second argument on Safari + self.ws.send(data); + } else { + self.ws.send(data, opts); + } + } catch (e) { + debug('websocket closed before onclose event'); + } + + --total || done(); + }); + })(packets[i]); + } + + function done () { + self.emit('flush'); + + // fake drain + // defer to next tick to allow Socket to clear writeBuffer + setTimeout(function () { + self.writable = true; + self.emit('drain'); + }, 0); + } +}; + +/** + * Called upon close + * + * @api private + */ + +WS.prototype.onClose = function () { + Transport.prototype.onClose.call(this); +}; + +/** + * Closes socket. + * + * @api private + */ + +WS.prototype.doClose = function () { + if (typeof this.ws !== 'undefined') { + this.ws.close(); + } +}; + +/** + * Generates uri for connection. + * + * @api private + */ + +WS.prototype.uri = function () { + var query = this.query || {}; + var schema = this.secure ? 'wss' : 'ws'; + var port = ''; + + // avoid port if default for schema + if (this.port && (('wss' === schema && Number(this.port) !== 443) || + ('ws' === schema && Number(this.port) !== 80))) { + port = ':' + this.port; + } + + // append timestamp to URI + if (this.timestampRequests) { + query[this.timestampParam] = yeast(); + } + + // communicate binary support capabilities + if (!this.supportsBinary) { + query.b64 = 1; + } + + query = parseqs.encode(query); + + // prepend ? to query + if (query.length) { + query = '?' + query; + } + + var ipv6 = this.hostname.indexOf(':') !== -1; + return schema + '://' + (ipv6 ? '[' + this.hostname + ']' : this.hostname) + port + this.path + query; +}; + +/** + * Feature detection for WebSocket. + * + * @return {Boolean} whether this transport is available. + * @api public + */ + +WS.prototype.check = function () { + return !!WebSocket && !('__initialize' in WebSocket && this.name === WS.prototype.name); +}; -- cgit v1.2.3