XMLHttpRequest.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. "use strict";
  2. const conversions = require("webidl-conversions");
  3. const utils = require("./utils.js");
  4. const Document = require("./Document.js");
  5. const Blob = require("./Blob.js");
  6. const FormData = require("./FormData.js");
  7. const EventHandlerNonNull = require("./EventHandlerNonNull.js");
  8. const XMLHttpRequestResponseType = require("./XMLHttpRequestResponseType.js");
  9. const implSymbol = utils.implSymbol;
  10. const ctorRegistrySymbol = utils.ctorRegistrySymbol;
  11. const XMLHttpRequestEventTarget = require("./XMLHttpRequestEventTarget.js");
  12. const interfaceName = "XMLHttpRequest";
  13. exports.is = value => {
  14. return utils.isObject(value) && Object.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
  15. };
  16. exports.isImpl = value => {
  17. return utils.isObject(value) && value instanceof Impl.implementation;
  18. };
  19. exports.convert = (globalObject, value, { context = "The provided value" } = {}) => {
  20. if (exports.is(value)) {
  21. return utils.implForWrapper(value);
  22. }
  23. throw new globalObject.TypeError(`${context} is not of type 'XMLHttpRequest'.`);
  24. };
  25. function makeWrapper(globalObject, newTarget) {
  26. let proto;
  27. if (newTarget !== undefined) {
  28. proto = newTarget.prototype;
  29. }
  30. if (!utils.isObject(proto)) {
  31. proto = globalObject[ctorRegistrySymbol]["XMLHttpRequest"].prototype;
  32. }
  33. return Object.create(proto);
  34. }
  35. exports.create = (globalObject, constructorArgs, privateData) => {
  36. const wrapper = makeWrapper(globalObject);
  37. return exports.setup(wrapper, globalObject, constructorArgs, privateData);
  38. };
  39. exports.createImpl = (globalObject, constructorArgs, privateData) => {
  40. const wrapper = exports.create(globalObject, constructorArgs, privateData);
  41. return utils.implForWrapper(wrapper);
  42. };
  43. exports._internalSetup = (wrapper, globalObject) => {
  44. XMLHttpRequestEventTarget._internalSetup(wrapper, globalObject);
  45. };
  46. exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
  47. privateData.wrapper = wrapper;
  48. exports._internalSetup(wrapper, globalObject);
  49. Object.defineProperty(wrapper, implSymbol, {
  50. value: new Impl.implementation(globalObject, constructorArgs, privateData),
  51. configurable: true
  52. });
  53. wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
  54. if (Impl.init) {
  55. Impl.init(wrapper[implSymbol]);
  56. }
  57. return wrapper;
  58. };
  59. exports.new = (globalObject, newTarget) => {
  60. const wrapper = makeWrapper(globalObject, newTarget);
  61. exports._internalSetup(wrapper, globalObject);
  62. Object.defineProperty(wrapper, implSymbol, {
  63. value: Object.create(Impl.implementation.prototype),
  64. configurable: true
  65. });
  66. wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
  67. if (Impl.init) {
  68. Impl.init(wrapper[implSymbol]);
  69. }
  70. return wrapper[implSymbol];
  71. };
  72. const exposed = new Set(["Window", "DedicatedWorker", "SharedWorker"]);
  73. exports.install = (globalObject, globalNames) => {
  74. if (!globalNames.some(globalName => exposed.has(globalName))) {
  75. return;
  76. }
  77. const ctorRegistry = utils.initCtorRegistry(globalObject);
  78. class XMLHttpRequest extends globalObject.XMLHttpRequestEventTarget {
  79. constructor() {
  80. return exports.setup(Object.create(new.target.prototype), globalObject, undefined);
  81. }
  82. open(method, url) {
  83. const esValue = this !== null && this !== undefined ? this : globalObject;
  84. if (!exports.is(esValue)) {
  85. throw new globalObject.TypeError("'open' called on an object that is not a valid instance of XMLHttpRequest.");
  86. }
  87. if (arguments.length < 2) {
  88. throw new globalObject.TypeError(
  89. `Failed to execute 'open' on 'XMLHttpRequest': 2 arguments required, but only ${arguments.length} present.`
  90. );
  91. }
  92. const args = [];
  93. switch (arguments.length) {
  94. case 2:
  95. {
  96. let curArg = arguments[0];
  97. curArg = conversions["ByteString"](curArg, {
  98. context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 1",
  99. globals: globalObject
  100. });
  101. args.push(curArg);
  102. }
  103. {
  104. let curArg = arguments[1];
  105. curArg = conversions["USVString"](curArg, {
  106. context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 2",
  107. globals: globalObject
  108. });
  109. args.push(curArg);
  110. }
  111. break;
  112. case 3:
  113. {
  114. let curArg = arguments[0];
  115. curArg = conversions["ByteString"](curArg, {
  116. context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 1",
  117. globals: globalObject
  118. });
  119. args.push(curArg);
  120. }
  121. {
  122. let curArg = arguments[1];
  123. curArg = conversions["USVString"](curArg, {
  124. context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 2",
  125. globals: globalObject
  126. });
  127. args.push(curArg);
  128. }
  129. {
  130. let curArg = arguments[2];
  131. curArg = conversions["boolean"](curArg, {
  132. context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 3",
  133. globals: globalObject
  134. });
  135. args.push(curArg);
  136. }
  137. break;
  138. case 4:
  139. {
  140. let curArg = arguments[0];
  141. curArg = conversions["ByteString"](curArg, {
  142. context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 1",
  143. globals: globalObject
  144. });
  145. args.push(curArg);
  146. }
  147. {
  148. let curArg = arguments[1];
  149. curArg = conversions["USVString"](curArg, {
  150. context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 2",
  151. globals: globalObject
  152. });
  153. args.push(curArg);
  154. }
  155. {
  156. let curArg = arguments[2];
  157. curArg = conversions["boolean"](curArg, {
  158. context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 3",
  159. globals: globalObject
  160. });
  161. args.push(curArg);
  162. }
  163. {
  164. let curArg = arguments[3];
  165. if (curArg !== undefined) {
  166. if (curArg === null || curArg === undefined) {
  167. curArg = null;
  168. } else {
  169. curArg = conversions["USVString"](curArg, {
  170. context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 4",
  171. globals: globalObject
  172. });
  173. }
  174. } else {
  175. curArg = null;
  176. }
  177. args.push(curArg);
  178. }
  179. break;
  180. default:
  181. {
  182. let curArg = arguments[0];
  183. curArg = conversions["ByteString"](curArg, {
  184. context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 1",
  185. globals: globalObject
  186. });
  187. args.push(curArg);
  188. }
  189. {
  190. let curArg = arguments[1];
  191. curArg = conversions["USVString"](curArg, {
  192. context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 2",
  193. globals: globalObject
  194. });
  195. args.push(curArg);
  196. }
  197. {
  198. let curArg = arguments[2];
  199. curArg = conversions["boolean"](curArg, {
  200. context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 3",
  201. globals: globalObject
  202. });
  203. args.push(curArg);
  204. }
  205. {
  206. let curArg = arguments[3];
  207. if (curArg !== undefined) {
  208. if (curArg === null || curArg === undefined) {
  209. curArg = null;
  210. } else {
  211. curArg = conversions["USVString"](curArg, {
  212. context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 4",
  213. globals: globalObject
  214. });
  215. }
  216. } else {
  217. curArg = null;
  218. }
  219. args.push(curArg);
  220. }
  221. {
  222. let curArg = arguments[4];
  223. if (curArg !== undefined) {
  224. if (curArg === null || curArg === undefined) {
  225. curArg = null;
  226. } else {
  227. curArg = conversions["USVString"](curArg, {
  228. context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 5",
  229. globals: globalObject
  230. });
  231. }
  232. } else {
  233. curArg = null;
  234. }
  235. args.push(curArg);
  236. }
  237. }
  238. return esValue[implSymbol].open(...args);
  239. }
  240. setRequestHeader(name, value) {
  241. const esValue = this !== null && this !== undefined ? this : globalObject;
  242. if (!exports.is(esValue)) {
  243. throw new globalObject.TypeError(
  244. "'setRequestHeader' called on an object that is not a valid instance of XMLHttpRequest."
  245. );
  246. }
  247. if (arguments.length < 2) {
  248. throw new globalObject.TypeError(
  249. `Failed to execute 'setRequestHeader' on 'XMLHttpRequest': 2 arguments required, but only ${arguments.length} present.`
  250. );
  251. }
  252. const args = [];
  253. {
  254. let curArg = arguments[0];
  255. curArg = conversions["ByteString"](curArg, {
  256. context: "Failed to execute 'setRequestHeader' on 'XMLHttpRequest': parameter 1",
  257. globals: globalObject
  258. });
  259. args.push(curArg);
  260. }
  261. {
  262. let curArg = arguments[1];
  263. curArg = conversions["ByteString"](curArg, {
  264. context: "Failed to execute 'setRequestHeader' on 'XMLHttpRequest': parameter 2",
  265. globals: globalObject
  266. });
  267. args.push(curArg);
  268. }
  269. return esValue[implSymbol].setRequestHeader(...args);
  270. }
  271. send() {
  272. const esValue = this !== null && this !== undefined ? this : globalObject;
  273. if (!exports.is(esValue)) {
  274. throw new globalObject.TypeError("'send' called on an object that is not a valid instance of XMLHttpRequest.");
  275. }
  276. const args = [];
  277. {
  278. let curArg = arguments[0];
  279. if (curArg !== undefined) {
  280. if (curArg === null || curArg === undefined) {
  281. curArg = null;
  282. } else {
  283. if (Document.is(curArg) || Blob.is(curArg) || FormData.is(curArg)) {
  284. curArg = utils.implForWrapper(curArg);
  285. } else if (utils.isArrayBuffer(curArg)) {
  286. curArg = conversions["ArrayBuffer"](curArg, {
  287. context: "Failed to execute 'send' on 'XMLHttpRequest': parameter 1",
  288. globals: globalObject
  289. });
  290. } else if (ArrayBuffer.isView(curArg)) {
  291. curArg = conversions["ArrayBufferView"](curArg, {
  292. context: "Failed to execute 'send' on 'XMLHttpRequest': parameter 1",
  293. globals: globalObject
  294. });
  295. } else {
  296. curArg = conversions["USVString"](curArg, {
  297. context: "Failed to execute 'send' on 'XMLHttpRequest': parameter 1",
  298. globals: globalObject
  299. });
  300. }
  301. }
  302. } else {
  303. curArg = null;
  304. }
  305. args.push(curArg);
  306. }
  307. return esValue[implSymbol].send(...args);
  308. }
  309. abort() {
  310. const esValue = this !== null && this !== undefined ? this : globalObject;
  311. if (!exports.is(esValue)) {
  312. throw new globalObject.TypeError("'abort' called on an object that is not a valid instance of XMLHttpRequest.");
  313. }
  314. return esValue[implSymbol].abort();
  315. }
  316. getResponseHeader(name) {
  317. const esValue = this !== null && this !== undefined ? this : globalObject;
  318. if (!exports.is(esValue)) {
  319. throw new globalObject.TypeError(
  320. "'getResponseHeader' called on an object that is not a valid instance of XMLHttpRequest."
  321. );
  322. }
  323. if (arguments.length < 1) {
  324. throw new globalObject.TypeError(
  325. `Failed to execute 'getResponseHeader' on 'XMLHttpRequest': 1 argument required, but only ${arguments.length} present.`
  326. );
  327. }
  328. const args = [];
  329. {
  330. let curArg = arguments[0];
  331. curArg = conversions["ByteString"](curArg, {
  332. context: "Failed to execute 'getResponseHeader' on 'XMLHttpRequest': parameter 1",
  333. globals: globalObject
  334. });
  335. args.push(curArg);
  336. }
  337. return esValue[implSymbol].getResponseHeader(...args);
  338. }
  339. getAllResponseHeaders() {
  340. const esValue = this !== null && this !== undefined ? this : globalObject;
  341. if (!exports.is(esValue)) {
  342. throw new globalObject.TypeError(
  343. "'getAllResponseHeaders' called on an object that is not a valid instance of XMLHttpRequest."
  344. );
  345. }
  346. return esValue[implSymbol].getAllResponseHeaders();
  347. }
  348. overrideMimeType(mime) {
  349. const esValue = this !== null && this !== undefined ? this : globalObject;
  350. if (!exports.is(esValue)) {
  351. throw new globalObject.TypeError(
  352. "'overrideMimeType' called on an object that is not a valid instance of XMLHttpRequest."
  353. );
  354. }
  355. if (arguments.length < 1) {
  356. throw new globalObject.TypeError(
  357. `Failed to execute 'overrideMimeType' on 'XMLHttpRequest': 1 argument required, but only ${arguments.length} present.`
  358. );
  359. }
  360. const args = [];
  361. {
  362. let curArg = arguments[0];
  363. curArg = conversions["DOMString"](curArg, {
  364. context: "Failed to execute 'overrideMimeType' on 'XMLHttpRequest': parameter 1",
  365. globals: globalObject
  366. });
  367. args.push(curArg);
  368. }
  369. return esValue[implSymbol].overrideMimeType(...args);
  370. }
  371. get onreadystatechange() {
  372. const esValue = this !== null && this !== undefined ? this : globalObject;
  373. if (!exports.is(esValue)) {
  374. throw new globalObject.TypeError(
  375. "'get onreadystatechange' called on an object that is not a valid instance of XMLHttpRequest."
  376. );
  377. }
  378. return utils.tryWrapperForImpl(esValue[implSymbol]["onreadystatechange"]);
  379. }
  380. set onreadystatechange(V) {
  381. const esValue = this !== null && this !== undefined ? this : globalObject;
  382. if (!exports.is(esValue)) {
  383. throw new globalObject.TypeError(
  384. "'set onreadystatechange' called on an object that is not a valid instance of XMLHttpRequest."
  385. );
  386. }
  387. if (!utils.isObject(V)) {
  388. V = null;
  389. } else {
  390. V = EventHandlerNonNull.convert(globalObject, V, {
  391. context: "Failed to set the 'onreadystatechange' property on 'XMLHttpRequest': The provided value"
  392. });
  393. }
  394. esValue[implSymbol]["onreadystatechange"] = V;
  395. }
  396. get readyState() {
  397. const esValue = this !== null && this !== undefined ? this : globalObject;
  398. if (!exports.is(esValue)) {
  399. throw new globalObject.TypeError(
  400. "'get readyState' called on an object that is not a valid instance of XMLHttpRequest."
  401. );
  402. }
  403. return esValue[implSymbol]["readyState"];
  404. }
  405. get timeout() {
  406. const esValue = this !== null && this !== undefined ? this : globalObject;
  407. if (!exports.is(esValue)) {
  408. throw new globalObject.TypeError(
  409. "'get timeout' called on an object that is not a valid instance of XMLHttpRequest."
  410. );
  411. }
  412. return esValue[implSymbol]["timeout"];
  413. }
  414. set timeout(V) {
  415. const esValue = this !== null && this !== undefined ? this : globalObject;
  416. if (!exports.is(esValue)) {
  417. throw new globalObject.TypeError(
  418. "'set timeout' called on an object that is not a valid instance of XMLHttpRequest."
  419. );
  420. }
  421. V = conversions["unsigned long"](V, {
  422. context: "Failed to set the 'timeout' property on 'XMLHttpRequest': The provided value",
  423. globals: globalObject
  424. });
  425. esValue[implSymbol]["timeout"] = V;
  426. }
  427. get withCredentials() {
  428. const esValue = this !== null && this !== undefined ? this : globalObject;
  429. if (!exports.is(esValue)) {
  430. throw new globalObject.TypeError(
  431. "'get withCredentials' called on an object that is not a valid instance of XMLHttpRequest."
  432. );
  433. }
  434. return esValue[implSymbol]["withCredentials"];
  435. }
  436. set withCredentials(V) {
  437. const esValue = this !== null && this !== undefined ? this : globalObject;
  438. if (!exports.is(esValue)) {
  439. throw new globalObject.TypeError(
  440. "'set withCredentials' called on an object that is not a valid instance of XMLHttpRequest."
  441. );
  442. }
  443. V = conversions["boolean"](V, {
  444. context: "Failed to set the 'withCredentials' property on 'XMLHttpRequest': The provided value",
  445. globals: globalObject
  446. });
  447. esValue[implSymbol]["withCredentials"] = V;
  448. }
  449. get upload() {
  450. const esValue = this !== null && this !== undefined ? this : globalObject;
  451. if (!exports.is(esValue)) {
  452. throw new globalObject.TypeError(
  453. "'get upload' called on an object that is not a valid instance of XMLHttpRequest."
  454. );
  455. }
  456. return utils.getSameObject(this, "upload", () => {
  457. return utils.tryWrapperForImpl(esValue[implSymbol]["upload"]);
  458. });
  459. }
  460. get responseURL() {
  461. const esValue = this !== null && this !== undefined ? this : globalObject;
  462. if (!exports.is(esValue)) {
  463. throw new globalObject.TypeError(
  464. "'get responseURL' called on an object that is not a valid instance of XMLHttpRequest."
  465. );
  466. }
  467. return esValue[implSymbol]["responseURL"];
  468. }
  469. get status() {
  470. const esValue = this !== null && this !== undefined ? this : globalObject;
  471. if (!exports.is(esValue)) {
  472. throw new globalObject.TypeError(
  473. "'get status' called on an object that is not a valid instance of XMLHttpRequest."
  474. );
  475. }
  476. return esValue[implSymbol]["status"];
  477. }
  478. get statusText() {
  479. const esValue = this !== null && this !== undefined ? this : globalObject;
  480. if (!exports.is(esValue)) {
  481. throw new globalObject.TypeError(
  482. "'get statusText' called on an object that is not a valid instance of XMLHttpRequest."
  483. );
  484. }
  485. return esValue[implSymbol]["statusText"];
  486. }
  487. get responseType() {
  488. const esValue = this !== null && this !== undefined ? this : globalObject;
  489. if (!exports.is(esValue)) {
  490. throw new globalObject.TypeError(
  491. "'get responseType' called on an object that is not a valid instance of XMLHttpRequest."
  492. );
  493. }
  494. return utils.tryWrapperForImpl(esValue[implSymbol]["responseType"]);
  495. }
  496. set responseType(V) {
  497. const esValue = this !== null && this !== undefined ? this : globalObject;
  498. if (!exports.is(esValue)) {
  499. throw new globalObject.TypeError(
  500. "'set responseType' called on an object that is not a valid instance of XMLHttpRequest."
  501. );
  502. }
  503. V = `${V}`;
  504. if (!XMLHttpRequestResponseType.enumerationValues.has(V)) {
  505. return;
  506. }
  507. esValue[implSymbol]["responseType"] = V;
  508. }
  509. get response() {
  510. const esValue = this !== null && this !== undefined ? this : globalObject;
  511. if (!exports.is(esValue)) {
  512. throw new globalObject.TypeError(
  513. "'get response' called on an object that is not a valid instance of XMLHttpRequest."
  514. );
  515. }
  516. return esValue[implSymbol]["response"];
  517. }
  518. get responseText() {
  519. const esValue = this !== null && this !== undefined ? this : globalObject;
  520. if (!exports.is(esValue)) {
  521. throw new globalObject.TypeError(
  522. "'get responseText' called on an object that is not a valid instance of XMLHttpRequest."
  523. );
  524. }
  525. return esValue[implSymbol]["responseText"];
  526. }
  527. get responseXML() {
  528. const esValue = this !== null && this !== undefined ? this : globalObject;
  529. if (!exports.is(esValue)) {
  530. throw new globalObject.TypeError(
  531. "'get responseXML' called on an object that is not a valid instance of XMLHttpRequest."
  532. );
  533. }
  534. return utils.tryWrapperForImpl(esValue[implSymbol]["responseXML"]);
  535. }
  536. }
  537. Object.defineProperties(XMLHttpRequest.prototype, {
  538. open: { enumerable: true },
  539. setRequestHeader: { enumerable: true },
  540. send: { enumerable: true },
  541. abort: { enumerable: true },
  542. getResponseHeader: { enumerable: true },
  543. getAllResponseHeaders: { enumerable: true },
  544. overrideMimeType: { enumerable: true },
  545. onreadystatechange: { enumerable: true },
  546. readyState: { enumerable: true },
  547. timeout: { enumerable: true },
  548. withCredentials: { enumerable: true },
  549. upload: { enumerable: true },
  550. responseURL: { enumerable: true },
  551. status: { enumerable: true },
  552. statusText: { enumerable: true },
  553. responseType: { enumerable: true },
  554. response: { enumerable: true },
  555. responseText: { enumerable: true },
  556. responseXML: { enumerable: true },
  557. [Symbol.toStringTag]: { value: "XMLHttpRequest", configurable: true },
  558. UNSENT: { value: 0, enumerable: true },
  559. OPENED: { value: 1, enumerable: true },
  560. HEADERS_RECEIVED: { value: 2, enumerable: true },
  561. LOADING: { value: 3, enumerable: true },
  562. DONE: { value: 4, enumerable: true }
  563. });
  564. Object.defineProperties(XMLHttpRequest, {
  565. UNSENT: { value: 0, enumerable: true },
  566. OPENED: { value: 1, enumerable: true },
  567. HEADERS_RECEIVED: { value: 2, enumerable: true },
  568. LOADING: { value: 3, enumerable: true },
  569. DONE: { value: 4, enumerable: true }
  570. });
  571. ctorRegistry[interfaceName] = XMLHttpRequest;
  572. Object.defineProperty(globalObject, interfaceName, {
  573. configurable: true,
  574. writable: true,
  575. value: XMLHttpRequest
  576. });
  577. };
  578. const Impl = require("../../jsdom/living/xhr/XMLHttpRequest-impl.js");