const Polling = require("./polling"); const globalThis = require("../globalThis"); const rNewline = /\n/g; const rEscapedNewline = /\\n/g; /** * Global JSONP callbacks. */ let callbacks; /** * Noop. */ function empty() {} class JSONPPolling extends Polling { /** * JSONP Polling constructor. * * @param {Object} opts. * @api public */ constructor(opts) { super(opts); this.query = this.query || {}; // define global callbacks array if not present // we do this here (lazily) to avoid unneeded global pollution if (!callbacks) { // we need to consider multiple engines in the same page callbacks = globalThis.___eio = globalThis.___eio || []; } // callback identifier this.index = callbacks.length; // add callback to jsonp global const self = this; callbacks.push(function(msg) { self.onData(msg); }); // append to query string this.query.j = this.index; // prevent spurious errors from being emitted when the window is unloaded if (typeof addEventListener === "function") { addEventListener( "beforeunload", function() { if (self.script) self.script.onerror = empty; }, false ); } } /** * JSONP only supports binary as base64 encoded strings */ get supportsBinary() { return false; } /** * Closes the socket. * * @api private */ doClose() { if (this.script) { this.script.parentNode.removeChild(this.script); this.script = null; } if (this.form) { this.form.parentNode.removeChild(this.form); this.form = null; this.iframe = null; } super.doClose(); } /** * Starts a poll cycle. * * @api private */ doPoll() { const self = this; const script = document.createElement("script"); if (this.script) { this.script.parentNode.removeChild(this.script); this.script = null; } script.async = true; script.src = this.uri(); script.onerror = function(e) { self.onError("jsonp poll error", e); }; const insertAt = document.getElementsByTagName("script")[0]; if (insertAt) { insertAt.parentNode.insertBefore(script, insertAt); } else { (document.head || document.body).appendChild(script); } this.script = script; const isUAgecko = "undefined" !== typeof navigator && /gecko/i.test(navigator.userAgent); if (isUAgecko) { setTimeout(function() { const iframe = document.createElement("iframe"); document.body.appendChild(iframe); document.body.removeChild(iframe); }, 100); } } /** * Writes with a hidden iframe. * * @param {String} data to send * @param {Function} called upon flush. * @api private */ doWrite(data, fn) { const self = this; let iframe; if (!this.form) { const form = document.createElement("form"); const area = document.createElement("textarea"); const id = (this.iframeId = "eio_iframe_" + this.index); form.className = "socketio"; form.style.position = "absolute"; form.style.top = "-1000px"; form.style.left = "-1000px"; form.target = id; form.method = "POST"; form.setAttribute("accept-charset", "utf-8"); area.name = "d"; form.appendChild(area); document.body.appendChild(form); this.form = form; this.area = area; } this.form.action = this.uri(); function complete() { initIframe(); fn(); } function initIframe() { if (self.iframe) { try { self.form.removeChild(self.iframe); } catch (e) { self.onError("jsonp polling iframe removal error", e); } } try { // ie6 dynamic iframes with target="" support (thanks Chris Lambacher) const html = '