uniapp,h5

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. import { Polling } from "./polling.js";
  2. import { Emitter } from "@socket.io/component-emitter";
  3. import { installTimerFunctions, pick } from "../util.js";
  4. import { globalThisShim as globalThis } from "../globals.node.js";
  5. import { hasCORS } from "../contrib/has-cors.js";
  6. import debugModule from "debug"; // debug()
  7. const debug = debugModule("engine.io-client:polling"); // debug()
  8. function empty() { }
  9. export class BaseXHR extends Polling {
  10. /**
  11. * XHR Polling constructor.
  12. *
  13. * @param {Object} opts
  14. * @package
  15. */
  16. constructor(opts) {
  17. super(opts);
  18. if (typeof location !== "undefined") {
  19. const isSSL = "https:" === location.protocol;
  20. let port = location.port;
  21. // some user agents have empty `location.port`
  22. if (!port) {
  23. port = isSSL ? "443" : "80";
  24. }
  25. this.xd =
  26. (typeof location !== "undefined" &&
  27. opts.hostname !== location.hostname) ||
  28. port !== opts.port;
  29. }
  30. }
  31. /**
  32. * Sends data.
  33. *
  34. * @param {String} data to send.
  35. * @param {Function} called upon flush.
  36. * @private
  37. */
  38. doWrite(data, fn) {
  39. const req = this.request({
  40. method: "POST",
  41. data: data,
  42. });
  43. req.on("success", fn);
  44. req.on("error", (xhrStatus, context) => {
  45. this.onError("xhr post error", xhrStatus, context);
  46. });
  47. }
  48. /**
  49. * Starts a poll cycle.
  50. *
  51. * @private
  52. */
  53. doPoll() {
  54. debug("xhr poll");
  55. const req = this.request();
  56. req.on("data", this.onData.bind(this));
  57. req.on("error", (xhrStatus, context) => {
  58. this.onError("xhr poll error", xhrStatus, context);
  59. });
  60. this.pollXhr = req;
  61. }
  62. }
  63. export class Request extends Emitter {
  64. /**
  65. * Request constructor
  66. *
  67. * @param {Object} options
  68. * @package
  69. */
  70. constructor(createRequest, uri, opts) {
  71. super();
  72. this.createRequest = createRequest;
  73. installTimerFunctions(this, opts);
  74. this._opts = opts;
  75. this._method = opts.method || "GET";
  76. this._uri = uri;
  77. this._data = undefined !== opts.data ? opts.data : null;
  78. this._create();
  79. }
  80. /**
  81. * Creates the XHR object and sends the request.
  82. *
  83. * @private
  84. */
  85. _create() {
  86. var _a;
  87. const opts = pick(this._opts, "agent", "pfx", "key", "passphrase", "cert", "ca", "ciphers", "rejectUnauthorized", "autoUnref");
  88. opts.xdomain = !!this._opts.xd;
  89. const xhr = (this._xhr = this.createRequest(opts));
  90. try {
  91. debug("xhr open %s: %s", this._method, this._uri);
  92. xhr.open(this._method, this._uri, true);
  93. try {
  94. if (this._opts.extraHeaders) {
  95. // @ts-ignore
  96. xhr.setDisableHeaderCheck && xhr.setDisableHeaderCheck(true);
  97. for (let i in this._opts.extraHeaders) {
  98. if (this._opts.extraHeaders.hasOwnProperty(i)) {
  99. xhr.setRequestHeader(i, this._opts.extraHeaders[i]);
  100. }
  101. }
  102. }
  103. }
  104. catch (e) { }
  105. if ("POST" === this._method) {
  106. try {
  107. xhr.setRequestHeader("Content-type", "text/plain;charset=UTF-8");
  108. }
  109. catch (e) { }
  110. }
  111. try {
  112. xhr.setRequestHeader("Accept", "*/*");
  113. }
  114. catch (e) { }
  115. (_a = this._opts.cookieJar) === null || _a === void 0 ? void 0 : _a.addCookies(xhr);
  116. // ie6 check
  117. if ("withCredentials" in xhr) {
  118. xhr.withCredentials = this._opts.withCredentials;
  119. }
  120. if (this._opts.requestTimeout) {
  121. xhr.timeout = this._opts.requestTimeout;
  122. }
  123. xhr.onreadystatechange = () => {
  124. var _a;
  125. if (xhr.readyState === 3) {
  126. (_a = this._opts.cookieJar) === null || _a === void 0 ? void 0 : _a.parseCookies(
  127. // @ts-ignore
  128. xhr.getResponseHeader("set-cookie"));
  129. }
  130. if (4 !== xhr.readyState)
  131. return;
  132. if (200 === xhr.status || 1223 === xhr.status) {
  133. this._onLoad();
  134. }
  135. else {
  136. // make sure the `error` event handler that's user-set
  137. // does not throw in the same tick and gets caught here
  138. this.setTimeoutFn(() => {
  139. this._onError(typeof xhr.status === "number" ? xhr.status : 0);
  140. }, 0);
  141. }
  142. };
  143. debug("xhr data %s", this._data);
  144. xhr.send(this._data);
  145. }
  146. catch (e) {
  147. // Need to defer since .create() is called directly from the constructor
  148. // and thus the 'error' event can only be only bound *after* this exception
  149. // occurs. Therefore, also, we cannot throw here at all.
  150. this.setTimeoutFn(() => {
  151. this._onError(e);
  152. }, 0);
  153. return;
  154. }
  155. if (typeof document !== "undefined") {
  156. this._index = Request.requestsCount++;
  157. Request.requests[this._index] = this;
  158. }
  159. }
  160. /**
  161. * Called upon error.
  162. *
  163. * @private
  164. */
  165. _onError(err) {
  166. this.emitReserved("error", err, this._xhr);
  167. this._cleanup(true);
  168. }
  169. /**
  170. * Cleans up house.
  171. *
  172. * @private
  173. */
  174. _cleanup(fromError) {
  175. if ("undefined" === typeof this._xhr || null === this._xhr) {
  176. return;
  177. }
  178. this._xhr.onreadystatechange = empty;
  179. if (fromError) {
  180. try {
  181. this._xhr.abort();
  182. }
  183. catch (e) { }
  184. }
  185. if (typeof document !== "undefined") {
  186. delete Request.requests[this._index];
  187. }
  188. this._xhr = null;
  189. }
  190. /**
  191. * Called upon load.
  192. *
  193. * @private
  194. */
  195. _onLoad() {
  196. const data = this._xhr.responseText;
  197. if (data !== null) {
  198. this.emitReserved("data", data);
  199. this.emitReserved("success");
  200. this._cleanup();
  201. }
  202. }
  203. /**
  204. * Aborts the request.
  205. *
  206. * @package
  207. */
  208. abort() {
  209. this._cleanup();
  210. }
  211. }
  212. Request.requestsCount = 0;
  213. Request.requests = {};
  214. /**
  215. * Aborts pending requests when unloading the window. This is needed to prevent
  216. * memory leaks (e.g. when using IE) and to ensure that no spurious error is
  217. * emitted.
  218. */
  219. if (typeof document !== "undefined") {
  220. // @ts-ignore
  221. if (typeof attachEvent === "function") {
  222. // @ts-ignore
  223. attachEvent("onunload", unloadHandler);
  224. }
  225. else if (typeof addEventListener === "function") {
  226. const terminationEvent = "onpagehide" in globalThis ? "pagehide" : "unload";
  227. addEventListener(terminationEvent, unloadHandler, false);
  228. }
  229. }
  230. function unloadHandler() {
  231. for (let i in Request.requests) {
  232. if (Request.requests.hasOwnProperty(i)) {
  233. Request.requests[i].abort();
  234. }
  235. }
  236. }
  237. const hasXHR2 = (function () {
  238. const xhr = newRequest({
  239. xdomain: false,
  240. });
  241. return xhr && xhr.responseType !== null;
  242. })();
  243. /**
  244. * HTTP long-polling based on the built-in `XMLHttpRequest` object.
  245. *
  246. * Usage: browser
  247. *
  248. * @see https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
  249. */
  250. export class XHR extends BaseXHR {
  251. constructor(opts) {
  252. super(opts);
  253. const forceBase64 = opts && opts.forceBase64;
  254. this.supportsBinary = hasXHR2 && !forceBase64;
  255. }
  256. request(opts = {}) {
  257. Object.assign(opts, { xd: this.xd }, this.opts);
  258. return new Request(newRequest, this.uri(), opts);
  259. }
  260. }
  261. function newRequest(opts) {
  262. const xdomain = opts.xdomain;
  263. // XMLHttpRequest can be disabled on IE
  264. try {
  265. if ("undefined" !== typeof XMLHttpRequest && (!xdomain || hasCORS)) {
  266. return new XMLHttpRequest();
  267. }
  268. }
  269. catch (e) { }
  270. if (!xdomain) {
  271. try {
  272. return new globalThis[["Active"].concat("Object").join("X")]("Microsoft.XMLHTTP");
  273. }
  274. catch (e) { }
  275. }
  276. }