eventsource.js 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048
  1. /** @license
  2. * eventsource.js
  3. * Available under MIT License (MIT)
  4. * https://github.com/Yaffle/EventSource/
  5. */
  6. /*jslint indent: 2, vars: true, plusplus: true */
  7. /*global setTimeout, clearTimeout */
  8. (function (global) {
  9. "use strict";
  10. var setTimeout = global.setTimeout;
  11. var clearTimeout = global.clearTimeout;
  12. var XMLHttpRequest = global.XMLHttpRequest;
  13. var XDomainRequest = global.XDomainRequest;
  14. var ActiveXObject = global.ActiveXObject;
  15. var NativeEventSource = global.EventSource;
  16. var document = global.document;
  17. var Promise = global.Promise;
  18. var fetch = global.fetch;
  19. var Response = global.Response;
  20. var TextDecoder = global.TextDecoder;
  21. var TextEncoder = global.TextEncoder;
  22. var AbortController = global.AbortController;
  23. if (typeof window !== "undefined" && typeof document !== "undefined" && !("readyState" in document) && document.body == null) { // Firefox 2
  24. document.readyState = "loading";
  25. window.addEventListener("load", function (event) {
  26. document.readyState = "complete";
  27. }, false);
  28. }
  29. if (XMLHttpRequest == null && ActiveXObject != null) { // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest_in_IE6
  30. XMLHttpRequest = function () {
  31. return new ActiveXObject("Microsoft.XMLHTTP");
  32. };
  33. }
  34. if (Object.create == undefined) {
  35. Object.create = function (C) {
  36. function F(){}
  37. F.prototype = C;
  38. return new F();
  39. };
  40. }
  41. if (!Date.now) {
  42. Date.now = function now() {
  43. return new Date().getTime();
  44. };
  45. }
  46. // see #118 (Promise#finally with polyfilled Promise)
  47. // see #123 (data URLs crash Edge)
  48. // see #125 (CSP violations)
  49. // see pull/#138
  50. // => No way to polyfill Promise#finally
  51. if (AbortController == undefined) {
  52. var originalFetch2 = fetch;
  53. fetch = function (url, options) {
  54. var signal = options.signal;
  55. return originalFetch2(url, {headers: options.headers, credentials: options.credentials, cache: options.cache}).then(function (response) {
  56. var reader = response.body.getReader();
  57. signal._reader = reader;
  58. if (signal._aborted) {
  59. signal._reader.cancel();
  60. }
  61. return {
  62. status: response.status,
  63. statusText: response.statusText,
  64. headers: response.headers,
  65. body: {
  66. getReader: function () {
  67. return reader;
  68. }
  69. }
  70. };
  71. });
  72. };
  73. AbortController = function () {
  74. this.signal = {
  75. _reader: null,
  76. _aborted: false
  77. };
  78. this.abort = function () {
  79. if (this.signal._reader != null) {
  80. this.signal._reader.cancel();
  81. }
  82. this.signal._aborted = true;
  83. };
  84. };
  85. }
  86. function TextDecoderPolyfill() {
  87. this.bitsNeeded = 0;
  88. this.codePoint = 0;
  89. }
  90. TextDecoderPolyfill.prototype.decode = function (octets) {
  91. function valid(codePoint, shift, octetsCount) {
  92. if (octetsCount === 1) {
  93. return codePoint >= 0x0080 >> shift && codePoint << shift <= 0x07FF;
  94. }
  95. if (octetsCount === 2) {
  96. return codePoint >= 0x0800 >> shift && codePoint << shift <= 0xD7FF || codePoint >= 0xE000 >> shift && codePoint << shift <= 0xFFFF;
  97. }
  98. if (octetsCount === 3) {
  99. return codePoint >= 0x010000 >> shift && codePoint << shift <= 0x10FFFF;
  100. }
  101. throw new Error();
  102. }
  103. function octetsCount(bitsNeeded, codePoint) {
  104. if (bitsNeeded === 6 * 1) {
  105. return codePoint >> 6 > 15 ? 3 : codePoint > 31 ? 2 : 1;
  106. }
  107. if (bitsNeeded === 6 * 2) {
  108. return codePoint > 15 ? 3 : 2;
  109. }
  110. if (bitsNeeded === 6 * 3) {
  111. return 3;
  112. }
  113. throw new Error();
  114. }
  115. var REPLACER = 0xFFFD;
  116. var string = "";
  117. var bitsNeeded = this.bitsNeeded;
  118. var codePoint = this.codePoint;
  119. for (var i = 0; i < octets.length; i += 1) {
  120. var octet = octets[i];
  121. if (bitsNeeded !== 0) {
  122. if (octet < 128 || octet > 191 || !valid(codePoint << 6 | octet & 63, bitsNeeded - 6, octetsCount(bitsNeeded, codePoint))) {
  123. bitsNeeded = 0;
  124. codePoint = REPLACER;
  125. string += String.fromCharCode(codePoint);
  126. }
  127. }
  128. if (bitsNeeded === 0) {
  129. if (octet >= 0 && octet <= 127) {
  130. bitsNeeded = 0;
  131. codePoint = octet;
  132. } else if (octet >= 192 && octet <= 223) {
  133. bitsNeeded = 6 * 1;
  134. codePoint = octet & 31;
  135. } else if (octet >= 224 && octet <= 239) {
  136. bitsNeeded = 6 * 2;
  137. codePoint = octet & 15;
  138. } else if (octet >= 240 && octet <= 247) {
  139. bitsNeeded = 6 * 3;
  140. codePoint = octet & 7;
  141. } else {
  142. bitsNeeded = 0;
  143. codePoint = REPLACER;
  144. }
  145. if (bitsNeeded !== 0 && !valid(codePoint, bitsNeeded, octetsCount(bitsNeeded, codePoint))) {
  146. bitsNeeded = 0;
  147. codePoint = REPLACER;
  148. }
  149. } else {
  150. bitsNeeded -= 6;
  151. codePoint = codePoint << 6 | octet & 63;
  152. }
  153. if (bitsNeeded === 0) {
  154. if (codePoint <= 0xFFFF) {
  155. string += String.fromCharCode(codePoint);
  156. } else {
  157. string += String.fromCharCode(0xD800 + (codePoint - 0xFFFF - 1 >> 10));
  158. string += String.fromCharCode(0xDC00 + (codePoint - 0xFFFF - 1 & 0x3FF));
  159. }
  160. }
  161. }
  162. this.bitsNeeded = bitsNeeded;
  163. this.codePoint = codePoint;
  164. return string;
  165. };
  166. // Firefox < 38 throws an error with stream option
  167. var supportsStreamOption = function () {
  168. try {
  169. return new TextDecoder().decode(new TextEncoder().encode("test"), {stream: true}) === "test";
  170. } catch (error) {
  171. console.debug("TextDecoder does not support streaming option. Using polyfill instead: " + error);
  172. }
  173. return false;
  174. };
  175. // IE, Edge
  176. if (TextDecoder == undefined || TextEncoder == undefined || !supportsStreamOption()) {
  177. TextDecoder = TextDecoderPolyfill;
  178. }
  179. var k = function () {
  180. };
  181. function XHRWrapper(xhr) {
  182. this.withCredentials = false;
  183. this.readyState = 0;
  184. this.status = 0;
  185. this.statusText = "";
  186. this.responseText = "";
  187. this.onprogress = k;
  188. this.onload = k;
  189. this.onerror = k;
  190. this.onreadystatechange = k;
  191. this._contentType = "";
  192. this._xhr = xhr;
  193. this._sendTimeout = 0;
  194. this._abort = k;
  195. }
  196. XHRWrapper.prototype.open = function (method, url) {
  197. this._abort(true);
  198. var that = this;
  199. var xhr = this._xhr;
  200. var state = 1;
  201. var timeout = 0;
  202. this._abort = function (silent) {
  203. if (that._sendTimeout !== 0) {
  204. clearTimeout(that._sendTimeout);
  205. that._sendTimeout = 0;
  206. }
  207. if (state === 1 || state === 2 || state === 3) {
  208. state = 4;
  209. xhr.onload = k;
  210. xhr.onerror = k;
  211. xhr.onabort = k;
  212. xhr.onprogress = k;
  213. xhr.onreadystatechange = k;
  214. // IE 8 - 9: XDomainRequest#abort() does not fire any event
  215. // Opera < 10: XMLHttpRequest#abort() does not fire any event
  216. xhr.abort();
  217. if (timeout !== 0) {
  218. clearTimeout(timeout);
  219. timeout = 0;
  220. }
  221. if (!silent) {
  222. that.readyState = 4;
  223. that.onabort(null);
  224. that.onreadystatechange();
  225. }
  226. }
  227. state = 0;
  228. };
  229. var onStart = function () {
  230. if (state === 1) {
  231. //state = 2;
  232. var status = 0;
  233. var statusText = "";
  234. var contentType = undefined;
  235. if (!("contentType" in xhr)) {
  236. try {
  237. status = xhr.status;
  238. statusText = xhr.statusText;
  239. contentType = xhr.getResponseHeader("Content-Type");
  240. } catch (error) {
  241. // IE < 10 throws exception for `xhr.status` when xhr.readyState === 2 || xhr.readyState === 3
  242. // Opera < 11 throws exception for `xhr.status` when xhr.readyState === 2
  243. // https://bugs.webkit.org/show_bug.cgi?id=29121
  244. status = 0;
  245. statusText = "";
  246. contentType = undefined;
  247. // Firefox < 14, Chrome ?, Safari ?
  248. // https://bugs.webkit.org/show_bug.cgi?id=29658
  249. // https://bugs.webkit.org/show_bug.cgi?id=77854
  250. }
  251. } else {
  252. status = 200;
  253. statusText = "OK";
  254. contentType = xhr.contentType;
  255. }
  256. if (status !== 0) {
  257. state = 2;
  258. that.readyState = 2;
  259. that.status = status;
  260. that.statusText = statusText;
  261. that._contentType = contentType;
  262. that.onreadystatechange();
  263. }
  264. }
  265. };
  266. var onProgress = function () {
  267. onStart();
  268. if (state === 2 || state === 3) {
  269. state = 3;
  270. var responseText = "";
  271. try {
  272. responseText = xhr.responseText;
  273. } catch (error) {
  274. // IE 8 - 9 with XMLHttpRequest
  275. }
  276. that.readyState = 3;
  277. that.responseText = responseText;
  278. that.onprogress();
  279. }
  280. };
  281. var onFinish = function (type, event) {
  282. if (event == null || event.preventDefault == null) {
  283. event = {
  284. preventDefault: k
  285. };
  286. }
  287. // Firefox 52 fires "readystatechange" (xhr.readyState === 4) without final "readystatechange" (xhr.readyState === 3)
  288. // IE 8 fires "onload" without "onprogress"
  289. onProgress();
  290. if (state === 1 || state === 2 || state === 3) {
  291. state = 4;
  292. if (timeout !== 0) {
  293. clearTimeout(timeout);
  294. timeout = 0;
  295. }
  296. that.readyState = 4;
  297. if (type === "load") {
  298. that.onload(event);
  299. } else if (type === "error") {
  300. that.onerror(event);
  301. } else if (type === "abort") {
  302. that.onabort(event);
  303. } else {
  304. throw new TypeError();
  305. }
  306. that.onreadystatechange();
  307. }
  308. };
  309. var onReadyStateChange = function (event) {
  310. if (xhr != undefined) { // Opera 12
  311. if (xhr.readyState === 4) {
  312. if (!("onload" in xhr) || !("onerror" in xhr) || !("onabort" in xhr)) {
  313. onFinish(xhr.responseText === "" ? "error" : "load", event);
  314. }
  315. } else if (xhr.readyState === 3) {
  316. if (!("onprogress" in xhr)) { // testing XMLHttpRequest#responseText too many times is too slow in IE 11
  317. // and in Firefox 3.6
  318. onProgress();
  319. }
  320. } else if (xhr.readyState === 2) {
  321. onStart();
  322. }
  323. }
  324. };
  325. var onTimeout = function () {
  326. timeout = setTimeout(function () {
  327. onTimeout();
  328. }, 500);
  329. if (xhr.readyState === 3) {
  330. onProgress();
  331. }
  332. };
  333. // XDomainRequest#abort removes onprogress, onerror, onload
  334. if ("onload" in xhr) {
  335. xhr.onload = function (event) {
  336. onFinish("load", event);
  337. };
  338. }
  339. if ("onerror" in xhr) {
  340. xhr.onerror = function (event) {
  341. onFinish("error", event);
  342. };
  343. }
  344. // improper fix to match Firefox behaviour, but it is better than just ignore abort
  345. // see https://bugzilla.mozilla.org/show_bug.cgi?id=768596
  346. // https://bugzilla.mozilla.org/show_bug.cgi?id=880200
  347. // https://code.google.com/p/chromium/issues/detail?id=153570
  348. // IE 8 fires "onload" without "onprogress
  349. if ("onabort" in xhr) {
  350. xhr.onabort = function (event) {
  351. onFinish("abort", event);
  352. };
  353. }
  354. if ("onprogress" in xhr) {
  355. xhr.onprogress = onProgress;
  356. }
  357. // IE 8 - 9 (XMLHTTPRequest)
  358. // Opera < 12
  359. // Firefox < 3.5
  360. // Firefox 3.5 - 3.6 - ? < 9.0
  361. // onprogress is not fired sometimes or delayed
  362. // see also #64 (significant lag in IE 11)
  363. if ("onreadystatechange" in xhr) {
  364. xhr.onreadystatechange = function (event) {
  365. onReadyStateChange(event);
  366. };
  367. }
  368. if ("contentType" in xhr || !("ontimeout" in XMLHttpRequest.prototype)) {
  369. url += (url.indexOf("?") === -1 ? "?" : "&") + "padding=true";
  370. }
  371. xhr.open(method, url, true);
  372. if ("readyState" in xhr) {
  373. // workaround for Opera 12 issue with "progress" events
  374. // #91 (XMLHttpRequest onprogress not fired for streaming response in Edge 14-15-?)
  375. timeout = setTimeout(function () {
  376. onTimeout();
  377. }, 0);
  378. }
  379. };
  380. XHRWrapper.prototype.abort = function () {
  381. this._abort(false);
  382. };
  383. XHRWrapper.prototype.getResponseHeader = function (name) {
  384. return this._contentType;
  385. };
  386. XHRWrapper.prototype.setRequestHeader = function (name, value) {
  387. var xhr = this._xhr;
  388. if ("setRequestHeader" in xhr) {
  389. xhr.setRequestHeader(name, value);
  390. }
  391. };
  392. XHRWrapper.prototype.getAllResponseHeaders = function () {
  393. // XMLHttpRequest#getAllResponseHeaders returns null for CORS requests in Firefox 3.6.28
  394. return this._xhr.getAllResponseHeaders != undefined ? this._xhr.getAllResponseHeaders() || "" : "";
  395. };
  396. XHRWrapper.prototype.send = function () {
  397. // loading indicator in Safari < ? (6), Chrome < 14, Firefox
  398. // https://bugzilla.mozilla.org/show_bug.cgi?id=736723
  399. if ((!("ontimeout" in XMLHttpRequest.prototype) || (!("sendAsBinary" in XMLHttpRequest.prototype) && !("mozAnon" in XMLHttpRequest.prototype))) &&
  400. document != undefined &&
  401. document.readyState != undefined &&
  402. document.readyState !== "complete") {
  403. var that = this;
  404. that._sendTimeout = setTimeout(function () {
  405. that._sendTimeout = 0;
  406. that.send();
  407. }, 4);
  408. return;
  409. }
  410. var xhr = this._xhr;
  411. // withCredentials should be set after "open" for Safari and Chrome (< 19 ?)
  412. if ("withCredentials" in xhr) {
  413. xhr.withCredentials = this.withCredentials;
  414. }
  415. try {
  416. // xhr.send(); throws "Not enough arguments" in Firefox 3.0
  417. xhr.send(undefined);
  418. } catch (error1) {
  419. // Safari 5.1.7, Opera 12
  420. throw error1;
  421. }
  422. };
  423. function toLowerCase(name) {
  424. return name.replace(/[A-Z]/g, function (c) {
  425. return String.fromCharCode(c.charCodeAt(0) + 0x20);
  426. });
  427. }
  428. function HeadersPolyfill(all) {
  429. // Get headers: implemented according to mozilla's example code: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getAllResponseHeaders#Example
  430. var map = Object.create(null);
  431. var array = all.split("\r\n");
  432. for (var i = 0; i < array.length; i += 1) {
  433. var line = array[i];
  434. var parts = line.split(": ");
  435. var name = parts.shift();
  436. var value = parts.join(": ");
  437. map[toLowerCase(name)] = value;
  438. }
  439. this._map = map;
  440. }
  441. HeadersPolyfill.prototype.get = function (name) {
  442. return this._map[toLowerCase(name)];
  443. };
  444. if (XMLHttpRequest != null && XMLHttpRequest.HEADERS_RECEIVED == null) { // IE < 9, Firefox 3.6
  445. XMLHttpRequest.HEADERS_RECEIVED = 2;
  446. }
  447. function XHRTransport() {
  448. }
  449. XHRTransport.prototype.open = function (xhr, onStartCallback, onProgressCallback, onFinishCallback, url, withCredentials, headers) {
  450. xhr.open("GET", url);
  451. var offset = 0;
  452. xhr.onprogress = function () {
  453. var responseText = xhr.responseText;
  454. var chunk = responseText.slice(offset);
  455. offset += chunk.length;
  456. onProgressCallback(chunk);
  457. };
  458. xhr.onerror = function (event) {
  459. event.preventDefault();
  460. onFinishCallback(new Error("NetworkError"));
  461. };
  462. xhr.onload = function () {
  463. onFinishCallback(null);
  464. };
  465. xhr.onabort = function () {
  466. onFinishCallback(null);
  467. };
  468. xhr.onreadystatechange = function () {
  469. if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
  470. var status = xhr.status;
  471. var statusText = xhr.statusText;
  472. var contentType = xhr.getResponseHeader("Content-Type");
  473. var headers = xhr.getAllResponseHeaders();
  474. onStartCallback(status, statusText, contentType, new HeadersPolyfill(headers));
  475. }
  476. };
  477. xhr.withCredentials = withCredentials;
  478. for (var name in headers) {
  479. if (Object.prototype.hasOwnProperty.call(headers, name)) {
  480. xhr.setRequestHeader(name, headers[name]);
  481. }
  482. }
  483. xhr.send();
  484. return xhr;
  485. };
  486. function HeadersWrapper(headers) {
  487. this._headers = headers;
  488. }
  489. HeadersWrapper.prototype.get = function (name) {
  490. return this._headers.get(name);
  491. };
  492. function FetchTransport() {
  493. }
  494. FetchTransport.prototype.open = function (xhr, onStartCallback, onProgressCallback, onFinishCallback, url, withCredentials, headers) {
  495. var reader = null;
  496. var controller = new AbortController();
  497. var signal = controller.signal;
  498. var textDecoder = new TextDecoder();
  499. fetch(url, {
  500. headers: headers,
  501. credentials: withCredentials ? "include" : "same-origin",
  502. signal: signal,
  503. cache: "no-store"
  504. }).then(function (response) {
  505. reader = response.body.getReader();
  506. onStartCallback(response.status, response.statusText, response.headers.get("Content-Type"), new HeadersWrapper(response.headers));
  507. // see https://github.com/promises-aplus/promises-spec/issues/179
  508. return new Promise(function (resolve, reject) {
  509. var readNextChunk = function () {
  510. reader.read().then(function (result) {
  511. if (result.done) {
  512. //Note: bytes in textDecoder are ignored
  513. resolve(undefined);
  514. } else {
  515. var chunk = textDecoder.decode(result.value, {stream: true});
  516. onProgressCallback(chunk);
  517. readNextChunk();
  518. }
  519. })["catch"](function (error) {
  520. reject(error);
  521. });
  522. };
  523. readNextChunk();
  524. });
  525. })["catch"](function (error) {
  526. if (error.name === "AbortError") {
  527. return undefined;
  528. } else {
  529. return error;
  530. }
  531. }).then(function (error) {
  532. onFinishCallback(error);
  533. });
  534. return {
  535. abort: function () {
  536. if (reader != null) {
  537. reader.cancel(); // https://bugzilla.mozilla.org/show_bug.cgi?id=1583815
  538. }
  539. controller.abort();
  540. }
  541. };
  542. };
  543. function EventTarget() {
  544. this._listeners = Object.create(null);
  545. }
  546. function throwError(e) {
  547. setTimeout(function () {
  548. throw e;
  549. }, 0);
  550. }
  551. EventTarget.prototype.dispatchEvent = function (event) {
  552. event.target = this;
  553. var typeListeners = this._listeners[event.type];
  554. if (typeListeners != undefined) {
  555. var length = typeListeners.length;
  556. for (var i = 0; i < length; i += 1) {
  557. var listener = typeListeners[i];
  558. try {
  559. if (typeof listener.handleEvent === "function") {
  560. listener.handleEvent(event);
  561. } else {
  562. listener.call(this, event);
  563. }
  564. } catch (e) {
  565. throwError(e);
  566. }
  567. }
  568. }
  569. };
  570. EventTarget.prototype.addEventListener = function (type, listener) {
  571. type = String(type);
  572. var listeners = this._listeners;
  573. var typeListeners = listeners[type];
  574. if (typeListeners == undefined) {
  575. typeListeners = [];
  576. listeners[type] = typeListeners;
  577. }
  578. var found = false;
  579. for (var i = 0; i < typeListeners.length; i += 1) {
  580. if (typeListeners[i] === listener) {
  581. found = true;
  582. }
  583. }
  584. if (!found) {
  585. typeListeners.push(listener);
  586. }
  587. };
  588. EventTarget.prototype.removeEventListener = function (type, listener) {
  589. type = String(type);
  590. var listeners = this._listeners;
  591. var typeListeners = listeners[type];
  592. if (typeListeners != undefined) {
  593. var filtered = [];
  594. for (var i = 0; i < typeListeners.length; i += 1) {
  595. if (typeListeners[i] !== listener) {
  596. filtered.push(typeListeners[i]);
  597. }
  598. }
  599. if (filtered.length === 0) {
  600. delete listeners[type];
  601. } else {
  602. listeners[type] = filtered;
  603. }
  604. }
  605. };
  606. function Event(type) {
  607. this.type = type;
  608. this.target = undefined;
  609. }
  610. function MessageEvent(type, options) {
  611. Event.call(this, type);
  612. this.data = options.data;
  613. this.lastEventId = options.lastEventId;
  614. }
  615. MessageEvent.prototype = Object.create(Event.prototype);
  616. function ConnectionEvent(type, options) {
  617. Event.call(this, type);
  618. this.status = options.status;
  619. this.statusText = options.statusText;
  620. this.headers = options.headers;
  621. }
  622. ConnectionEvent.prototype = Object.create(Event.prototype);
  623. function ErrorEvent(type, options) {
  624. Event.call(this, type);
  625. this.error = options.error;
  626. }
  627. ErrorEvent.prototype = Object.create(Event.prototype);
  628. var WAITING = -1;
  629. var CONNECTING = 0;
  630. var OPEN = 1;
  631. var CLOSED = 2;
  632. var AFTER_CR = -1;
  633. var FIELD_START = 0;
  634. var FIELD = 1;
  635. var VALUE_START = 2;
  636. var VALUE = 3;
  637. var contentTypeRegExp = /^text\/event\-stream(;.*)?$/i;
  638. var MINIMUM_DURATION = 1000;
  639. var MAXIMUM_DURATION = 18000000;
  640. var parseDuration = function (value, def) {
  641. var n = value == null ? def : parseInt(value, 10);
  642. if (n !== n) {
  643. n = def;
  644. }
  645. return clampDuration(n);
  646. };
  647. var clampDuration = function (n) {
  648. return Math.min(Math.max(n, MINIMUM_DURATION), MAXIMUM_DURATION);
  649. };
  650. var fire = function (that, f, event) {
  651. try {
  652. if (typeof f === "function") {
  653. f.call(that, event);
  654. }
  655. } catch (e) {
  656. throwError(e);
  657. }
  658. };
  659. function EventSourcePolyfill(url, options) {
  660. EventTarget.call(this);
  661. options = options || {};
  662. this.onopen = undefined;
  663. this.onmessage = undefined;
  664. this.onerror = undefined;
  665. this.url = undefined;
  666. this.readyState = undefined;
  667. this.withCredentials = undefined;
  668. this.headers = undefined;
  669. this._close = undefined;
  670. start(this, url, options);
  671. }
  672. function getBestXHRTransport() {
  673. return (XMLHttpRequest != undefined && ("withCredentials" in XMLHttpRequest.prototype)) || XDomainRequest == undefined
  674. ? new XMLHttpRequest()
  675. : new XDomainRequest();
  676. }
  677. var isFetchSupported = fetch != undefined && Response != undefined && "body" in Response.prototype;
  678. function start(es, url, options) {
  679. url = String(url);
  680. var withCredentials = Boolean(options.withCredentials);
  681. var lastEventIdQueryParameterName = options.lastEventIdQueryParameterName || "lastEventId";
  682. var initialRetry = clampDuration(1000);
  683. var heartbeatTimeout = parseDuration(options.heartbeatTimeout, 45000);
  684. var lastEventId = "";
  685. var retry = initialRetry;
  686. var wasActivity = false;
  687. var textLength = 0;
  688. var headers = options.headers || {};
  689. var TransportOption = options.Transport;
  690. var xhr = isFetchSupported && TransportOption == undefined ? undefined : new XHRWrapper(TransportOption != undefined ? new TransportOption() : getBestXHRTransport());
  691. var transport = TransportOption != null && typeof TransportOption !== "string" ? new TransportOption() : (xhr == undefined ? new FetchTransport() : new XHRTransport());
  692. var abortController = undefined;
  693. var timeout = 0;
  694. var currentState = WAITING;
  695. var dataBuffer = "";
  696. var lastEventIdBuffer = "";
  697. var eventTypeBuffer = "";
  698. var textBuffer = "";
  699. var state = FIELD_START;
  700. var fieldStart = 0;
  701. var valueStart = 0;
  702. var onStart = function (status, statusText, contentType, headers) {
  703. if (currentState === CONNECTING) {
  704. if (status === 200 && contentType != undefined && contentTypeRegExp.test(contentType)) {
  705. currentState = OPEN;
  706. wasActivity = Date.now();
  707. retry = initialRetry;
  708. es.readyState = OPEN;
  709. var event = new ConnectionEvent("open", {
  710. status: status,
  711. statusText: statusText,
  712. headers: headers
  713. });
  714. es.dispatchEvent(event);
  715. fire(es, es.onopen, event);
  716. } else {
  717. var message = "";
  718. if (status !== 200) {
  719. if (statusText) {
  720. statusText = statusText.replace(/\s+/g, " ");
  721. }
  722. message = "EventSource's response has a status " + status + " " + statusText + " that is not 200. Aborting the connection.";
  723. } else {
  724. message = "EventSource's response has a Content-Type specifying an unsupported type: " + (contentType == undefined ? "-" : contentType.replace(/\s+/g, " ")) + ". Aborting the connection.";
  725. }
  726. close();
  727. var event = new ConnectionEvent("error", {
  728. status: status,
  729. statusText: statusText,
  730. headers: headers
  731. });
  732. es.dispatchEvent(event);
  733. fire(es, es.onerror, event);
  734. console.error(message);
  735. }
  736. }
  737. };
  738. var onProgress = function (textChunk) {
  739. if (currentState === OPEN) {
  740. var n = -1;
  741. for (var i = 0; i < textChunk.length; i += 1) {
  742. var c = textChunk.charCodeAt(i);
  743. if (c === "\n".charCodeAt(0) || c === "\r".charCodeAt(0)) {
  744. n = i;
  745. }
  746. }
  747. var chunk = (n !== -1 ? textBuffer : "") + textChunk.slice(0, n + 1);
  748. textBuffer = (n === -1 ? textBuffer : "") + textChunk.slice(n + 1);
  749. if (textChunk !== "") {
  750. wasActivity = Date.now();
  751. textLength += textChunk.length;
  752. }
  753. for (var position = 0; position < chunk.length; position += 1) {
  754. var c = chunk.charCodeAt(position);
  755. if (state === AFTER_CR && c === "\n".charCodeAt(0)) {
  756. state = FIELD_START;
  757. } else {
  758. if (state === AFTER_CR) {
  759. state = FIELD_START;
  760. }
  761. if (c === "\r".charCodeAt(0) || c === "\n".charCodeAt(0)) {
  762. if (state !== FIELD_START) {
  763. if (state === FIELD) {
  764. valueStart = position + 1;
  765. }
  766. var field = chunk.slice(fieldStart, valueStart - 1);
  767. var value = chunk.slice(valueStart + (valueStart < position && chunk.charCodeAt(valueStart) === " ".charCodeAt(0) ? 1 : 0), position);
  768. if (field === "data") {
  769. dataBuffer += "\n";
  770. dataBuffer += value;
  771. } else if (field === "id") {
  772. lastEventIdBuffer = value;
  773. } else if (field === "event") {
  774. eventTypeBuffer = value;
  775. } else if (field === "retry") {
  776. initialRetry = parseDuration(value, initialRetry);
  777. retry = initialRetry;
  778. } else if (field === "heartbeatTimeout") {
  779. heartbeatTimeout = parseDuration(value, heartbeatTimeout);
  780. if (timeout !== 0) {
  781. clearTimeout(timeout);
  782. timeout = setTimeout(function () {
  783. onTimeout();
  784. }, heartbeatTimeout);
  785. }
  786. }
  787. }
  788. if (state === FIELD_START) {
  789. if (dataBuffer !== "") {
  790. lastEventId = lastEventIdBuffer;
  791. if (eventTypeBuffer === "") {
  792. eventTypeBuffer = "message";
  793. }
  794. var event = new MessageEvent(eventTypeBuffer, {
  795. data: dataBuffer.slice(1),
  796. lastEventId: lastEventIdBuffer
  797. });
  798. es.dispatchEvent(event);
  799. if (eventTypeBuffer === "open") {
  800. fire(es, es.onopen, event);
  801. } else if (eventTypeBuffer === "message") {
  802. fire(es, es.onmessage, event);
  803. } else if (eventTypeBuffer === "error") {
  804. fire(es, es.onerror, event);
  805. }
  806. if (currentState === CLOSED) {
  807. return;
  808. }
  809. }
  810. dataBuffer = "";
  811. eventTypeBuffer = "";
  812. }
  813. state = c === "\r".charCodeAt(0) ? AFTER_CR : FIELD_START;
  814. } else {
  815. if (state === FIELD_START) {
  816. fieldStart = position;
  817. state = FIELD;
  818. }
  819. if (state === FIELD) {
  820. if (c === ":".charCodeAt(0)) {
  821. valueStart = position + 1;
  822. state = VALUE_START;
  823. }
  824. } else if (state === VALUE_START) {
  825. state = VALUE;
  826. }
  827. }
  828. }
  829. }
  830. }
  831. };
  832. var onFinish = function (error) {
  833. if (currentState === OPEN || currentState === CONNECTING) {
  834. currentState = WAITING;
  835. if (timeout !== 0) {
  836. clearTimeout(timeout);
  837. timeout = 0;
  838. }
  839. timeout = setTimeout(function () {
  840. onTimeout();
  841. }, retry);
  842. retry = clampDuration(Math.min(initialRetry * 16, retry * 2));
  843. es.readyState = CONNECTING;
  844. var event = new ErrorEvent("error", {error: error});
  845. es.dispatchEvent(event);
  846. fire(es, es.onerror, event);
  847. if (error != undefined) {
  848. console.error(error);
  849. }
  850. }
  851. };
  852. var close = function () {
  853. currentState = CLOSED;
  854. if (abortController != undefined) {
  855. abortController.abort();
  856. abortController = undefined;
  857. }
  858. if (timeout !== 0) {
  859. clearTimeout(timeout);
  860. timeout = 0;
  861. }
  862. es.readyState = CLOSED;
  863. };
  864. var onTimeout = function () {
  865. timeout = 0;
  866. if (currentState !== WAITING) {
  867. if (!wasActivity && abortController != undefined) {
  868. onFinish(new Error("No activity within " + heartbeatTimeout + " milliseconds." + " " + (currentState === CONNECTING ? "No response received." : textLength + " chars received.") + " " + "Reconnecting."));
  869. if (abortController != undefined) {
  870. abortController.abort();
  871. abortController = undefined;
  872. }
  873. } else {
  874. var nextHeartbeat = Math.max((wasActivity || Date.now()) + heartbeatTimeout - Date.now(), 1);
  875. wasActivity = false;
  876. timeout = setTimeout(function () {
  877. onTimeout();
  878. }, nextHeartbeat);
  879. }
  880. return;
  881. }
  882. wasActivity = false;
  883. textLength = 0;
  884. timeout = setTimeout(function () {
  885. onTimeout();
  886. }, heartbeatTimeout);
  887. currentState = CONNECTING;
  888. dataBuffer = "";
  889. eventTypeBuffer = "";
  890. lastEventIdBuffer = lastEventId;
  891. textBuffer = "";
  892. fieldStart = 0;
  893. valueStart = 0;
  894. state = FIELD_START;
  895. // https://bugzilla.mozilla.org/show_bug.cgi?id=428916
  896. // Request header field Last-Event-ID is not allowed by Access-Control-Allow-Headers.
  897. var requestURL = url;
  898. if (url.slice(0, 5) !== "data:" && url.slice(0, 5) !== "blob:") {
  899. if (lastEventId !== "") {
  900. // Remove the lastEventId parameter if it's already part of the request URL.
  901. var i = url.indexOf("?");
  902. requestURL = i === -1 ? url : url.slice(0, i + 1) + url.slice(i + 1).replace(/(?:^|&)([^=&]*)(?:=[^&]*)?/g, function (p, paramName) {
  903. return paramName === lastEventIdQueryParameterName ? '' : p;
  904. });
  905. // Append the current lastEventId to the request URL.
  906. requestURL += (url.indexOf("?") === -1 ? "?" : "&") + lastEventIdQueryParameterName +"=" + encodeURIComponent(lastEventId);
  907. }
  908. }
  909. var withCredentials = es.withCredentials;
  910. var requestHeaders = {};
  911. requestHeaders["Accept"] = "text/event-stream";
  912. var headers = es.headers;
  913. if (headers != undefined) {
  914. for (var name in headers) {
  915. if (Object.prototype.hasOwnProperty.call(headers, name)) {
  916. requestHeaders[name] = headers[name];
  917. }
  918. }
  919. }
  920. try {
  921. abortController = transport.open(xhr, onStart, onProgress, onFinish, requestURL, withCredentials, requestHeaders);
  922. } catch (error) {
  923. close();
  924. throw error;
  925. }
  926. };
  927. es.url = url;
  928. es.readyState = CONNECTING;
  929. es.withCredentials = withCredentials;
  930. es.headers = headers;
  931. es._close = close;
  932. onTimeout();
  933. }
  934. EventSourcePolyfill.prototype = Object.create(EventTarget.prototype);
  935. EventSourcePolyfill.prototype.CONNECTING = CONNECTING;
  936. EventSourcePolyfill.prototype.OPEN = OPEN;
  937. EventSourcePolyfill.prototype.CLOSED = CLOSED;
  938. EventSourcePolyfill.prototype.close = function () {
  939. this._close();
  940. };
  941. EventSourcePolyfill.CONNECTING = CONNECTING;
  942. EventSourcePolyfill.OPEN = OPEN;
  943. EventSourcePolyfill.CLOSED = CLOSED;
  944. EventSourcePolyfill.prototype.withCredentials = undefined;
  945. var R = NativeEventSource
  946. if (XMLHttpRequest != undefined && (NativeEventSource == undefined || !("withCredentials" in NativeEventSource.prototype))) {
  947. // Why replace a native EventSource ?
  948. // https://bugzilla.mozilla.org/show_bug.cgi?id=444328
  949. // https://bugzilla.mozilla.org/show_bug.cgi?id=831392
  950. // https://code.google.com/p/chromium/issues/detail?id=260144
  951. // https://code.google.com/p/chromium/issues/detail?id=225654
  952. // ...
  953. R = EventSourcePolyfill;
  954. }
  955. (function (factory) {
  956. if (typeof module === "object" && typeof module.exports === "object") {
  957. var v = factory(exports);
  958. if (v !== undefined) module.exports = v;
  959. }
  960. else if (typeof define === "function" && define.amd) {
  961. define(["exports"], factory);
  962. }
  963. else {
  964. factory(global);
  965. }
  966. })(function (exports) {
  967. exports.EventSourcePolyfill = EventSourcePolyfill;
  968. exports.NativeEventSource = NativeEventSource;
  969. exports.EventSource = R;
  970. });
  971. }(typeof globalThis === 'undefined' ? (typeof window !== 'undefined' ? window : typeof self !== 'undefined' ? self : this) : globalThis));