fetch.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. "use strict";
  2. var __create = Object.create;
  3. var __defProp = Object.defineProperty;
  4. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  5. var __getOwnPropNames = Object.getOwnPropertyNames;
  6. var __getProtoOf = Object.getPrototypeOf;
  7. var __hasOwnProp = Object.prototype.hasOwnProperty;
  8. var __export = (target, all) => {
  9. for (var name in all)
  10. __defProp(target, name, { get: all[name], enumerable: true });
  11. };
  12. var __copyProps = (to, from, except, desc) => {
  13. if (from && typeof from === "object" || typeof from === "function") {
  14. for (let key of __getOwnPropNames(from))
  15. if (!__hasOwnProp.call(to, key) && key !== except)
  16. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  17. }
  18. return to;
  19. };
  20. var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  21. // If the importer is in node compatibility mode or this is not an ESM
  22. // file that has been converted to a CommonJS file using a Babel-
  23. // compatible transform (i.e. "__esModule" has not been set), then set
  24. // "default" to the CommonJS "module.exports" for node compatibility.
  25. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  26. mod
  27. ));
  28. var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
  29. var fetch_exports = {};
  30. __export(fetch_exports, {
  31. APIRequestContext: () => APIRequestContext,
  32. BrowserContextAPIRequestContext: () => BrowserContextAPIRequestContext,
  33. GlobalAPIRequestContext: () => GlobalAPIRequestContext
  34. });
  35. module.exports = __toCommonJS(fetch_exports);
  36. var import_http = __toESM(require("http"));
  37. var import_https = __toESM(require("https"));
  38. var import_stream = require("stream");
  39. var import_tls = require("tls");
  40. var zlib = __toESM(require("zlib"));
  41. var import_utils = require("../utils");
  42. var import_crypto = require("./utils/crypto");
  43. var import_userAgent = require("./utils/userAgent");
  44. var import_browserContext = require("./browserContext");
  45. var import_cookieStore = require("./cookieStore");
  46. var import_formData = require("./formData");
  47. var import_instrumentation = require("./instrumentation");
  48. var import_progress = require("./progress");
  49. var import_socksClientCertificatesInterceptor = require("./socksClientCertificatesInterceptor");
  50. var import_happyEyeballs = require("./utils/happyEyeballs");
  51. var import_tracing = require("./trace/recorder/tracing");
  52. class APIRequestContext extends import_instrumentation.SdkObject {
  53. constructor(parent) {
  54. super(parent, "request-context");
  55. this.fetchResponses = /* @__PURE__ */ new Map();
  56. this.fetchLog = /* @__PURE__ */ new Map();
  57. APIRequestContext.allInstances.add(this);
  58. }
  59. static {
  60. this.Events = {
  61. Dispose: "dispose",
  62. Request: "request",
  63. RequestFinished: "requestfinished"
  64. };
  65. }
  66. static {
  67. this.allInstances = /* @__PURE__ */ new Set();
  68. }
  69. static findResponseBody(guid) {
  70. for (const request of APIRequestContext.allInstances) {
  71. const body = request.fetchResponses.get(guid);
  72. if (body)
  73. return body;
  74. }
  75. return void 0;
  76. }
  77. _disposeImpl() {
  78. APIRequestContext.allInstances.delete(this);
  79. this.fetchResponses.clear();
  80. this.fetchLog.clear();
  81. this.emit(APIRequestContext.Events.Dispose);
  82. }
  83. disposeResponse(fetchUid) {
  84. this.fetchResponses.delete(fetchUid);
  85. this.fetchLog.delete(fetchUid);
  86. }
  87. _storeResponseBody(body) {
  88. const uid = (0, import_crypto.createGuid)();
  89. this.fetchResponses.set(uid, body);
  90. return uid;
  91. }
  92. async fetch(progress, params) {
  93. const defaults = this._defaultOptions();
  94. const headers = {
  95. "user-agent": defaults.userAgent,
  96. "accept": "*/*",
  97. "accept-encoding": "gzip,deflate,br"
  98. };
  99. if (defaults.extraHTTPHeaders) {
  100. for (const { name, value } of defaults.extraHTTPHeaders)
  101. setHeader(headers, name, value);
  102. }
  103. if (params.headers) {
  104. for (const { name, value } of params.headers)
  105. setHeader(headers, name, value);
  106. }
  107. const requestUrl = new URL((0, import_utils.constructURLBasedOnBaseURL)(defaults.baseURL, params.url));
  108. if (params.encodedParams) {
  109. requestUrl.search = params.encodedParams;
  110. } else if (params.params) {
  111. for (const { name, value } of params.params)
  112. requestUrl.searchParams.append(name, value);
  113. }
  114. const credentials = this._getHttpCredentials(requestUrl);
  115. if (credentials?.send === "always")
  116. setBasicAuthorizationHeader(headers, credentials);
  117. const method = params.method?.toUpperCase() || "GET";
  118. const proxy = defaults.proxy;
  119. let agent;
  120. if (proxy?.server !== "per-context")
  121. agent = (0, import_utils.createProxyAgent)(proxy, requestUrl);
  122. let maxRedirects = params.maxRedirects ?? (defaults.maxRedirects ?? 20);
  123. maxRedirects = maxRedirects === 0 ? -1 : maxRedirects;
  124. const options = {
  125. method,
  126. headers,
  127. agent,
  128. maxRedirects,
  129. ...(0, import_socksClientCertificatesInterceptor.getMatchingTLSOptionsForOrigin)(this._defaultOptions().clientCertificates, requestUrl.origin),
  130. __testHookLookup: params.__testHookLookup
  131. };
  132. if (params.ignoreHTTPSErrors || defaults.ignoreHTTPSErrors)
  133. options.rejectUnauthorized = false;
  134. const postData = serializePostData(params, headers);
  135. if (postData)
  136. setHeader(headers, "content-length", String(postData.byteLength));
  137. const fetchResponse = await this._sendRequestWithRetries(progress, requestUrl, options, postData, params.maxRetries);
  138. const fetchUid = this._storeResponseBody(fetchResponse.body);
  139. this.fetchLog.set(fetchUid, progress.metadata.log);
  140. const failOnStatusCode = params.failOnStatusCode !== void 0 ? params.failOnStatusCode : !!defaults.failOnStatusCode;
  141. if (failOnStatusCode && (fetchResponse.status < 200 || fetchResponse.status >= 400)) {
  142. let responseText = "";
  143. if (fetchResponse.body.byteLength) {
  144. let text = fetchResponse.body.toString("utf8");
  145. if (text.length > 1e3)
  146. text = text.substring(0, 997) + "...";
  147. responseText = `
  148. Response text:
  149. ${text}`;
  150. }
  151. throw new Error(`${fetchResponse.status} ${fetchResponse.statusText}${responseText}`);
  152. }
  153. return { ...fetchResponse, fetchUid };
  154. }
  155. _parseSetCookieHeader(responseUrl, setCookie) {
  156. if (!setCookie)
  157. return [];
  158. const url = new URL(responseUrl);
  159. const defaultPath = "/" + url.pathname.substr(1).split("/").slice(0, -1).join("/");
  160. const cookies = [];
  161. for (const header of setCookie) {
  162. const cookie = parseCookie(header);
  163. if (!cookie)
  164. continue;
  165. if (!cookie.domain)
  166. cookie.domain = url.hostname;
  167. else
  168. (0, import_utils.assert)(cookie.domain.startsWith(".") || !cookie.domain.includes("."));
  169. if (!(0, import_cookieStore.domainMatches)(url.hostname, cookie.domain))
  170. continue;
  171. if (!cookie.path || !cookie.path.startsWith("/"))
  172. cookie.path = defaultPath;
  173. cookies.push(cookie);
  174. }
  175. return cookies;
  176. }
  177. async _updateRequestCookieHeader(progress, url, headers) {
  178. if (getHeader(headers, "cookie") !== void 0)
  179. return;
  180. const contextCookies = await progress.race(this._cookies(url));
  181. const cookies = contextCookies.filter((c) => new import_cookieStore.Cookie(c).matches(url));
  182. if (cookies.length) {
  183. const valueArray = cookies.map((c) => `${c.name}=${c.value}`);
  184. setHeader(headers, "cookie", valueArray.join("; "));
  185. }
  186. }
  187. async _sendRequestWithRetries(progress, url, options, postData, maxRetries) {
  188. maxRetries ??= 0;
  189. let backoff = 250;
  190. for (let i = 0; i <= maxRetries; i++) {
  191. try {
  192. return await this._sendRequest(progress, url, options, postData);
  193. } catch (e) {
  194. if ((0, import_progress.isAbortError)(e))
  195. throw e;
  196. e = (0, import_socksClientCertificatesInterceptor.rewriteOpenSSLErrorIfNeeded)(e);
  197. if (maxRetries === 0)
  198. throw e;
  199. if (i === maxRetries)
  200. throw new Error(`Failed after ${i + 1} attempt(s): ${e}`);
  201. if (e.code !== "ECONNRESET")
  202. throw e;
  203. progress.log(` Received ECONNRESET, will retry after ${backoff}ms.`);
  204. await progress.wait(backoff);
  205. backoff *= 2;
  206. }
  207. }
  208. throw new Error("Unreachable");
  209. }
  210. async _sendRequest(progress, url, options, postData) {
  211. await this._updateRequestCookieHeader(progress, url, options.headers);
  212. const requestCookies = getHeader(options.headers, "cookie")?.split(";").map((p) => {
  213. const [name, value] = p.split("=").map((v) => v.trim());
  214. return { name, value };
  215. }) || [];
  216. const requestEvent = {
  217. url,
  218. method: options.method,
  219. headers: options.headers,
  220. cookies: requestCookies,
  221. postData
  222. };
  223. this.emit(APIRequestContext.Events.Request, requestEvent);
  224. let destroyRequest;
  225. const resultPromise = new Promise((fulfill, reject) => {
  226. const requestConstructor = (url.protocol === "https:" ? import_https.default : import_http.default).request;
  227. const agent = options.agent || (url.protocol === "https:" ? import_happyEyeballs.httpsHappyEyeballsAgent : import_happyEyeballs.httpHappyEyeballsAgent);
  228. const requestOptions = { ...options, agent };
  229. const startAt = (0, import_utils.monotonicTime)();
  230. let reusedSocketAt;
  231. let dnsLookupAt;
  232. let tcpConnectionAt;
  233. let tlsHandshakeAt;
  234. let requestFinishAt;
  235. let serverIPAddress;
  236. let serverPort;
  237. let securityDetails;
  238. const listeners = [];
  239. const request = requestConstructor(url, requestOptions, async (response) => {
  240. const responseAt = (0, import_utils.monotonicTime)();
  241. const notifyRequestFinished = (body2) => {
  242. const endAt = (0, import_utils.monotonicTime)();
  243. const connectEnd = tlsHandshakeAt ?? tcpConnectionAt;
  244. const timings = {
  245. send: requestFinishAt - startAt,
  246. wait: responseAt - requestFinishAt,
  247. receive: endAt - responseAt,
  248. dns: dnsLookupAt ? dnsLookupAt - startAt : -1,
  249. connect: connectEnd ? connectEnd - startAt : -1,
  250. // "If [ssl] is defined then the time is also included in the connect field "
  251. ssl: tlsHandshakeAt ? tlsHandshakeAt - tcpConnectionAt : -1,
  252. blocked: reusedSocketAt ? reusedSocketAt - startAt : -1
  253. };
  254. const requestFinishedEvent = {
  255. requestEvent,
  256. httpVersion: response.httpVersion,
  257. statusCode: response.statusCode || 0,
  258. statusMessage: response.statusMessage || "",
  259. headers: response.headers,
  260. rawHeaders: response.rawHeaders,
  261. cookies,
  262. body: body2,
  263. timings,
  264. serverIPAddress,
  265. serverPort,
  266. securityDetails
  267. };
  268. this.emit(APIRequestContext.Events.RequestFinished, requestFinishedEvent);
  269. };
  270. progress.log(`\u2190 ${response.statusCode} ${response.statusMessage}`);
  271. for (const [name, value] of Object.entries(response.headers))
  272. progress.log(` ${name}: ${value}`);
  273. const cookies = this._parseSetCookieHeader(response.url || url.toString(), response.headers["set-cookie"]);
  274. if (cookies.length) {
  275. try {
  276. await this._addCookies(cookies);
  277. } catch (e) {
  278. await Promise.all(cookies.map((c) => this._addCookies([c]).catch(() => {
  279. })));
  280. }
  281. }
  282. if (redirectStatus.includes(response.statusCode) && options.maxRedirects >= 0) {
  283. if (options.maxRedirects === 0) {
  284. reject(new Error("Max redirect count exceeded"));
  285. request.destroy();
  286. return;
  287. }
  288. const headers = { ...options.headers };
  289. removeHeader(headers, `cookie`);
  290. const status = response.statusCode;
  291. let method = options.method;
  292. if ((status === 301 || status === 302) && method === "POST" || status === 303 && !["GET", "HEAD"].includes(method)) {
  293. method = "GET";
  294. postData = void 0;
  295. removeHeader(headers, `content-encoding`);
  296. removeHeader(headers, `content-language`);
  297. removeHeader(headers, `content-length`);
  298. removeHeader(headers, `content-location`);
  299. removeHeader(headers, `content-type`);
  300. }
  301. const redirectOptions = {
  302. method,
  303. headers,
  304. agent: options.agent,
  305. maxRedirects: options.maxRedirects - 1,
  306. ...(0, import_socksClientCertificatesInterceptor.getMatchingTLSOptionsForOrigin)(this._defaultOptions().clientCertificates, url.origin),
  307. __testHookLookup: options.__testHookLookup
  308. };
  309. if (options.rejectUnauthorized === false)
  310. redirectOptions.rejectUnauthorized = false;
  311. const locationHeaderValue = Buffer.from(response.headers.location ?? "", "latin1").toString("utf8");
  312. if (locationHeaderValue) {
  313. let locationURL;
  314. try {
  315. locationURL = new URL(locationHeaderValue, url);
  316. } catch (error) {
  317. reject(new Error(`uri requested responds with an invalid redirect URL: ${locationHeaderValue}`));
  318. request.destroy();
  319. return;
  320. }
  321. if (headers["host"])
  322. headers["host"] = locationURL.host;
  323. notifyRequestFinished();
  324. fulfill(this._sendRequest(progress, locationURL, redirectOptions, postData));
  325. request.destroy();
  326. return;
  327. }
  328. }
  329. if (response.statusCode === 401 && !getHeader(options.headers, "authorization")) {
  330. const auth = response.headers["www-authenticate"];
  331. const credentials = this._getHttpCredentials(url);
  332. if (auth?.trim().startsWith("Basic") && credentials) {
  333. setBasicAuthorizationHeader(options.headers, credentials);
  334. notifyRequestFinished();
  335. fulfill(this._sendRequest(progress, url, options, postData));
  336. request.destroy();
  337. return;
  338. }
  339. }
  340. response.on("aborted", () => reject(new Error("aborted")));
  341. const chunks = [];
  342. const notifyBodyFinished = () => {
  343. const body2 = Buffer.concat(chunks);
  344. notifyRequestFinished(body2);
  345. fulfill({
  346. url: response.url || url.toString(),
  347. status: response.statusCode || 0,
  348. statusText: response.statusMessage || "",
  349. headers: toHeadersArray(response.rawHeaders),
  350. body: body2
  351. });
  352. };
  353. let body = response;
  354. let transform;
  355. const encoding = response.headers["content-encoding"];
  356. if (encoding === "gzip" || encoding === "x-gzip") {
  357. transform = zlib.createGunzip({
  358. flush: zlib.constants.Z_SYNC_FLUSH,
  359. finishFlush: zlib.constants.Z_SYNC_FLUSH
  360. });
  361. } else if (encoding === "br") {
  362. transform = zlib.createBrotliDecompress({
  363. flush: zlib.constants.BROTLI_OPERATION_FLUSH,
  364. finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH
  365. });
  366. } else if (encoding === "deflate") {
  367. transform = zlib.createInflate();
  368. }
  369. if (transform) {
  370. const emptyStreamTransform = new SafeEmptyStreamTransform(notifyBodyFinished);
  371. body = (0, import_stream.pipeline)(response, emptyStreamTransform, transform, (e) => {
  372. if (e)
  373. reject(new Error(`failed to decompress '${encoding}' encoding: ${e.message}`));
  374. });
  375. body.on("error", (e) => reject(new Error(`failed to decompress '${encoding}' encoding: ${e}`)));
  376. } else {
  377. body.on("error", reject);
  378. }
  379. body.on("data", (chunk) => chunks.push(chunk));
  380. body.on("end", notifyBodyFinished);
  381. });
  382. request.on("error", reject);
  383. destroyRequest = () => request.destroy();
  384. listeners.push(
  385. import_utils.eventsHelper.addEventListener(this, APIRequestContext.Events.Dispose, () => {
  386. reject(new Error("Request context disposed."));
  387. request.destroy();
  388. })
  389. );
  390. request.on("close", () => import_utils.eventsHelper.removeEventListeners(listeners));
  391. request.on("socket", (socket) => {
  392. if (request.reusedSocket) {
  393. reusedSocketAt = (0, import_utils.monotonicTime)();
  394. return;
  395. }
  396. const happyEyeBallsTimings = (0, import_happyEyeballs.timingForSocket)(socket);
  397. dnsLookupAt = happyEyeBallsTimings.dnsLookupAt;
  398. tcpConnectionAt = happyEyeBallsTimings.tcpConnectionAt;
  399. listeners.push(
  400. import_utils.eventsHelper.addEventListener(socket, "lookup", () => {
  401. dnsLookupAt = (0, import_utils.monotonicTime)();
  402. }),
  403. import_utils.eventsHelper.addEventListener(socket, "connect", () => {
  404. tcpConnectionAt = (0, import_utils.monotonicTime)();
  405. }),
  406. import_utils.eventsHelper.addEventListener(socket, "secureConnect", () => {
  407. tlsHandshakeAt = (0, import_utils.monotonicTime)();
  408. if (socket instanceof import_tls.TLSSocket) {
  409. const peerCertificate = socket.getPeerCertificate();
  410. securityDetails = {
  411. protocol: socket.getProtocol() ?? void 0,
  412. subjectName: peerCertificate.subject.CN,
  413. validFrom: new Date(peerCertificate.valid_from).getTime() / 1e3,
  414. validTo: new Date(peerCertificate.valid_to).getTime() / 1e3,
  415. issuer: peerCertificate.issuer.CN
  416. };
  417. }
  418. })
  419. );
  420. serverIPAddress = socket.remoteAddress;
  421. serverPort = socket.remotePort;
  422. });
  423. request.on("finish", () => {
  424. requestFinishAt = (0, import_utils.monotonicTime)();
  425. });
  426. progress.log(`\u2192 ${options.method} ${url.toString()}`);
  427. if (options.headers) {
  428. for (const [name, value] of Object.entries(options.headers))
  429. progress.log(` ${name}: ${value}`);
  430. }
  431. if (postData)
  432. request.write(postData);
  433. request.end();
  434. });
  435. return progress.race(resultPromise).catch((error) => {
  436. destroyRequest?.();
  437. throw error;
  438. });
  439. }
  440. _getHttpCredentials(url) {
  441. if (!this._defaultOptions().httpCredentials?.origin || url.origin.toLowerCase() === this._defaultOptions().httpCredentials?.origin?.toLowerCase())
  442. return this._defaultOptions().httpCredentials;
  443. return void 0;
  444. }
  445. }
  446. class SafeEmptyStreamTransform extends import_stream.Transform {
  447. constructor(onEmptyStreamCallback) {
  448. super();
  449. this._receivedSomeData = false;
  450. this._onEmptyStreamCallback = onEmptyStreamCallback;
  451. }
  452. _transform(chunk, encoding, callback) {
  453. this._receivedSomeData = true;
  454. callback(null, chunk);
  455. }
  456. _flush(callback) {
  457. if (this._receivedSomeData)
  458. callback(null);
  459. else
  460. this._onEmptyStreamCallback();
  461. }
  462. }
  463. class BrowserContextAPIRequestContext extends APIRequestContext {
  464. constructor(context) {
  465. super(context);
  466. this._context = context;
  467. context.once(import_browserContext.BrowserContext.Events.Close, () => this._disposeImpl());
  468. }
  469. tracing() {
  470. return this._context.tracing;
  471. }
  472. async dispose(options) {
  473. this._closeReason = options.reason;
  474. this.fetchResponses.clear();
  475. }
  476. _defaultOptions() {
  477. return {
  478. userAgent: this._context._options.userAgent || this._context._browser.userAgent(),
  479. extraHTTPHeaders: this._context._options.extraHTTPHeaders,
  480. failOnStatusCode: void 0,
  481. httpCredentials: this._context._options.httpCredentials,
  482. proxy: this._context._options.proxy || this._context._browser.options.proxy,
  483. ignoreHTTPSErrors: this._context._options.ignoreHTTPSErrors,
  484. baseURL: this._context._options.baseURL,
  485. clientCertificates: this._context._options.clientCertificates
  486. };
  487. }
  488. async _addCookies(cookies) {
  489. await this._context.addCookies(cookies);
  490. }
  491. async _cookies(url) {
  492. return await this._context.cookies(url.toString());
  493. }
  494. async storageState(progress, indexedDB) {
  495. return this._context.storageState(progress, indexedDB);
  496. }
  497. }
  498. class GlobalAPIRequestContext extends APIRequestContext {
  499. constructor(playwright, options) {
  500. super(playwright);
  501. this._cookieStore = new import_cookieStore.CookieStore();
  502. this.attribution.context = this;
  503. if (options.storageState) {
  504. this._origins = options.storageState.origins?.map((origin) => ({ indexedDB: [], ...origin }));
  505. this._cookieStore.addCookies(options.storageState.cookies || []);
  506. }
  507. (0, import_browserContext.verifyClientCertificates)(options.clientCertificates);
  508. this._options = {
  509. baseURL: options.baseURL,
  510. userAgent: options.userAgent || (0, import_userAgent.getUserAgent)(),
  511. extraHTTPHeaders: options.extraHTTPHeaders,
  512. failOnStatusCode: !!options.failOnStatusCode,
  513. ignoreHTTPSErrors: !!options.ignoreHTTPSErrors,
  514. maxRedirects: options.maxRedirects,
  515. httpCredentials: options.httpCredentials,
  516. clientCertificates: options.clientCertificates,
  517. proxy: options.proxy
  518. };
  519. this._tracing = new import_tracing.Tracing(this, options.tracesDir);
  520. }
  521. tracing() {
  522. return this._tracing;
  523. }
  524. async dispose(options) {
  525. this._closeReason = options.reason;
  526. await this._tracing.flush();
  527. await this._tracing.deleteTmpTracesDir();
  528. this._disposeImpl();
  529. }
  530. _defaultOptions() {
  531. return this._options;
  532. }
  533. async _addCookies(cookies) {
  534. this._cookieStore.addCookies(cookies);
  535. }
  536. async _cookies(url) {
  537. return this._cookieStore.cookies(url);
  538. }
  539. async storageState(progress, indexedDB = false) {
  540. return {
  541. cookies: this._cookieStore.allCookies(),
  542. origins: (this._origins || []).map((origin) => ({ ...origin, indexedDB: indexedDB ? origin.indexedDB : [] }))
  543. };
  544. }
  545. }
  546. function toHeadersArray(rawHeaders) {
  547. const result = [];
  548. for (let i = 0; i < rawHeaders.length; i += 2)
  549. result.push({ name: rawHeaders[i], value: rawHeaders[i + 1] });
  550. return result;
  551. }
  552. const redirectStatus = [301, 302, 303, 307, 308];
  553. function parseCookie(header) {
  554. const raw = (0, import_cookieStore.parseRawCookie)(header);
  555. if (!raw)
  556. return null;
  557. const cookie = {
  558. domain: "",
  559. path: "",
  560. expires: -1,
  561. httpOnly: false,
  562. secure: false,
  563. // From https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
  564. // The cookie-sending behavior if SameSite is not specified is SameSite=Lax.
  565. sameSite: "Lax",
  566. ...raw
  567. };
  568. return cookie;
  569. }
  570. function serializePostData(params, headers) {
  571. (0, import_utils.assert)((params.postData ? 1 : 0) + (params.jsonData ? 1 : 0) + (params.formData ? 1 : 0) + (params.multipartData ? 1 : 0) <= 1, `Only one of 'data', 'form' or 'multipart' can be specified`);
  572. if (params.jsonData !== void 0) {
  573. setHeader(headers, "content-type", "application/json", true);
  574. return Buffer.from(params.jsonData, "utf8");
  575. } else if (params.formData) {
  576. const searchParams = new URLSearchParams();
  577. for (const { name, value } of params.formData)
  578. searchParams.append(name, value);
  579. setHeader(headers, "content-type", "application/x-www-form-urlencoded", true);
  580. return Buffer.from(searchParams.toString(), "utf8");
  581. } else if (params.multipartData) {
  582. const formData = new import_formData.MultipartFormData();
  583. for (const field of params.multipartData) {
  584. if (field.file)
  585. formData.addFileField(field.name, field.file);
  586. else if (field.value)
  587. formData.addField(field.name, field.value);
  588. }
  589. setHeader(headers, "content-type", formData.contentTypeHeader(), true);
  590. return formData.finish();
  591. } else if (params.postData !== void 0) {
  592. setHeader(headers, "content-type", "application/octet-stream", true);
  593. return params.postData;
  594. }
  595. return void 0;
  596. }
  597. function setHeader(headers, name, value, keepExisting = false) {
  598. const existing = Object.entries(headers).find((pair) => pair[0].toLowerCase() === name.toLowerCase());
  599. if (!existing)
  600. headers[name] = value;
  601. else if (!keepExisting)
  602. headers[existing[0]] = value;
  603. }
  604. function getHeader(headers, name) {
  605. const existing = Object.entries(headers).find((pair) => pair[0].toLowerCase() === name.toLowerCase());
  606. return existing ? existing[1] : void 0;
  607. }
  608. function removeHeader(headers, name) {
  609. delete headers[name];
  610. }
  611. function setBasicAuthorizationHeader(headers, credentials) {
  612. const { username, password } = credentials;
  613. const encoded = Buffer.from(`${username || ""}:${password || ""}`).toString("base64");
  614. setHeader(headers, "authorization", `Basic ${encoded}`);
  615. }
  616. // Annotate the CommonJS export names for ESM import in node:
  617. 0 && (module.exports = {
  618. APIRequestContext,
  619. BrowserContextAPIRequestContext,
  620. GlobalAPIRequestContext
  621. });