Headers.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. "use strict";
  2. const conversions = require("webidl-conversions");
  3. const utils = require("./utils.js");
  4. const Function = require("./Function.js");
  5. const newObjectInRealm = utils.newObjectInRealm;
  6. const implSymbol = utils.implSymbol;
  7. const ctorRegistrySymbol = utils.ctorRegistrySymbol;
  8. const interfaceName = "Headers";
  9. exports.is = value => {
  10. return utils.isObject(value) && Object.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
  11. };
  12. exports.isImpl = value => {
  13. return utils.isObject(value) && value instanceof Impl.implementation;
  14. };
  15. exports.convert = (globalObject, value, { context = "The provided value" } = {}) => {
  16. if (exports.is(value)) {
  17. return utils.implForWrapper(value);
  18. }
  19. throw new globalObject.TypeError(`${context} is not of type 'Headers'.`);
  20. };
  21. exports.createDefaultIterator = (globalObject, target, kind) => {
  22. const ctorRegistry = globalObject[ctorRegistrySymbol];
  23. const iteratorPrototype = ctorRegistry["Headers Iterator"];
  24. const iterator = Object.create(iteratorPrototype);
  25. Object.defineProperty(iterator, utils.iterInternalSymbol, {
  26. value: { target, kind, index: 0 },
  27. configurable: true
  28. });
  29. return iterator;
  30. };
  31. function makeWrapper(globalObject, newTarget) {
  32. let proto;
  33. if (newTarget !== undefined) {
  34. proto = newTarget.prototype;
  35. }
  36. if (!utils.isObject(proto)) {
  37. proto = globalObject[ctorRegistrySymbol]["Headers"].prototype;
  38. }
  39. return Object.create(proto);
  40. }
  41. exports.create = (globalObject, constructorArgs, privateData) => {
  42. const wrapper = makeWrapper(globalObject);
  43. return exports.setup(wrapper, globalObject, constructorArgs, privateData);
  44. };
  45. exports.createImpl = (globalObject, constructorArgs, privateData) => {
  46. const wrapper = exports.create(globalObject, constructorArgs, privateData);
  47. return utils.implForWrapper(wrapper);
  48. };
  49. exports._internalSetup = (wrapper, globalObject) => {};
  50. exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
  51. privateData.wrapper = wrapper;
  52. exports._internalSetup(wrapper, globalObject);
  53. Object.defineProperty(wrapper, implSymbol, {
  54. value: new Impl.implementation(globalObject, constructorArgs, privateData),
  55. configurable: true
  56. });
  57. wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
  58. if (Impl.init) {
  59. Impl.init(wrapper[implSymbol]);
  60. }
  61. return wrapper;
  62. };
  63. exports.new = (globalObject, newTarget) => {
  64. const wrapper = makeWrapper(globalObject, newTarget);
  65. exports._internalSetup(wrapper, globalObject);
  66. Object.defineProperty(wrapper, implSymbol, {
  67. value: Object.create(Impl.implementation.prototype),
  68. configurable: true
  69. });
  70. wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
  71. if (Impl.init) {
  72. Impl.init(wrapper[implSymbol]);
  73. }
  74. return wrapper[implSymbol];
  75. };
  76. const exposed = new Set(["Window", "Worker"]);
  77. exports.install = (globalObject, globalNames) => {
  78. if (!globalNames.some(globalName => exposed.has(globalName))) {
  79. return;
  80. }
  81. const ctorRegistry = utils.initCtorRegistry(globalObject);
  82. class Headers {
  83. constructor() {
  84. const args = [];
  85. {
  86. let curArg = arguments[0];
  87. if (curArg !== undefined) {
  88. if (utils.isObject(curArg)) {
  89. if (curArg[Symbol.iterator] !== undefined) {
  90. if (!utils.isObject(curArg)) {
  91. throw new globalObject.TypeError(
  92. "Failed to construct 'Headers': parameter 1" + " sequence" + " is not an iterable object."
  93. );
  94. } else {
  95. const V = [];
  96. const tmp = curArg;
  97. for (let nextItem of tmp) {
  98. if (!utils.isObject(nextItem)) {
  99. throw new globalObject.TypeError(
  100. "Failed to construct 'Headers': parameter 1" +
  101. " sequence" +
  102. "'s element" +
  103. " is not an iterable object."
  104. );
  105. } else {
  106. const V = [];
  107. const tmp = nextItem;
  108. for (let nextItem of tmp) {
  109. nextItem = conversions["ByteString"](nextItem, {
  110. context:
  111. "Failed to construct 'Headers': parameter 1" + " sequence" + "'s element" + "'s element",
  112. globals: globalObject
  113. });
  114. V.push(nextItem);
  115. }
  116. nextItem = V;
  117. }
  118. V.push(nextItem);
  119. }
  120. curArg = V;
  121. }
  122. } else {
  123. if (!utils.isObject(curArg)) {
  124. throw new globalObject.TypeError(
  125. "Failed to construct 'Headers': parameter 1" + " record" + " is not an object."
  126. );
  127. } else {
  128. const result = Object.create(null);
  129. for (const key of Reflect.ownKeys(curArg)) {
  130. const desc = Object.getOwnPropertyDescriptor(curArg, key);
  131. if (desc && desc.enumerable) {
  132. let typedKey = key;
  133. typedKey = conversions["ByteString"](typedKey, {
  134. context: "Failed to construct 'Headers': parameter 1" + " record" + "'s key",
  135. globals: globalObject
  136. });
  137. let typedValue = curArg[key];
  138. typedValue = conversions["ByteString"](typedValue, {
  139. context: "Failed to construct 'Headers': parameter 1" + " record" + "'s value",
  140. globals: globalObject
  141. });
  142. result[typedKey] = typedValue;
  143. }
  144. }
  145. curArg = result;
  146. }
  147. }
  148. } else {
  149. throw new globalObject.TypeError(
  150. "Failed to construct 'Headers': parameter 1" + " is not of any supported type."
  151. );
  152. }
  153. }
  154. args.push(curArg);
  155. }
  156. return exports.setup(Object.create(new.target.prototype), globalObject, args);
  157. }
  158. append(name, value) {
  159. const esValue = this !== null && this !== undefined ? this : globalObject;
  160. if (!exports.is(esValue)) {
  161. throw new globalObject.TypeError("'append' called on an object that is not a valid instance of Headers.");
  162. }
  163. if (arguments.length < 2) {
  164. throw new globalObject.TypeError(
  165. `Failed to execute 'append' on 'Headers': 2 arguments required, but only ${arguments.length} present.`
  166. );
  167. }
  168. const args = [];
  169. {
  170. let curArg = arguments[0];
  171. curArg = conversions["ByteString"](curArg, {
  172. context: "Failed to execute 'append' on 'Headers': parameter 1",
  173. globals: globalObject
  174. });
  175. args.push(curArg);
  176. }
  177. {
  178. let curArg = arguments[1];
  179. curArg = conversions["ByteString"](curArg, {
  180. context: "Failed to execute 'append' on 'Headers': parameter 2",
  181. globals: globalObject
  182. });
  183. args.push(curArg);
  184. }
  185. return esValue[implSymbol].append(...args);
  186. }
  187. delete(name) {
  188. const esValue = this !== null && this !== undefined ? this : globalObject;
  189. if (!exports.is(esValue)) {
  190. throw new globalObject.TypeError("'delete' called on an object that is not a valid instance of Headers.");
  191. }
  192. if (arguments.length < 1) {
  193. throw new globalObject.TypeError(
  194. `Failed to execute 'delete' on 'Headers': 1 argument required, but only ${arguments.length} present.`
  195. );
  196. }
  197. const args = [];
  198. {
  199. let curArg = arguments[0];
  200. curArg = conversions["ByteString"](curArg, {
  201. context: "Failed to execute 'delete' on 'Headers': parameter 1",
  202. globals: globalObject
  203. });
  204. args.push(curArg);
  205. }
  206. return esValue[implSymbol].delete(...args);
  207. }
  208. get(name) {
  209. const esValue = this !== null && this !== undefined ? this : globalObject;
  210. if (!exports.is(esValue)) {
  211. throw new globalObject.TypeError("'get' called on an object that is not a valid instance of Headers.");
  212. }
  213. if (arguments.length < 1) {
  214. throw new globalObject.TypeError(
  215. `Failed to execute 'get' on 'Headers': 1 argument required, but only ${arguments.length} present.`
  216. );
  217. }
  218. const args = [];
  219. {
  220. let curArg = arguments[0];
  221. curArg = conversions["ByteString"](curArg, {
  222. context: "Failed to execute 'get' on 'Headers': parameter 1",
  223. globals: globalObject
  224. });
  225. args.push(curArg);
  226. }
  227. return esValue[implSymbol].get(...args);
  228. }
  229. getSetCookie() {
  230. const esValue = this !== null && this !== undefined ? this : globalObject;
  231. if (!exports.is(esValue)) {
  232. throw new globalObject.TypeError("'getSetCookie' called on an object that is not a valid instance of Headers.");
  233. }
  234. return utils.tryWrapperForImpl(esValue[implSymbol].getSetCookie());
  235. }
  236. has(name) {
  237. const esValue = this !== null && this !== undefined ? this : globalObject;
  238. if (!exports.is(esValue)) {
  239. throw new globalObject.TypeError("'has' called on an object that is not a valid instance of Headers.");
  240. }
  241. if (arguments.length < 1) {
  242. throw new globalObject.TypeError(
  243. `Failed to execute 'has' on 'Headers': 1 argument required, but only ${arguments.length} present.`
  244. );
  245. }
  246. const args = [];
  247. {
  248. let curArg = arguments[0];
  249. curArg = conversions["ByteString"](curArg, {
  250. context: "Failed to execute 'has' on 'Headers': parameter 1",
  251. globals: globalObject
  252. });
  253. args.push(curArg);
  254. }
  255. return esValue[implSymbol].has(...args);
  256. }
  257. set(name, value) {
  258. const esValue = this !== null && this !== undefined ? this : globalObject;
  259. if (!exports.is(esValue)) {
  260. throw new globalObject.TypeError("'set' called on an object that is not a valid instance of Headers.");
  261. }
  262. if (arguments.length < 2) {
  263. throw new globalObject.TypeError(
  264. `Failed to execute 'set' on 'Headers': 2 arguments required, but only ${arguments.length} present.`
  265. );
  266. }
  267. const args = [];
  268. {
  269. let curArg = arguments[0];
  270. curArg = conversions["ByteString"](curArg, {
  271. context: "Failed to execute 'set' on 'Headers': parameter 1",
  272. globals: globalObject
  273. });
  274. args.push(curArg);
  275. }
  276. {
  277. let curArg = arguments[1];
  278. curArg = conversions["ByteString"](curArg, {
  279. context: "Failed to execute 'set' on 'Headers': parameter 2",
  280. globals: globalObject
  281. });
  282. args.push(curArg);
  283. }
  284. return esValue[implSymbol].set(...args);
  285. }
  286. keys() {
  287. if (!exports.is(this)) {
  288. throw new globalObject.TypeError("'keys' called on an object that is not a valid instance of Headers.");
  289. }
  290. return exports.createDefaultIterator(globalObject, this, "key");
  291. }
  292. values() {
  293. if (!exports.is(this)) {
  294. throw new globalObject.TypeError("'values' called on an object that is not a valid instance of Headers.");
  295. }
  296. return exports.createDefaultIterator(globalObject, this, "value");
  297. }
  298. entries() {
  299. if (!exports.is(this)) {
  300. throw new globalObject.TypeError("'entries' called on an object that is not a valid instance of Headers.");
  301. }
  302. return exports.createDefaultIterator(globalObject, this, "key+value");
  303. }
  304. forEach(callback) {
  305. if (!exports.is(this)) {
  306. throw new globalObject.TypeError("'forEach' called on an object that is not a valid instance of Headers.");
  307. }
  308. if (arguments.length < 1) {
  309. throw new globalObject.TypeError(
  310. "Failed to execute 'forEach' on 'iterable': 1 argument required, but only 0 present."
  311. );
  312. }
  313. callback = Function.convert(globalObject, callback, {
  314. context: "Failed to execute 'forEach' on 'iterable': The callback provided as parameter 1"
  315. });
  316. const thisArg = arguments[1];
  317. let pairs = Array.from(this[implSymbol]);
  318. let i = 0;
  319. while (i < pairs.length) {
  320. const [key, value] = pairs[i].map(utils.tryWrapperForImpl);
  321. callback.call(thisArg, value, key, this);
  322. pairs = Array.from(this[implSymbol]);
  323. i++;
  324. }
  325. }
  326. }
  327. Object.defineProperties(Headers.prototype, {
  328. append: { enumerable: true },
  329. delete: { enumerable: true },
  330. get: { enumerable: true },
  331. getSetCookie: { enumerable: true },
  332. has: { enumerable: true },
  333. set: { enumerable: true },
  334. keys: { enumerable: true },
  335. values: { enumerable: true },
  336. entries: { enumerable: true },
  337. forEach: { enumerable: true },
  338. [Symbol.toStringTag]: { value: "Headers", configurable: true },
  339. [Symbol.iterator]: { value: Headers.prototype.entries, configurable: true, writable: true }
  340. });
  341. ctorRegistry[interfaceName] = Headers;
  342. ctorRegistry["Headers Iterator"] = Object.create(ctorRegistry["%IteratorPrototype%"], {
  343. [Symbol.toStringTag]: {
  344. configurable: true,
  345. value: "Headers Iterator"
  346. }
  347. });
  348. utils.define(ctorRegistry["Headers Iterator"], {
  349. next() {
  350. const internal = this && this[utils.iterInternalSymbol];
  351. if (!internal) {
  352. throw new globalObject.TypeError("next() called on a value that is not a Headers iterator object");
  353. }
  354. const { target, kind, index } = internal;
  355. const values = Array.from(target[implSymbol]);
  356. const len = values.length;
  357. if (index >= len) {
  358. return newObjectInRealm(globalObject, { value: undefined, done: true });
  359. }
  360. const pair = values[index];
  361. internal.index = index + 1;
  362. return newObjectInRealm(globalObject, utils.iteratorResult(pair.map(utils.tryWrapperForImpl), kind));
  363. }
  364. });
  365. Object.defineProperty(globalObject, interfaceName, {
  366. configurable: true,
  367. writable: true,
  368. value: Headers
  369. });
  370. };
  371. const Impl = require("../../jsdom/living/fetch/Headers-impl.js");