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/polling-xhr.js | 413 +++++++++++++++++++++ 1 file changed, 413 insertions(+) create mode 100644 node_modules/engine.io-client/lib/transports/polling-xhr.js (limited to 'node_modules/engine.io-client/lib/transports/polling-xhr.js') diff --git a/node_modules/engine.io-client/lib/transports/polling-xhr.js b/node_modules/engine.io-client/lib/transports/polling-xhr.js new file mode 100644 index 0000000..297bac5 --- /dev/null +++ b/node_modules/engine.io-client/lib/transports/polling-xhr.js @@ -0,0 +1,413 @@ +/** + * Module requirements. + */ + +var XMLHttpRequest = require('xmlhttprequest-ssl'); +var Polling = require('./polling'); +var Emitter = require('component-emitter'); +var inherit = require('component-inherit'); +var debug = require('debug')('engine.io-client:polling-xhr'); + +/** + * Module exports. + */ + +module.exports = XHR; +module.exports.Request = Request; + +/** + * Empty function + */ + +function empty () {} + +/** + * XHR Polling constructor. + * + * @param {Object} opts + * @api public + */ + +function XHR (opts) { + Polling.call(this, opts); + this.requestTimeout = opts.requestTimeout; + this.extraHeaders = opts.extraHeaders; + + if (global.location) { + var isSSL = 'https:' === location.protocol; + var port = location.port; + + // some user agents have empty `location.port` + if (!port) { + port = isSSL ? 443 : 80; + } + + this.xd = opts.hostname !== global.location.hostname || + port !== opts.port; + this.xs = opts.secure !== isSSL; + } +} + +/** + * Inherits from Polling. + */ + +inherit(XHR, Polling); + +/** + * XHR supports binary + */ + +XHR.prototype.supportsBinary = true; + +/** + * Creates a request. + * + * @param {String} method + * @api private + */ + +XHR.prototype.request = function (opts) { + opts = opts || {}; + opts.uri = this.uri(); + opts.xd = this.xd; + opts.xs = this.xs; + opts.agent = this.agent || false; + opts.supportsBinary = this.supportsBinary; + opts.enablesXDR = this.enablesXDR; + + // 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; + opts.requestTimeout = this.requestTimeout; + + // other options for Node.js client + opts.extraHeaders = this.extraHeaders; + + return new Request(opts); +}; + +/** + * Sends data. + * + * @param {String} data to send. + * @param {Function} called upon flush. + * @api private + */ + +XHR.prototype.doWrite = function (data, fn) { + var isBinary = typeof data !== 'string' && data !== undefined; + var req = this.request({ method: 'POST', data: data, isBinary: isBinary }); + var self = this; + req.on('success', fn); + req.on('error', function (err) { + self.onError('xhr post error', err); + }); + this.sendXhr = req; +}; + +/** + * Starts a poll cycle. + * + * @api private + */ + +XHR.prototype.doPoll = function () { + debug('xhr poll'); + var req = this.request(); + var self = this; + req.on('data', function (data) { + self.onData(data); + }); + req.on('error', function (err) { + self.onError('xhr poll error', err); + }); + this.pollXhr = req; +}; + +/** + * Request constructor + * + * @param {Object} options + * @api public + */ + +function Request (opts) { + this.method = opts.method || 'GET'; + this.uri = opts.uri; + this.xd = !!opts.xd; + this.xs = !!opts.xs; + this.async = false !== opts.async; + this.data = undefined !== opts.data ? opts.data : null; + this.agent = opts.agent; + this.isBinary = opts.isBinary; + this.supportsBinary = opts.supportsBinary; + this.enablesXDR = opts.enablesXDR; + this.requestTimeout = opts.requestTimeout; + + // SSL options for Node.js client + this.pfx = opts.pfx; + this.key = opts.key; + this.passphrase = opts.passphrase; + this.cert = opts.cert; + this.ca = opts.ca; + this.ciphers = opts.ciphers; + this.rejectUnauthorized = opts.rejectUnauthorized; + + // other options for Node.js client + this.extraHeaders = opts.extraHeaders; + + this.create(); +} + +/** + * Mix in `Emitter`. + */ + +Emitter(Request.prototype); + +/** + * Creates the XHR object and sends the request. + * + * @api private + */ + +Request.prototype.create = function () { + var opts = { agent: this.agent, xdomain: this.xd, xscheme: this.xs, enablesXDR: this.enablesXDR }; + + // 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; + + var xhr = this.xhr = new XMLHttpRequest(opts); + var self = this; + + try { + debug('xhr open %s: %s', this.method, this.uri); + xhr.open(this.method, this.uri, this.async); + try { + if (this.extraHeaders) { + xhr.setDisableHeaderCheck && xhr.setDisableHeaderCheck(true); + for (var i in this.extraHeaders) { + if (this.extraHeaders.hasOwnProperty(i)) { + xhr.setRequestHeader(i, this.extraHeaders[i]); + } + } + } + } catch (e) {} + + if ('POST' === this.method) { + try { + if (this.isBinary) { + xhr.setRequestHeader('Content-type', 'application/octet-stream'); + } else { + xhr.setRequestHeader('Content-type', 'text/plain;charset=UTF-8'); + } + } catch (e) {} + } + + try { + xhr.setRequestHeader('Accept', '*/*'); + } catch (e) {} + + // ie6 check + if ('withCredentials' in xhr) { + xhr.withCredentials = true; + } + + if (this.requestTimeout) { + xhr.timeout = this.requestTimeout; + } + + if (this.hasXDR()) { + xhr.onload = function () { + self.onLoad(); + }; + xhr.onerror = function () { + self.onError(xhr.responseText); + }; + } else { + xhr.onreadystatechange = function () { + if (xhr.readyState === 2) { + var contentType; + try { + contentType = xhr.getResponseHeader('Content-Type'); + } catch (e) {} + if (contentType === 'application/octet-stream') { + xhr.responseType = 'arraybuffer'; + } + } + if (4 !== xhr.readyState) return; + if (200 === xhr.status || 1223 === xhr.status) { + self.onLoad(); + } else { + // make sure the `error` event handler that's user-set + // does not throw in the same tick and gets caught here + setTimeout(function () { + self.onError(xhr.status); + }, 0); + } + }; + } + + debug('xhr data %s', this.data); + xhr.send(this.data); + } catch (e) { + // Need to defer since .create() is called directly fhrom the constructor + // and thus the 'error' event can only be only bound *after* this exception + // occurs. Therefore, also, we cannot throw here at all. + setTimeout(function () { + self.onError(e); + }, 0); + return; + } + + if (global.document) { + this.index = Request.requestsCount++; + Request.requests[this.index] = this; + } +}; + +/** + * Called upon successful response. + * + * @api private + */ + +Request.prototype.onSuccess = function () { + this.emit('success'); + this.cleanup(); +}; + +/** + * Called if we have data. + * + * @api private + */ + +Request.prototype.onData = function (data) { + this.emit('data', data); + this.onSuccess(); +}; + +/** + * Called upon error. + * + * @api private + */ + +Request.prototype.onError = function (err) { + this.emit('error', err); + this.cleanup(true); +}; + +/** + * Cleans up house. + * + * @api private + */ + +Request.prototype.cleanup = function (fromError) { + if ('undefined' === typeof this.xhr || null === this.xhr) { + return; + } + // xmlhttprequest + if (this.hasXDR()) { + this.xhr.onload = this.xhr.onerror = empty; + } else { + this.xhr.onreadystatechange = empty; + } + + if (fromError) { + try { + this.xhr.abort(); + } catch (e) {} + } + + if (global.document) { + delete Request.requests[this.index]; + } + + this.xhr = null; +}; + +/** + * Called upon load. + * + * @api private + */ + +Request.prototype.onLoad = function () { + var data; + try { + var contentType; + try { + contentType = this.xhr.getResponseHeader('Content-Type'); + } catch (e) {} + if (contentType === 'application/octet-stream') { + data = this.xhr.response || this.xhr.responseText; + } else { + data = this.xhr.responseText; + } + } catch (e) { + this.onError(e); + } + if (null != data) { + this.onData(data); + } +}; + +/** + * Check if it has XDomainRequest. + * + * @api private + */ + +Request.prototype.hasXDR = function () { + return 'undefined' !== typeof global.XDomainRequest && !this.xs && this.enablesXDR; +}; + +/** + * Aborts the request. + * + * @api public + */ + +Request.prototype.abort = function () { + this.cleanup(); +}; + +/** + * Aborts pending requests when unloading the window. This is needed to prevent + * memory leaks (e.g. when using IE) and to ensure that no spurious error is + * emitted. + */ + +Request.requestsCount = 0; +Request.requests = {}; + +if (global.document) { + if (global.attachEvent) { + global.attachEvent('onunload', unloadHandler); + } else if (global.addEventListener) { + global.addEventListener('beforeunload', unloadHandler, false); + } +} + +function unloadHandler () { + for (var i in Request.requests) { + if (Request.requests.hasOwnProperty(i)) { + Request.requests[i].abort(); + } + } +} -- cgit v1.2.3