UNPKG

55.6 kBJavaScriptView Raw
1import process from 'node:process';
2import { promisify, inspect } from 'node:util';
3import { URL, URLSearchParams } from 'node:url';
4import { checkServerIdentity } from 'node:tls';
5// DO NOT use destructuring for `https.request` and `http.request` as it's not compatible with `nock`.
6import http from 'node:http';
7import https from 'node:https';
8import is, { assert } from '@sindresorhus/is';
9import lowercaseKeys from 'lowercase-keys';
10import CacheableLookup from 'cacheable-lookup';
11import http2wrapper from 'http2-wrapper';
12import { isFormDataLike } from 'form-data-encoder';
13import parseLinkHeader from './parse-link-header.js';
14const [major, minor] = process.versions.node.split('.').map(v => Number(v));
15function validateSearchParameters(searchParameters) {
16 // eslint-disable-next-line guard-for-in
17 for (const key in searchParameters) {
18 const value = searchParameters[key];
19 assert.any([is.string, is.number, is.boolean, is.null_, is.undefined], value);
20 }
21}
22const globalCache = new Map();
23let globalDnsCache;
24const getGlobalDnsCache = () => {
25 if (globalDnsCache) {
26 return globalDnsCache;
27 }
28 globalDnsCache = new CacheableLookup();
29 return globalDnsCache;
30};
31const defaultInternals = {
32 request: undefined,
33 agent: {
34 http: undefined,
35 https: undefined,
36 http2: undefined,
37 },
38 h2session: undefined,
39 decompress: true,
40 timeout: {
41 connect: undefined,
42 lookup: undefined,
43 read: undefined,
44 request: undefined,
45 response: undefined,
46 secureConnect: undefined,
47 send: undefined,
48 socket: undefined,
49 },
50 prefixUrl: '',
51 body: undefined,
52 form: undefined,
53 json: undefined,
54 cookieJar: undefined,
55 ignoreInvalidCookies: false,
56 searchParams: undefined,
57 dnsLookup: undefined,
58 dnsCache: undefined,
59 context: {},
60 hooks: {
61 init: [],
62 beforeRequest: [],
63 beforeError: [],
64 beforeRedirect: [],
65 beforeRetry: [],
66 afterResponse: [],
67 },
68 followRedirect: true,
69 maxRedirects: 10,
70 cache: undefined,
71 throwHttpErrors: true,
72 username: '',
73 password: '',
74 http2: false,
75 allowGetBody: false,
76 headers: {
77 'user-agent': 'got (https://github.com/sindresorhus/got)',
78 },
79 methodRewriting: false,
80 dnsLookupIpVersion: undefined,
81 parseJson: JSON.parse,
82 stringifyJson: JSON.stringify,
83 retry: {
84 limit: 2,
85 methods: [
86 'GET',
87 'PUT',
88 'HEAD',
89 'DELETE',
90 'OPTIONS',
91 'TRACE',
92 ],
93 statusCodes: [
94 408,
95 413,
96 429,
97 500,
98 502,
99 503,
100 504,
101 521,
102 522,
103 524,
104 ],
105 errorCodes: [
106 'ETIMEDOUT',
107 'ECONNRESET',
108 'EADDRINUSE',
109 'ECONNREFUSED',
110 'EPIPE',
111 'ENOTFOUND',
112 'ENETUNREACH',
113 'EAI_AGAIN',
114 ],
115 maxRetryAfter: undefined,
116 calculateDelay: ({ computedValue }) => computedValue,
117 backoffLimit: Number.POSITIVE_INFINITY,
118 noise: 100,
119 },
120 localAddress: undefined,
121 method: 'GET',
122 createConnection: undefined,
123 cacheOptions: {
124 shared: undefined,
125 cacheHeuristic: undefined,
126 immutableMinTimeToLive: undefined,
127 ignoreCargoCult: undefined,
128 },
129 https: {
130 alpnProtocols: undefined,
131 rejectUnauthorized: undefined,
132 checkServerIdentity: undefined,
133 certificateAuthority: undefined,
134 key: undefined,
135 certificate: undefined,
136 passphrase: undefined,
137 pfx: undefined,
138 ciphers: undefined,
139 honorCipherOrder: undefined,
140 minVersion: undefined,
141 maxVersion: undefined,
142 signatureAlgorithms: undefined,
143 tlsSessionLifetime: undefined,
144 dhparam: undefined,
145 ecdhCurve: undefined,
146 certificateRevocationLists: undefined,
147 },
148 encoding: undefined,
149 resolveBodyOnly: false,
150 isStream: false,
151 responseType: 'text',
152 url: undefined,
153 pagination: {
154 transform: (response) => {
155 if (response.request.options.responseType === 'json') {
156 return response.body;
157 }
158 return JSON.parse(response.body);
159 },
160 paginate: ({ response }) => {
161 const rawLinkHeader = response.headers.link;
162 if (typeof rawLinkHeader !== 'string' || rawLinkHeader.trim() === '') {
163 return false;
164 }
165 const parsed = parseLinkHeader(rawLinkHeader);
166 const next = parsed.find(entry => entry.parameters.rel === 'next' || entry.parameters.rel === '"next"');
167 if (next) {
168 return {
169 url: new URL(next.reference, response.url),
170 };
171 }
172 return false;
173 },
174 filter: () => true,
175 shouldContinue: () => true,
176 countLimit: Number.POSITIVE_INFINITY,
177 backoff: 0,
178 requestLimit: 10000,
179 stackAllItems: false,
180 },
181 setHost: true,
182 maxHeaderSize: undefined,
183};
184const cloneInternals = (internals) => {
185 const { hooks, retry } = internals;
186 const result = {
187 ...internals,
188 context: { ...internals.context },
189 cacheOptions: { ...internals.cacheOptions },
190 https: { ...internals.https },
191 agent: { ...internals.agent },
192 headers: { ...internals.headers },
193 retry: {
194 ...retry,
195 errorCodes: [...retry.errorCodes],
196 methods: [...retry.methods],
197 statusCodes: [...retry.statusCodes],
198 },
199 timeout: { ...internals.timeout },
200 hooks: {
201 init: [...hooks.init],
202 beforeRequest: [...hooks.beforeRequest],
203 beforeError: [...hooks.beforeError],
204 beforeRedirect: [...hooks.beforeRedirect],
205 beforeRetry: [...hooks.beforeRetry],
206 afterResponse: [...hooks.afterResponse],
207 },
208 searchParams: internals.searchParams ? new URLSearchParams(internals.searchParams) : undefined,
209 pagination: { ...internals.pagination },
210 };
211 if (result.url !== undefined) {
212 result.prefixUrl = '';
213 }
214 return result;
215};
216const cloneRaw = (raw) => {
217 const { hooks, retry } = raw;
218 const result = { ...raw };
219 if (is.object(raw.context)) {
220 result.context = { ...raw.context };
221 }
222 if (is.object(raw.cacheOptions)) {
223 result.cacheOptions = { ...raw.cacheOptions };
224 }
225 if (is.object(raw.https)) {
226 result.https = { ...raw.https };
227 }
228 if (is.object(raw.cacheOptions)) {
229 result.cacheOptions = { ...result.cacheOptions };
230 }
231 if (is.object(raw.agent)) {
232 result.agent = { ...raw.agent };
233 }
234 if (is.object(raw.headers)) {
235 result.headers = { ...raw.headers };
236 }
237 if (is.object(retry)) {
238 result.retry = { ...retry };
239 if (is.array(retry.errorCodes)) {
240 result.retry.errorCodes = [...retry.errorCodes];
241 }
242 if (is.array(retry.methods)) {
243 result.retry.methods = [...retry.methods];
244 }
245 if (is.array(retry.statusCodes)) {
246 result.retry.statusCodes = [...retry.statusCodes];
247 }
248 }
249 if (is.object(raw.timeout)) {
250 result.timeout = { ...raw.timeout };
251 }
252 if (is.object(hooks)) {
253 result.hooks = {
254 ...hooks,
255 };
256 if (is.array(hooks.init)) {
257 result.hooks.init = [...hooks.init];
258 }
259 if (is.array(hooks.beforeRequest)) {
260 result.hooks.beforeRequest = [...hooks.beforeRequest];
261 }
262 if (is.array(hooks.beforeError)) {
263 result.hooks.beforeError = [...hooks.beforeError];
264 }
265 if (is.array(hooks.beforeRedirect)) {
266 result.hooks.beforeRedirect = [...hooks.beforeRedirect];
267 }
268 if (is.array(hooks.beforeRetry)) {
269 result.hooks.beforeRetry = [...hooks.beforeRetry];
270 }
271 if (is.array(hooks.afterResponse)) {
272 result.hooks.afterResponse = [...hooks.afterResponse];
273 }
274 }
275 // TODO: raw.searchParams
276 if (is.object(raw.pagination)) {
277 result.pagination = { ...raw.pagination };
278 }
279 return result;
280};
281const getHttp2TimeoutOption = (internals) => {
282 const delays = [internals.timeout.socket, internals.timeout.connect, internals.timeout.lookup, internals.timeout.request, internals.timeout.secureConnect].filter(delay => typeof delay === 'number');
283 if (delays.length > 0) {
284 return Math.min(...delays);
285 }
286 return undefined;
287};
288const init = (options, withOptions, self) => {
289 const initHooks = options.hooks?.init;
290 if (initHooks) {
291 for (const hook of initHooks) {
292 hook(withOptions, self);
293 }
294 }
295};
296export default class Options {
297 constructor(input, options, defaults) {
298 Object.defineProperty(this, "_unixOptions", {
299 enumerable: true,
300 configurable: true,
301 writable: true,
302 value: void 0
303 });
304 Object.defineProperty(this, "_internals", {
305 enumerable: true,
306 configurable: true,
307 writable: true,
308 value: void 0
309 });
310 Object.defineProperty(this, "_merging", {
311 enumerable: true,
312 configurable: true,
313 writable: true,
314 value: void 0
315 });
316 Object.defineProperty(this, "_init", {
317 enumerable: true,
318 configurable: true,
319 writable: true,
320 value: void 0
321 });
322 assert.any([is.string, is.urlInstance, is.object, is.undefined], input);
323 assert.any([is.object, is.undefined], options);
324 assert.any([is.object, is.undefined], defaults);
325 if (input instanceof Options || options instanceof Options) {
326 throw new TypeError('The defaults must be passed as the third argument');
327 }
328 this._internals = cloneInternals(defaults?._internals ?? defaults ?? defaultInternals);
329 this._init = [...(defaults?._init ?? [])];
330 this._merging = false;
331 this._unixOptions = undefined;
332 // This rule allows `finally` to be considered more important.
333 // Meaning no matter the error thrown in the `try` block,
334 // if `finally` throws then the `finally` error will be thrown.
335 //
336 // Yes, we want this. If we set `url` first, then the `url.searchParams`
337 // would get merged. Instead we set the `searchParams` first, then
338 // `url.searchParams` is overwritten as expected.
339 //
340 /* eslint-disable no-unsafe-finally */
341 try {
342 if (is.plainObject(input)) {
343 try {
344 this.merge(input);
345 this.merge(options);
346 }
347 finally {
348 this.url = input.url;
349 }
350 }
351 else {
352 try {
353 this.merge(options);
354 }
355 finally {
356 if (options?.url !== undefined) {
357 if (input === undefined) {
358 this.url = options.url;
359 }
360 else {
361 throw new TypeError('The `url` option is mutually exclusive with the `input` argument');
362 }
363 }
364 else if (input !== undefined) {
365 this.url = input;
366 }
367 }
368 }
369 }
370 catch (error) {
371 error.options = this;
372 throw error;
373 }
374 /* eslint-enable no-unsafe-finally */
375 }
376 merge(options) {
377 if (!options) {
378 return;
379 }
380 if (options instanceof Options) {
381 for (const init of options._init) {
382 this.merge(init);
383 }
384 return;
385 }
386 options = cloneRaw(options);
387 init(this, options, this);
388 init(options, options, this);
389 this._merging = true;
390 // Always merge `isStream` first
391 if ('isStream' in options) {
392 this.isStream = options.isStream;
393 }
394 try {
395 let push = false;
396 for (const key in options) {
397 // `got.extend()` options
398 if (key === 'mutableDefaults' || key === 'handlers') {
399 continue;
400 }
401 // Never merge `url`
402 if (key === 'url') {
403 continue;
404 }
405 if (!(key in this)) {
406 throw new Error(`Unexpected option: ${key}`);
407 }
408 // @ts-expect-error Type 'unknown' is not assignable to type 'never'.
409 this[key] = options[key];
410 push = true;
411 }
412 if (push) {
413 this._init.push(options);
414 }
415 }
416 finally {
417 this._merging = false;
418 }
419 }
420 /**
421 Custom request function.
422 The main purpose of this is to [support HTTP2 using a wrapper](https://github.com/szmarczak/http2-wrapper).
423
424 @default http.request | https.request
425 */
426 get request() {
427 return this._internals.request;
428 }
429 set request(value) {
430 assert.any([is.function_, is.undefined], value);
431 this._internals.request = value;
432 }
433 /**
434 An object representing `http`, `https` and `http2` keys for [`http.Agent`](https://nodejs.org/api/http.html#http_class_http_agent), [`https.Agent`](https://nodejs.org/api/https.html#https_class_https_agent) and [`http2wrapper.Agent`](https://github.com/szmarczak/http2-wrapper#new-http2agentoptions) instance.
435 This is necessary because a request to one protocol might redirect to another.
436 In such a scenario, Got will switch over to the right protocol agent for you.
437
438 If a key is not present, it will default to a global agent.
439
440 @example
441 ```
442 import got from 'got';
443 import HttpAgent from 'agentkeepalive';
444
445 const {HttpsAgent} = HttpAgent;
446
447 await got('https://sindresorhus.com', {
448 agent: {
449 http: new HttpAgent(),
450 https: new HttpsAgent()
451 }
452 });
453 ```
454 */
455 get agent() {
456 return this._internals.agent;
457 }
458 set agent(value) {
459 assert.plainObject(value);
460 // eslint-disable-next-line guard-for-in
461 for (const key in value) {
462 if (!(key in this._internals.agent)) {
463 throw new TypeError(`Unexpected agent option: ${key}`);
464 }
465 assert.any([is.object, is.undefined], value[key]);
466 }
467 if (this._merging) {
468 Object.assign(this._internals.agent, value);
469 }
470 else {
471 this._internals.agent = { ...value };
472 }
473 }
474 get h2session() {
475 return this._internals.h2session;
476 }
477 set h2session(value) {
478 this._internals.h2session = value;
479 }
480 /**
481 Decompress the response automatically.
482
483 This will set the `accept-encoding` header to `gzip, deflate, br` unless you set it yourself.
484
485 If this is disabled, a compressed response is returned as a `Buffer`.
486 This may be useful if you want to handle decompression yourself or stream the raw compressed data.
487
488 @default true
489 */
490 get decompress() {
491 return this._internals.decompress;
492 }
493 set decompress(value) {
494 assert.boolean(value);
495 this._internals.decompress = value;
496 }
497 /**
498 Milliseconds to wait for the server to end the response before aborting the request with `got.TimeoutError` error (a.k.a. `request` property).
499 By default, there's no timeout.
500
501 This also accepts an `object` with the following fields to constrain the duration of each phase of the request lifecycle:
502
503 - `lookup` starts when a socket is assigned and ends when the hostname has been resolved.
504 Does not apply when using a Unix domain socket.
505 - `connect` starts when `lookup` completes (or when the socket is assigned if lookup does not apply to the request) and ends when the socket is connected.
506 - `secureConnect` starts when `connect` completes and ends when the handshaking process completes (HTTPS only).
507 - `socket` starts when the socket is connected. See [request.setTimeout](https://nodejs.org/api/http.html#http_request_settimeout_timeout_callback).
508 - `response` starts when the request has been written to the socket and ends when the response headers are received.
509 - `send` starts when the socket is connected and ends with the request has been written to the socket.
510 - `request` starts when the request is initiated and ends when the response's end event fires.
511 */
512 get timeout() {
513 // We always return `Delays` here.
514 // It has to be `Delays | number`, otherwise TypeScript will error because the getter and the setter have incompatible types.
515 return this._internals.timeout;
516 }
517 set timeout(value) {
518 assert.plainObject(value);
519 // eslint-disable-next-line guard-for-in
520 for (const key in value) {
521 if (!(key in this._internals.timeout)) {
522 throw new Error(`Unexpected timeout option: ${key}`);
523 }
524 assert.any([is.number, is.undefined], value[key]);
525 }
526 if (this._merging) {
527 Object.assign(this._internals.timeout, value);
528 }
529 else {
530 this._internals.timeout = { ...value };
531 }
532 }
533 /**
534 When specified, `prefixUrl` will be prepended to `url`.
535 The prefix can be any valid URL, either relative or absolute.
536 A trailing slash `/` is optional - one will be added automatically.
537
538 __Note__: `prefixUrl` will be ignored if the `url` argument is a URL instance.
539
540 __Note__: Leading slashes in `input` are disallowed when using this option to enforce consistency and avoid confusion.
541 For example, when the prefix URL is `https://example.com/foo` and the input is `/bar`, there's ambiguity whether the resulting URL would become `https://example.com/foo/bar` or `https://example.com/bar`.
542 The latter is used by browsers.
543
544 __Tip__: Useful when used with `got.extend()` to create niche-specific Got instances.
545
546 __Tip__: You can change `prefixUrl` using hooks as long as the URL still includes the `prefixUrl`.
547 If the URL doesn't include it anymore, it will throw.
548
549 @example
550 ```
551 import got from 'got';
552
553 await got('unicorn', {prefixUrl: 'https://cats.com'});
554 //=> 'https://cats.com/unicorn'
555
556 const instance = got.extend({
557 prefixUrl: 'https://google.com'
558 });
559
560 await instance('unicorn', {
561 hooks: {
562 beforeRequest: [
563 options => {
564 options.prefixUrl = 'https://cats.com';
565 }
566 ]
567 }
568 });
569 //=> 'https://cats.com/unicorn'
570 ```
571 */
572 get prefixUrl() {
573 // We always return `string` here.
574 // It has to be `string | URL`, otherwise TypeScript will error because the getter and the setter have incompatible types.
575 return this._internals.prefixUrl;
576 }
577 set prefixUrl(value) {
578 assert.any([is.string, is.urlInstance], value);
579 if (value === '') {
580 this._internals.prefixUrl = '';
581 return;
582 }
583 value = value.toString();
584 if (!value.endsWith('/')) {
585 value += '/';
586 }
587 if (this._internals.prefixUrl && this._internals.url) {
588 const { href } = this._internals.url;
589 this._internals.url.href = value + href.slice(this._internals.prefixUrl.length);
590 }
591 this._internals.prefixUrl = value;
592 }
593 /**
594 __Note #1__: The `body` option cannot be used with the `json` or `form` option.
595
596 __Note #2__: If you provide this option, `got.stream()` will be read-only.
597
598 __Note #3__: If you provide a payload with the `GET` or `HEAD` method, it will throw a `TypeError` unless the method is `GET` and the `allowGetBody` option is set to `true`.
599
600 __Note #4__: This option is not enumerable and will not be merged with the instance defaults.
601
602 The `content-length` header will be automatically set if `body` is a `string` / `Buffer` / [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) / [`form-data` instance](https://github.com/form-data/form-data), and `content-length` and `transfer-encoding` are not manually set in `options.headers`.
603
604 Since Got 12, the `content-length` is not automatically set when `body` is a `fs.createReadStream`.
605 */
606 get body() {
607 return this._internals.body;
608 }
609 set body(value) {
610 assert.any([is.string, is.buffer, is.nodeStream, is.generator, is.asyncGenerator, isFormDataLike, is.undefined], value);
611 if (is.nodeStream(value)) {
612 assert.truthy(value.readable);
613 }
614 if (value !== undefined) {
615 assert.undefined(this._internals.form);
616 assert.undefined(this._internals.json);
617 }
618 this._internals.body = value;
619 }
620 /**
621 The form body is converted to a query string using [`(new URLSearchParams(object)).toString()`](https://nodejs.org/api/url.html#url_constructor_new_urlsearchparams_obj).
622
623 If the `Content-Type` header is not present, it will be set to `application/x-www-form-urlencoded`.
624
625 __Note #1__: If you provide this option, `got.stream()` will be read-only.
626
627 __Note #2__: This option is not enumerable and will not be merged with the instance defaults.
628 */
629 get form() {
630 return this._internals.form;
631 }
632 set form(value) {
633 assert.any([is.plainObject, is.undefined], value);
634 if (value !== undefined) {
635 assert.undefined(this._internals.body);
636 assert.undefined(this._internals.json);
637 }
638 this._internals.form = value;
639 }
640 /**
641 JSON body. If the `Content-Type` header is not set, it will be set to `application/json`.
642
643 __Note #1__: If you provide this option, `got.stream()` will be read-only.
644
645 __Note #2__: This option is not enumerable and will not be merged with the instance defaults.
646 */
647 get json() {
648 return this._internals.json;
649 }
650 set json(value) {
651 assert.any([is.object, is.undefined], value);
652 if (value !== undefined) {
653 assert.undefined(this._internals.body);
654 assert.undefined(this._internals.form);
655 }
656 this._internals.json = value;
657 }
658 /**
659 The URL to request, as a string, a [`https.request` options object](https://nodejs.org/api/https.html#https_https_request_options_callback), or a [WHATWG `URL`](https://nodejs.org/api/url.html#url_class_url).
660
661 Properties from `options` will override properties in the parsed `url`.
662
663 If no protocol is specified, it will throw a `TypeError`.
664
665 __Note__: The query string is **not** parsed as search params.
666
667 @example
668 ```
669 await got('https://example.com/?query=a b'); //=> https://example.com/?query=a%20b
670 await got('https://example.com/', {searchParams: {query: 'a b'}}); //=> https://example.com/?query=a+b
671
672 // The query string is overridden by `searchParams`
673 await got('https://example.com/?query=a b', {searchParams: {query: 'a b'}}); //=> https://example.com/?query=a+b
674 ```
675 */
676 get url() {
677 return this._internals.url;
678 }
679 set url(value) {
680 assert.any([is.string, is.urlInstance, is.undefined], value);
681 if (value === undefined) {
682 this._internals.url = undefined;
683 return;
684 }
685 if (is.string(value) && value.startsWith('/')) {
686 throw new Error('`url` must not start with a slash');
687 }
688 const urlString = `${this.prefixUrl}${value.toString()}`;
689 const url = new URL(urlString);
690 this._internals.url = url;
691 decodeURI(urlString);
692 if (url.protocol === 'unix:') {
693 url.href = `http://unix${url.pathname}${url.search}`;
694 }
695 if (url.protocol !== 'http:' && url.protocol !== 'https:') {
696 const error = new Error(`Unsupported protocol: ${url.protocol}`);
697 error.code = 'ERR_UNSUPPORTED_PROTOCOL';
698 throw error;
699 }
700 if (this._internals.username) {
701 url.username = this._internals.username;
702 this._internals.username = '';
703 }
704 if (this._internals.password) {
705 url.password = this._internals.password;
706 this._internals.password = '';
707 }
708 if (this._internals.searchParams) {
709 url.search = this._internals.searchParams.toString();
710 this._internals.searchParams = undefined;
711 }
712 if (url.hostname === 'unix') {
713 const matches = /(?<socketPath>.+?):(?<path>.+)/.exec(`${url.pathname}${url.search}`);
714 if (matches?.groups) {
715 const { socketPath, path } = matches.groups;
716 this._unixOptions = {
717 socketPath,
718 path,
719 host: '',
720 };
721 }
722 else {
723 this._unixOptions = undefined;
724 }
725 return;
726 }
727 this._unixOptions = undefined;
728 }
729 /**
730 Cookie support. You don't have to care about parsing or how to store them.
731
732 __Note__: If you provide this option, `options.headers.cookie` will be overridden.
733 */
734 get cookieJar() {
735 return this._internals.cookieJar;
736 }
737 set cookieJar(value) {
738 assert.any([is.object, is.undefined], value);
739 if (value === undefined) {
740 this._internals.cookieJar = undefined;
741 return;
742 }
743 let { setCookie, getCookieString } = value;
744 assert.function_(setCookie);
745 assert.function_(getCookieString);
746 /* istanbul ignore next: Horrible `tough-cookie` v3 check */
747 if (setCookie.length === 4 && getCookieString.length === 0) {
748 setCookie = promisify(setCookie.bind(value));
749 getCookieString = promisify(getCookieString.bind(value));
750 this._internals.cookieJar = {
751 setCookie,
752 getCookieString: getCookieString,
753 };
754 }
755 else {
756 this._internals.cookieJar = value;
757 }
758 }
759 /**
760 Ignore invalid cookies instead of throwing an error.
761 Only useful when the `cookieJar` option has been set. Not recommended.
762
763 @default false
764 */
765 get ignoreInvalidCookies() {
766 return this._internals.ignoreInvalidCookies;
767 }
768 set ignoreInvalidCookies(value) {
769 assert.boolean(value);
770 this._internals.ignoreInvalidCookies = value;
771 }
772 /**
773 Query string that will be added to the request URL.
774 This will override the query string in `url`.
775
776 If you need to pass in an array, you can do it using a `URLSearchParams` instance.
777
778 @example
779 ```
780 import got from 'got';
781
782 const searchParams = new URLSearchParams([['key', 'a'], ['key', 'b']]);
783
784 await got('https://example.com', {searchParams});
785
786 console.log(searchParams.toString());
787 //=> 'key=a&key=b'
788 ```
789 */
790 get searchParams() {
791 if (this._internals.url) {
792 return this._internals.url.searchParams;
793 }
794 if (this._internals.searchParams === undefined) {
795 this._internals.searchParams = new URLSearchParams();
796 }
797 return this._internals.searchParams;
798 }
799 set searchParams(value) {
800 assert.any([is.string, is.object, is.undefined], value);
801 const url = this._internals.url;
802 if (value === undefined) {
803 this._internals.searchParams = undefined;
804 if (url) {
805 url.search = '';
806 }
807 return;
808 }
809 const searchParameters = this.searchParams;
810 let updated;
811 if (is.string(value)) {
812 updated = new URLSearchParams(value);
813 }
814 else if (value instanceof URLSearchParams) {
815 updated = value;
816 }
817 else {
818 validateSearchParameters(value);
819 updated = new URLSearchParams();
820 // eslint-disable-next-line guard-for-in
821 for (const key in value) {
822 const entry = value[key];
823 if (entry === null) {
824 updated.append(key, '');
825 }
826 else if (entry === undefined) {
827 searchParameters.delete(key);
828 }
829 else {
830 updated.append(key, entry);
831 }
832 }
833 }
834 if (this._merging) {
835 // These keys will be replaced
836 for (const key of updated.keys()) {
837 searchParameters.delete(key);
838 }
839 for (const [key, value] of updated) {
840 searchParameters.append(key, value);
841 }
842 }
843 else if (url) {
844 url.search = searchParameters.toString();
845 }
846 else {
847 this._internals.searchParams = searchParameters;
848 }
849 }
850 get searchParameters() {
851 throw new Error('The `searchParameters` option does not exist. Use `searchParams` instead.');
852 }
853 set searchParameters(_value) {
854 throw new Error('The `searchParameters` option does not exist. Use `searchParams` instead.');
855 }
856 get dnsLookup() {
857 return this._internals.dnsLookup;
858 }
859 set dnsLookup(value) {
860 assert.any([is.function_, is.undefined], value);
861 this._internals.dnsLookup = value;
862 }
863 /**
864 An instance of [`CacheableLookup`](https://github.com/szmarczak/cacheable-lookup) used for making DNS lookups.
865 Useful when making lots of requests to different *public* hostnames.
866
867 `CacheableLookup` uses `dns.resolver4(..)` and `dns.resolver6(...)` under the hood and fall backs to `dns.lookup(...)` when the first two fail, which may lead to additional delay.
868
869 __Note__: This should stay disabled when making requests to internal hostnames such as `localhost`, `database.local` etc.
870
871 @default false
872 */
873 get dnsCache() {
874 return this._internals.dnsCache;
875 }
876 set dnsCache(value) {
877 assert.any([is.object, is.boolean, is.undefined], value);
878 if (value === true) {
879 this._internals.dnsCache = getGlobalDnsCache();
880 }
881 else if (value === false) {
882 this._internals.dnsCache = undefined;
883 }
884 else {
885 this._internals.dnsCache = value;
886 }
887 }
888 /**
889 User data. `context` is shallow merged and enumerable. If it contains non-enumerable properties they will NOT be merged.
890
891 @example
892 ```
893 import got from 'got';
894
895 const instance = got.extend({
896 hooks: {
897 beforeRequest: [
898 options => {
899 if (!options.context || !options.context.token) {
900 throw new Error('Token required');
901 }
902
903 options.headers.token = options.context.token;
904 }
905 ]
906 }
907 });
908
909 const context = {
910 token: 'secret'
911 };
912
913 const response = await instance('https://httpbin.org/headers', {context});
914
915 // Let's see the headers
916 console.log(response.body);
917 ```
918 */
919 get context() {
920 return this._internals.context;
921 }
922 set context(value) {
923 assert.object(value);
924 if (this._merging) {
925 Object.assign(this._internals.context, value);
926 }
927 else {
928 this._internals.context = { ...value };
929 }
930 }
931 /**
932 Hooks allow modifications during the request lifecycle.
933 Hook functions may be async and are run serially.
934 */
935 get hooks() {
936 return this._internals.hooks;
937 }
938 set hooks(value) {
939 assert.object(value);
940 // eslint-disable-next-line guard-for-in
941 for (const knownHookEvent in value) {
942 if (!(knownHookEvent in this._internals.hooks)) {
943 throw new Error(`Unexpected hook event: ${knownHookEvent}`);
944 }
945 const typedKnownHookEvent = knownHookEvent;
946 const typedValue = value;
947 const hooks = typedValue[typedKnownHookEvent];
948 assert.any([is.array, is.undefined], hooks);
949 if (hooks) {
950 for (const hook of hooks) {
951 assert.function_(hook);
952 }
953 }
954 if (this._merging) {
955 if (hooks) {
956 // @ts-expect-error FIXME
957 this._internals.hooks[typedKnownHookEvent].push(...hooks);
958 }
959 }
960 else {
961 if (!hooks) {
962 throw new Error(`Missing hook event: ${knownHookEvent}`);
963 }
964 // @ts-expect-error FIXME
965 this._internals.hooks[knownHookEvent] = [...hooks];
966 }
967 }
968 }
969 /**
970 Defines if redirect responses should be followed automatically.
971
972 Note that if a `303` is sent by the server in response to any request type (`POST`, `DELETE`, etc.), Got will automatically request the resource pointed to in the location header via `GET`.
973 This is in accordance with [the spec](https://tools.ietf.org/html/rfc7231#section-6.4.4).
974
975 @default true
976 */
977 get followRedirect() {
978 return this._internals.followRedirect;
979 }
980 set followRedirect(value) {
981 assert.boolean(value);
982 this._internals.followRedirect = value;
983 }
984 get followRedirects() {
985 throw new TypeError('The `followRedirects` option does not exist. Use `followRedirect` instead.');
986 }
987 set followRedirects(_value) {
988 throw new TypeError('The `followRedirects` option does not exist. Use `followRedirect` instead.');
989 }
990 /**
991 If exceeded, the request will be aborted and a `MaxRedirectsError` will be thrown.
992
993 @default 10
994 */
995 get maxRedirects() {
996 return this._internals.maxRedirects;
997 }
998 set maxRedirects(value) {
999 assert.number(value);
1000 this._internals.maxRedirects = value;
1001 }
1002 /**
1003 A cache adapter instance for storing cached response data.
1004
1005 @default false
1006 */
1007 get cache() {
1008 return this._internals.cache;
1009 }
1010 set cache(value) {
1011 assert.any([is.object, is.string, is.boolean, is.undefined], value);
1012 if (value === true) {
1013 this._internals.cache = globalCache;
1014 }
1015 else if (value === false) {
1016 this._internals.cache = undefined;
1017 }
1018 else {
1019 this._internals.cache = value;
1020 }
1021 }
1022 /**
1023 Determines if a `got.HTTPError` is thrown for unsuccessful responses.
1024
1025 If this is disabled, requests that encounter an error status code will be resolved with the `response` instead of throwing.
1026 This may be useful if you are checking for resource availability and are expecting error responses.
1027
1028 @default true
1029 */
1030 get throwHttpErrors() {
1031 return this._internals.throwHttpErrors;
1032 }
1033 set throwHttpErrors(value) {
1034 assert.boolean(value);
1035 this._internals.throwHttpErrors = value;
1036 }
1037 get username() {
1038 const url = this._internals.url;
1039 const value = url ? url.username : this._internals.username;
1040 return decodeURIComponent(value);
1041 }
1042 set username(value) {
1043 assert.string(value);
1044 const url = this._internals.url;
1045 const fixedValue = encodeURIComponent(value);
1046 if (url) {
1047 url.username = fixedValue;
1048 }
1049 else {
1050 this._internals.username = fixedValue;
1051 }
1052 }
1053 get password() {
1054 const url = this._internals.url;
1055 const value = url ? url.password : this._internals.password;
1056 return decodeURIComponent(value);
1057 }
1058 set password(value) {
1059 assert.string(value);
1060 const url = this._internals.url;
1061 const fixedValue = encodeURIComponent(value);
1062 if (url) {
1063 url.password = fixedValue;
1064 }
1065 else {
1066 this._internals.password = fixedValue;
1067 }
1068 }
1069 /**
1070 If set to `true`, Got will additionally accept HTTP2 requests.
1071
1072 It will choose either HTTP/1.1 or HTTP/2 depending on the ALPN protocol.
1073
1074 __Note__: This option requires Node.js 15.10.0 or newer as HTTP/2 support on older Node.js versions is very buggy.
1075
1076 __Note__: Overriding `options.request` will disable HTTP2 support.
1077
1078 @default false
1079
1080 @example
1081 ```
1082 import got from 'got';
1083
1084 const {headers} = await got('https://nghttp2.org/httpbin/anything', {http2: true});
1085
1086 console.log(headers.via);
1087 //=> '2 nghttpx'
1088 ```
1089 */
1090 get http2() {
1091 return this._internals.http2;
1092 }
1093 set http2(value) {
1094 assert.boolean(value);
1095 this._internals.http2 = value;
1096 }
1097 /**
1098 Set this to `true` to allow sending body for the `GET` method.
1099 However, the [HTTP/2 specification](https://tools.ietf.org/html/rfc7540#section-8.1.3) says that `An HTTP GET request includes request header fields and no payload body`, therefore when using the HTTP/2 protocol this option will have no effect.
1100 This option is only meant to interact with non-compliant servers when you have no other choice.
1101
1102 __Note__: The [RFC 7321](https://tools.ietf.org/html/rfc7231#section-4.3.1) doesn't specify any particular behavior for the GET method having a payload, therefore __it's considered an [anti-pattern](https://en.wikipedia.org/wiki/Anti-pattern)__.
1103
1104 @default false
1105 */
1106 get allowGetBody() {
1107 return this._internals.allowGetBody;
1108 }
1109 set allowGetBody(value) {
1110 assert.boolean(value);
1111 this._internals.allowGetBody = value;
1112 }
1113 /**
1114 Request headers.
1115
1116 Existing headers will be overwritten. Headers set to `undefined` will be omitted.
1117
1118 @default {}
1119 */
1120 get headers() {
1121 return this._internals.headers;
1122 }
1123 set headers(value) {
1124 assert.plainObject(value);
1125 if (this._merging) {
1126 Object.assign(this._internals.headers, lowercaseKeys(value));
1127 }
1128 else {
1129 this._internals.headers = lowercaseKeys(value);
1130 }
1131 }
1132 /**
1133 Specifies if the redirects should be [rewritten as `GET`](https://tools.ietf.org/html/rfc7231#section-6.4).
1134
1135 If `false`, when sending a POST request and receiving a `302`, it will resend the body to the new location using the same HTTP method (`POST` in this case).
1136
1137 @default false
1138 */
1139 get methodRewriting() {
1140 return this._internals.methodRewriting;
1141 }
1142 set methodRewriting(value) {
1143 assert.boolean(value);
1144 this._internals.methodRewriting = value;
1145 }
1146 /**
1147 Indicates which DNS record family to use.
1148
1149 Values:
1150 - `undefined`: IPv4 (if present) or IPv6
1151 - `4`: Only IPv4
1152 - `6`: Only IPv6
1153
1154 @default undefined
1155 */
1156 get dnsLookupIpVersion() {
1157 return this._internals.dnsLookupIpVersion;
1158 }
1159 set dnsLookupIpVersion(value) {
1160 if (value !== undefined && value !== 4 && value !== 6) {
1161 throw new TypeError(`Invalid DNS lookup IP version: ${value}`);
1162 }
1163 this._internals.dnsLookupIpVersion = value;
1164 }
1165 /**
1166 A function used to parse JSON responses.
1167
1168 @example
1169 ```
1170 import got from 'got';
1171 import Bourne from '@hapi/bourne';
1172
1173 const parsed = await got('https://example.com', {
1174 parseJson: text => Bourne.parse(text)
1175 }).json();
1176
1177 console.log(parsed);
1178 ```
1179 */
1180 get parseJson() {
1181 return this._internals.parseJson;
1182 }
1183 set parseJson(value) {
1184 assert.function_(value);
1185 this._internals.parseJson = value;
1186 }
1187 /**
1188 A function used to stringify the body of JSON requests.
1189
1190 @example
1191 ```
1192 import got from 'got';
1193
1194 await got.post('https://example.com', {
1195 stringifyJson: object => JSON.stringify(object, (key, value) => {
1196 if (key.startsWith('_')) {
1197 return;
1198 }
1199
1200 return value;
1201 }),
1202 json: {
1203 some: 'payload',
1204 _ignoreMe: 1234
1205 }
1206 });
1207 ```
1208
1209 @example
1210 ```
1211 import got from 'got';
1212
1213 await got.post('https://example.com', {
1214 stringifyJson: object => JSON.stringify(object, (key, value) => {
1215 if (typeof value === 'number') {
1216 return value.toString();
1217 }
1218
1219 return value;
1220 }),
1221 json: {
1222 some: 'payload',
1223 number: 1
1224 }
1225 });
1226 ```
1227 */
1228 get stringifyJson() {
1229 return this._internals.stringifyJson;
1230 }
1231 set stringifyJson(value) {
1232 assert.function_(value);
1233 this._internals.stringifyJson = value;
1234 }
1235 /**
1236 An object representing `limit`, `calculateDelay`, `methods`, `statusCodes`, `maxRetryAfter` and `errorCodes` fields for maximum retry count, retry handler, allowed methods, allowed status codes, maximum [`Retry-After`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After) time and allowed error codes.
1237
1238 Delays between retries counts with function `1000 * Math.pow(2, retry) + Math.random() * 100`, where `retry` is attempt number (starts from 1).
1239
1240 The `calculateDelay` property is a `function` that receives an object with `attemptCount`, `retryOptions`, `error` and `computedValue` properties for current retry count, the retry options, error and default computed value.
1241 The function must return a delay in milliseconds (or a Promise resolving with it) (`0` return value cancels retry).
1242
1243 By default, it retries *only* on the specified methods, status codes, and on these network errors:
1244
1245 - `ETIMEDOUT`: One of the [timeout](#timeout) limits were reached.
1246 - `ECONNRESET`: Connection was forcibly closed by a peer.
1247 - `EADDRINUSE`: Could not bind to any free port.
1248 - `ECONNREFUSED`: Connection was refused by the server.
1249 - `EPIPE`: The remote side of the stream being written has been closed.
1250 - `ENOTFOUND`: Couldn't resolve the hostname to an IP address.
1251 - `ENETUNREACH`: No internet connection.
1252 - `EAI_AGAIN`: DNS lookup timed out.
1253
1254 __Note__: If `maxRetryAfter` is set to `undefined`, it will use `options.timeout`.
1255 __Note__: If [`Retry-After`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After) header is greater than `maxRetryAfter`, it will cancel the request.
1256 */
1257 get retry() {
1258 return this._internals.retry;
1259 }
1260 set retry(value) {
1261 assert.plainObject(value);
1262 assert.any([is.function_, is.undefined], value.calculateDelay);
1263 assert.any([is.number, is.undefined], value.maxRetryAfter);
1264 assert.any([is.number, is.undefined], value.limit);
1265 assert.any([is.array, is.undefined], value.methods);
1266 assert.any([is.array, is.undefined], value.statusCodes);
1267 assert.any([is.array, is.undefined], value.errorCodes);
1268 assert.any([is.number, is.undefined], value.noise);
1269 if (value.noise && Math.abs(value.noise) > 100) {
1270 throw new Error(`The maximum acceptable retry noise is +/- 100ms, got ${value.noise}`);
1271 }
1272 for (const key in value) {
1273 if (!(key in this._internals.retry)) {
1274 throw new Error(`Unexpected retry option: ${key}`);
1275 }
1276 }
1277 if (this._merging) {
1278 Object.assign(this._internals.retry, value);
1279 }
1280 else {
1281 this._internals.retry = { ...value };
1282 }
1283 const { retry } = this._internals;
1284 retry.methods = [...new Set(retry.methods.map(method => method.toUpperCase()))];
1285 retry.statusCodes = [...new Set(retry.statusCodes)];
1286 retry.errorCodes = [...new Set(retry.errorCodes)];
1287 }
1288 /**
1289 From `http.RequestOptions`.
1290
1291 The IP address used to send the request from.
1292 */
1293 get localAddress() {
1294 return this._internals.localAddress;
1295 }
1296 set localAddress(value) {
1297 assert.any([is.string, is.undefined], value);
1298 this._internals.localAddress = value;
1299 }
1300 /**
1301 The HTTP method used to make the request.
1302
1303 @default 'GET'
1304 */
1305 get method() {
1306 return this._internals.method;
1307 }
1308 set method(value) {
1309 assert.string(value);
1310 this._internals.method = value.toUpperCase();
1311 }
1312 get createConnection() {
1313 return this._internals.createConnection;
1314 }
1315 set createConnection(value) {
1316 assert.any([is.function_, is.undefined], value);
1317 this._internals.createConnection = value;
1318 }
1319 /**
1320 From `http-cache-semantics`
1321
1322 @default {}
1323 */
1324 get cacheOptions() {
1325 return this._internals.cacheOptions;
1326 }
1327 set cacheOptions(value) {
1328 assert.plainObject(value);
1329 assert.any([is.boolean, is.undefined], value.shared);
1330 assert.any([is.number, is.undefined], value.cacheHeuristic);
1331 assert.any([is.number, is.undefined], value.immutableMinTimeToLive);
1332 assert.any([is.boolean, is.undefined], value.ignoreCargoCult);
1333 for (const key in value) {
1334 if (!(key in this._internals.cacheOptions)) {
1335 throw new Error(`Cache option \`${key}\` does not exist`);
1336 }
1337 }
1338 if (this._merging) {
1339 Object.assign(this._internals.cacheOptions, value);
1340 }
1341 else {
1342 this._internals.cacheOptions = { ...value };
1343 }
1344 }
1345 /**
1346 Options for the advanced HTTPS API.
1347 */
1348 get https() {
1349 return this._internals.https;
1350 }
1351 set https(value) {
1352 assert.plainObject(value);
1353 assert.any([is.boolean, is.undefined], value.rejectUnauthorized);
1354 assert.any([is.function_, is.undefined], value.checkServerIdentity);
1355 assert.any([is.string, is.object, is.array, is.undefined], value.certificateAuthority);
1356 assert.any([is.string, is.object, is.array, is.undefined], value.key);
1357 assert.any([is.string, is.object, is.array, is.undefined], value.certificate);
1358 assert.any([is.string, is.undefined], value.passphrase);
1359 assert.any([is.string, is.buffer, is.array, is.undefined], value.pfx);
1360 assert.any([is.array, is.undefined], value.alpnProtocols);
1361 assert.any([is.string, is.undefined], value.ciphers);
1362 assert.any([is.string, is.buffer, is.undefined], value.dhparam);
1363 assert.any([is.string, is.undefined], value.signatureAlgorithms);
1364 assert.any([is.string, is.undefined], value.minVersion);
1365 assert.any([is.string, is.undefined], value.maxVersion);
1366 assert.any([is.boolean, is.undefined], value.honorCipherOrder);
1367 assert.any([is.number, is.undefined], value.tlsSessionLifetime);
1368 assert.any([is.string, is.undefined], value.ecdhCurve);
1369 assert.any([is.string, is.buffer, is.array, is.undefined], value.certificateRevocationLists);
1370 for (const key in value) {
1371 if (!(key in this._internals.https)) {
1372 throw new Error(`HTTPS option \`${key}\` does not exist`);
1373 }
1374 }
1375 if (this._merging) {
1376 Object.assign(this._internals.https, value);
1377 }
1378 else {
1379 this._internals.https = { ...value };
1380 }
1381 }
1382 /**
1383 [Encoding](https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings) to be used on `setEncoding` of the response data.
1384
1385 To get a [`Buffer`](https://nodejs.org/api/buffer.html), you need to set `responseType` to `buffer` instead.
1386 Don't set this option to `null`.
1387
1388 __Note__: This doesn't affect streams! Instead, you need to do `got.stream(...).setEncoding(encoding)`.
1389
1390 @default 'utf-8'
1391 */
1392 get encoding() {
1393 return this._internals.encoding;
1394 }
1395 set encoding(value) {
1396 if (value === null) {
1397 throw new TypeError('To get a Buffer, set `options.responseType` to `buffer` instead');
1398 }
1399 assert.any([is.string, is.undefined], value);
1400 this._internals.encoding = value;
1401 }
1402 /**
1403 When set to `true` the promise will return the Response body instead of the Response object.
1404
1405 @default false
1406 */
1407 get resolveBodyOnly() {
1408 return this._internals.resolveBodyOnly;
1409 }
1410 set resolveBodyOnly(value) {
1411 assert.boolean(value);
1412 this._internals.resolveBodyOnly = value;
1413 }
1414 /**
1415 Returns a `Stream` instead of a `Promise`.
1416 This is equivalent to calling `got.stream(url, options?)`.
1417
1418 @default false
1419 */
1420 get isStream() {
1421 return this._internals.isStream;
1422 }
1423 set isStream(value) {
1424 assert.boolean(value);
1425 this._internals.isStream = value;
1426 }
1427 /**
1428 The parsing method.
1429
1430 The promise also has `.text()`, `.json()` and `.buffer()` methods which return another Got promise for the parsed body.
1431
1432 It's like setting the options to `{responseType: 'json', resolveBodyOnly: true}` but without affecting the main Got promise.
1433
1434 __Note__: When using streams, this option is ignored.
1435
1436 @example
1437 ```
1438 const responsePromise = got(url);
1439 const bufferPromise = responsePromise.buffer();
1440 const jsonPromise = responsePromise.json();
1441
1442 const [response, buffer, json] = Promise.all([responsePromise, bufferPromise, jsonPromise]);
1443 // `response` is an instance of Got Response
1444 // `buffer` is an instance of Buffer
1445 // `json` is an object
1446 ```
1447
1448 @example
1449 ```
1450 // This
1451 const body = await got(url).json();
1452
1453 // is semantically the same as this
1454 const body = await got(url, {responseType: 'json', resolveBodyOnly: true});
1455 ```
1456 */
1457 get responseType() {
1458 return this._internals.responseType;
1459 }
1460 set responseType(value) {
1461 if (value === undefined) {
1462 this._internals.responseType = 'text';
1463 return;
1464 }
1465 if (value !== 'text' && value !== 'buffer' && value !== 'json') {
1466 throw new Error(`Invalid \`responseType\` option: ${value}`);
1467 }
1468 this._internals.responseType = value;
1469 }
1470 get pagination() {
1471 return this._internals.pagination;
1472 }
1473 set pagination(value) {
1474 assert.object(value);
1475 if (this._merging) {
1476 Object.assign(this._internals.pagination, value);
1477 }
1478 else {
1479 this._internals.pagination = value;
1480 }
1481 }
1482 get auth() {
1483 throw new Error('Parameter `auth` is deprecated. Use `username` / `password` instead.');
1484 }
1485 set auth(_value) {
1486 throw new Error('Parameter `auth` is deprecated. Use `username` / `password` instead.');
1487 }
1488 get setHost() {
1489 return this._internals.setHost;
1490 }
1491 set setHost(value) {
1492 assert.boolean(value);
1493 this._internals.setHost = value;
1494 }
1495 get maxHeaderSize() {
1496 return this._internals.maxHeaderSize;
1497 }
1498 set maxHeaderSize(value) {
1499 assert.any([is.number, is.undefined], value);
1500 this._internals.maxHeaderSize = value;
1501 }
1502 // eslint-disable-next-line @typescript-eslint/naming-convention
1503 toJSON() {
1504 return { ...this._internals };
1505 }
1506 [Symbol.for('nodejs.util.inspect.custom')](_depth, options) {
1507 return inspect(this._internals, options);
1508 }
1509 createNativeRequestOptions() {
1510 const internals = this._internals;
1511 const url = internals.url;
1512 let agent;
1513 if (url.protocol === 'https:') {
1514 agent = internals.http2 ? internals.agent : internals.agent.https;
1515 }
1516 else {
1517 agent = internals.agent.http;
1518 }
1519 const { https } = internals;
1520 let { pfx } = https;
1521 if (is.array(pfx) && is.plainObject(pfx[0])) {
1522 pfx = pfx.map(object => ({
1523 buf: object.buffer,
1524 passphrase: object.passphrase,
1525 }));
1526 }
1527 return {
1528 ...internals.cacheOptions,
1529 ...this._unixOptions,
1530 // HTTPS options
1531 // eslint-disable-next-line @typescript-eslint/naming-convention
1532 ALPNProtocols: https.alpnProtocols,
1533 ca: https.certificateAuthority,
1534 cert: https.certificate,
1535 key: https.key,
1536 passphrase: https.passphrase,
1537 pfx: https.pfx,
1538 rejectUnauthorized: https.rejectUnauthorized,
1539 checkServerIdentity: https.checkServerIdentity ?? checkServerIdentity,
1540 ciphers: https.ciphers,
1541 honorCipherOrder: https.honorCipherOrder,
1542 minVersion: https.minVersion,
1543 maxVersion: https.maxVersion,
1544 sigalgs: https.signatureAlgorithms,
1545 sessionTimeout: https.tlsSessionLifetime,
1546 dhparam: https.dhparam,
1547 ecdhCurve: https.ecdhCurve,
1548 crl: https.certificateRevocationLists,
1549 // HTTP options
1550 lookup: internals.dnsLookup ?? internals.dnsCache?.lookup,
1551 family: internals.dnsLookupIpVersion,
1552 agent,
1553 setHost: internals.setHost,
1554 method: internals.method,
1555 maxHeaderSize: internals.maxHeaderSize,
1556 localAddress: internals.localAddress,
1557 headers: internals.headers,
1558 createConnection: internals.createConnection,
1559 timeout: internals.http2 ? getHttp2TimeoutOption(internals) : undefined,
1560 // HTTP/2 options
1561 h2session: internals.h2session,
1562 };
1563 }
1564 getRequestFunction() {
1565 const url = this._internals.url;
1566 const { request } = this._internals;
1567 if (!request && url) {
1568 return this.getFallbackRequestFunction();
1569 }
1570 return request;
1571 }
1572 getFallbackRequestFunction() {
1573 const url = this._internals.url;
1574 if (!url) {
1575 return;
1576 }
1577 if (url.protocol === 'https:') {
1578 if (this._internals.http2) {
1579 if (major < 15 || (major === 15 && minor < 10)) {
1580 const error = new Error('To use the `http2` option, install Node.js 15.10.0 or above');
1581 error.code = 'EUNSUPPORTED';
1582 throw error;
1583 }
1584 return http2wrapper.auto;
1585 }
1586 return https.request;
1587 }
1588 return http.request;
1589 }
1590 freeze() {
1591 const options = this._internals;
1592 Object.freeze(options);
1593 Object.freeze(options.hooks);
1594 Object.freeze(options.hooks.afterResponse);
1595 Object.freeze(options.hooks.beforeError);
1596 Object.freeze(options.hooks.beforeRedirect);
1597 Object.freeze(options.hooks.beforeRequest);
1598 Object.freeze(options.hooks.beforeRetry);
1599 Object.freeze(options.hooks.init);
1600 Object.freeze(options.https);
1601 Object.freeze(options.cacheOptions);
1602 Object.freeze(options.agent);
1603 Object.freeze(options.headers);
1604 Object.freeze(options.timeout);
1605 Object.freeze(options.retry);
1606 Object.freeze(options.retry.errorCodes);
1607 Object.freeze(options.retry.methods);
1608 Object.freeze(options.retry.statusCodes);
1609 Object.freeze(options.context);
1610 }
1611}