got 14.6.5 → 15.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/source/as-promise/index.d.ts +2 -2
- package/dist/source/as-promise/index.js +59 -41
- package/dist/source/as-promise/types.d.ts +10 -23
- package/dist/source/as-promise/types.js +1 -17
- package/dist/source/core/calculate-retry-delay.js +1 -4
- package/dist/source/core/diagnostics-channel.js +12 -21
- package/dist/source/core/errors.d.ts +2 -1
- package/dist/source/core/errors.js +7 -10
- package/dist/source/core/index.d.ts +19 -7
- package/dist/source/core/index.js +726 -311
- package/dist/source/core/options.d.ts +92 -91
- package/dist/source/core/options.js +616 -303
- package/dist/source/core/response.d.ts +5 -3
- package/dist/source/core/response.js +26 -3
- package/dist/source/core/timed-out.d.ts +1 -1
- package/dist/source/core/timed-out.js +3 -3
- package/dist/source/core/utils/defer-to-connect.js +5 -17
- package/dist/source/core/utils/get-body-size.d.ts +1 -1
- package/dist/source/core/utils/get-body-size.js +3 -20
- package/dist/source/core/utils/proxy-events.d.ts +1 -1
- package/dist/source/core/utils/proxy-events.js +3 -3
- package/dist/source/core/utils/strip-url-auth.d.ts +1 -0
- package/dist/source/core/utils/strip-url-auth.js +9 -0
- package/dist/source/core/utils/timer.js +5 -7
- package/dist/source/core/utils/unhandle.js +1 -2
- package/dist/source/create.js +83 -27
- package/dist/source/index.d.ts +2 -3
- package/dist/source/index.js +0 -4
- package/dist/source/types.d.ts +42 -70
- package/package.json +34 -38
- package/readme.md +2 -2
- package/dist/source/core/utils/is-form-data.d.ts +0 -7
- package/dist/source/core/utils/is-form-data.js +0 -4
- package/dist/source/core/utils/url-to-options.d.ts +0 -14
- package/dist/source/core/utils/url-to-options.js +0 -22
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import process from 'node:process';
|
|
2
|
-
import { promisify, inspect } from 'node:util';
|
|
2
|
+
import { promisify, inspect, isDeepStrictEqual, } from 'node:util';
|
|
3
3
|
import { checkServerIdentity } from 'node:tls';
|
|
4
4
|
// DO NOT use destructuring for `https.request` and `http.request` as it's not compatible with `nock`.
|
|
5
5
|
import https from 'node:https';
|
|
@@ -8,8 +8,8 @@ import is, { assert } from '@sindresorhus/is';
|
|
|
8
8
|
import lowercaseKeys from 'lowercase-keys';
|
|
9
9
|
import CacheableLookup from 'cacheable-lookup';
|
|
10
10
|
import http2wrapper from 'http2-wrapper';
|
|
11
|
-
import { isFormData } from 'form-data-encoder';
|
|
12
11
|
import parseLinkHeader from './parse-link-header.js';
|
|
12
|
+
import { getUnixSocketPath } from './utils/is-unix-socket-url.js';
|
|
13
13
|
const [major, minor] = process.versions.node.split('.').map(Number);
|
|
14
14
|
/**
|
|
15
15
|
Generic helper that wraps any assertion function to add context to error messages.
|
|
@@ -43,9 +43,68 @@ function assertPlainObject(optionName, value) {
|
|
|
43
43
|
assert.plainObject(value);
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
|
+
export function isSameOrigin(previousUrl, nextUrl) {
|
|
47
|
+
return previousUrl.origin === nextUrl.origin
|
|
48
|
+
&& getUnixSocketPath(previousUrl) === getUnixSocketPath(nextUrl);
|
|
49
|
+
}
|
|
50
|
+
export const crossOriginStripHeaders = ['host', 'cookie', 'cookie2', 'authorization', 'proxy-authorization'];
|
|
51
|
+
const bodyHeaderNames = ['content-length', 'content-encoding', 'content-language', 'content-location', 'content-type', 'transfer-encoding'];
|
|
52
|
+
function usesUnixSocket(url) {
|
|
53
|
+
return url.protocol === 'unix:' || getUnixSocketPath(url) !== undefined;
|
|
54
|
+
}
|
|
55
|
+
function hasCredentialInUrl(url, credential) {
|
|
56
|
+
if (url instanceof URL) {
|
|
57
|
+
return url[credential] !== '';
|
|
58
|
+
}
|
|
59
|
+
if (!is.string(url)) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
return new URL(url)[credential] !== '';
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export const hasExplicitCredentialInUrlChange = (changedState, url, credential) => (changedState.has(credential)
|
|
70
|
+
|| (changedState.has('url') && url?.[credential] !== ''));
|
|
71
|
+
const hasProtocolSlashes = (value) => /^[a-z][a-z\d+.-]*:\/\//i.test(value);
|
|
72
|
+
const hasHttpProtocolWithoutSlashes = (value) => /^https?:(?!\/\/)/i.test(value);
|
|
73
|
+
export function applyUrlOverride(options, url, { username, password } = {}) {
|
|
74
|
+
if (is.string(url) && options.url) {
|
|
75
|
+
url = new URL(url, options.url).toString();
|
|
76
|
+
}
|
|
77
|
+
options.prefixUrl = '';
|
|
78
|
+
options.url = url;
|
|
79
|
+
if (username !== undefined) {
|
|
80
|
+
options.username = username;
|
|
81
|
+
}
|
|
82
|
+
if (password !== undefined) {
|
|
83
|
+
options.password = password;
|
|
84
|
+
}
|
|
85
|
+
return options.url;
|
|
86
|
+
}
|
|
87
|
+
function assertValidHeaderName(name) {
|
|
88
|
+
if (name.startsWith(':')) {
|
|
89
|
+
throw new TypeError(`HTTP/2 pseudo-headers are not supported in \`options.headers\`: ${name}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
Safely assign own properties from source to target, skipping `__proto__` to prevent prototype pollution from JSON.parse'd input.
|
|
94
|
+
*/
|
|
95
|
+
function safeObjectAssign(target, source) {
|
|
96
|
+
for (const key of Object.keys(source)) {
|
|
97
|
+
if (key === '__proto__') {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
target[key] = source[key];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
46
103
|
function validateSearchParameters(searchParameters) {
|
|
47
|
-
|
|
48
|
-
|
|
104
|
+
for (const key of Object.keys(searchParameters)) {
|
|
105
|
+
if (key === '__proto__') {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
49
108
|
const value = searchParameters[key];
|
|
50
109
|
assertAny(`searchParams.${key}`, [is.string, is.number, is.boolean, is.null, is.undefined], value);
|
|
51
110
|
}
|
|
@@ -138,7 +197,7 @@ const defaultInternals = {
|
|
|
138
197
|
password: '',
|
|
139
198
|
http2: false,
|
|
140
199
|
allowGetBody: false,
|
|
141
|
-
copyPipedHeaders:
|
|
200
|
+
copyPipedHeaders: false,
|
|
142
201
|
headers: {
|
|
143
202
|
'user-agent': 'got (https://github.com/sindresorhus/got)',
|
|
144
203
|
},
|
|
@@ -182,8 +241,7 @@ const defaultInternals = {
|
|
|
182
241
|
calculateDelay: ({ computedValue }) => computedValue,
|
|
183
242
|
backoffLimit: Number.POSITIVE_INFINITY,
|
|
184
243
|
noise: 100,
|
|
185
|
-
|
|
186
|
-
enforceRetryRules: false,
|
|
244
|
+
enforceRetryRules: true,
|
|
187
245
|
},
|
|
188
246
|
localAddress: undefined,
|
|
189
247
|
method: 'GET',
|
|
@@ -235,8 +293,9 @@ const defaultInternals = {
|
|
|
235
293
|
const parsed = parseLinkHeader(rawLinkHeader);
|
|
236
294
|
const next = parsed.find(entry => entry.parameters.rel === 'next' || entry.parameters.rel === '"next"');
|
|
237
295
|
if (next) {
|
|
296
|
+
const baseUrl = response.request.options.url ?? response.url;
|
|
238
297
|
return {
|
|
239
|
-
url: new URL(next.reference,
|
|
298
|
+
url: new URL(next.reference, baseUrl),
|
|
240
299
|
};
|
|
241
300
|
}
|
|
242
301
|
return false;
|
|
@@ -252,7 +311,7 @@ const defaultInternals = {
|
|
|
252
311
|
maxHeaderSize: undefined,
|
|
253
312
|
signal: undefined,
|
|
254
313
|
enableUnixSockets: false,
|
|
255
|
-
strictContentLength:
|
|
314
|
+
strictContentLength: true,
|
|
256
315
|
};
|
|
257
316
|
const cloneInternals = (internals) => {
|
|
258
317
|
const { hooks, retry } = internals;
|
|
@@ -285,27 +344,24 @@ const cloneInternals = (internals) => {
|
|
|
285
344
|
return result;
|
|
286
345
|
};
|
|
287
346
|
const cloneRaw = (raw) => {
|
|
288
|
-
const { hooks, retry } = raw;
|
|
289
347
|
const result = { ...raw };
|
|
290
|
-
if (is.object(raw.context)) {
|
|
348
|
+
if (Object.hasOwn(raw, 'context') && is.object(raw.context)) {
|
|
291
349
|
result.context = { ...raw.context };
|
|
292
350
|
}
|
|
293
|
-
if (is.object(raw.cacheOptions)) {
|
|
351
|
+
if (Object.hasOwn(raw, 'cacheOptions') && is.object(raw.cacheOptions)) {
|
|
294
352
|
result.cacheOptions = { ...raw.cacheOptions };
|
|
295
353
|
}
|
|
296
|
-
if (is.object(raw.https)) {
|
|
354
|
+
if (Object.hasOwn(raw, 'https') && is.object(raw.https)) {
|
|
297
355
|
result.https = { ...raw.https };
|
|
298
356
|
}
|
|
299
|
-
if (is.object(raw.
|
|
300
|
-
result.cacheOptions = { ...result.cacheOptions };
|
|
301
|
-
}
|
|
302
|
-
if (is.object(raw.agent)) {
|
|
357
|
+
if (Object.hasOwn(raw, 'agent') && is.object(raw.agent)) {
|
|
303
358
|
result.agent = { ...raw.agent };
|
|
304
359
|
}
|
|
305
|
-
if (is.object(raw.headers)) {
|
|
360
|
+
if (Object.hasOwn(raw, 'headers') && is.object(raw.headers)) {
|
|
306
361
|
result.headers = { ...raw.headers };
|
|
307
362
|
}
|
|
308
|
-
if (is.object(retry)) {
|
|
363
|
+
if (Object.hasOwn(raw, 'retry') && is.object(raw.retry)) {
|
|
364
|
+
const { retry } = raw;
|
|
309
365
|
result.retry = { ...retry };
|
|
310
366
|
if (is.array(retry.errorCodes)) {
|
|
311
367
|
result.retry.errorCodes = [...retry.errorCodes];
|
|
@@ -317,10 +373,11 @@ const cloneRaw = (raw) => {
|
|
|
317
373
|
result.retry.statusCodes = [...retry.statusCodes];
|
|
318
374
|
}
|
|
319
375
|
}
|
|
320
|
-
if (is.object(raw.timeout)) {
|
|
376
|
+
if (Object.hasOwn(raw, 'timeout') && is.object(raw.timeout)) {
|
|
321
377
|
result.timeout = { ...raw.timeout };
|
|
322
378
|
}
|
|
323
|
-
if (is.object(hooks)) {
|
|
379
|
+
if (Object.hasOwn(raw, 'hooks') && is.object(raw.hooks)) {
|
|
380
|
+
const { hooks } = raw;
|
|
324
381
|
result.hooks = {
|
|
325
382
|
...hooks,
|
|
326
383
|
};
|
|
@@ -346,7 +403,7 @@ const cloneRaw = (raw) => {
|
|
|
346
403
|
result.hooks.afterResponse = [...hooks.afterResponse];
|
|
347
404
|
}
|
|
348
405
|
}
|
|
349
|
-
if (raw.searchParams) {
|
|
406
|
+
if (Object.hasOwn(raw, 'searchParams') && raw.searchParams) {
|
|
350
407
|
if (is.string(raw.searchParams)) {
|
|
351
408
|
result.searchParams = raw.searchParams;
|
|
352
409
|
}
|
|
@@ -357,17 +414,34 @@ const cloneRaw = (raw) => {
|
|
|
357
414
|
result.searchParams = { ...raw.searchParams };
|
|
358
415
|
}
|
|
359
416
|
}
|
|
360
|
-
if (is.object(raw.pagination)) {
|
|
417
|
+
if (Object.hasOwn(raw, 'pagination') && is.object(raw.pagination)) {
|
|
361
418
|
result.pagination = { ...raw.pagination };
|
|
362
419
|
}
|
|
363
420
|
return result;
|
|
364
421
|
};
|
|
365
422
|
const getHttp2TimeoutOption = (internals) => {
|
|
366
423
|
const delays = [internals.timeout.socket, internals.timeout.connect, internals.timeout.lookup, internals.timeout.request, internals.timeout.secureConnect].filter(delay => typeof delay === 'number');
|
|
367
|
-
|
|
368
|
-
|
|
424
|
+
return delays.length > 0 ? Math.min(...delays) : undefined;
|
|
425
|
+
};
|
|
426
|
+
const trackStateMutation = (trackedStateMutations, name) => {
|
|
427
|
+
trackedStateMutations?.add(name);
|
|
428
|
+
};
|
|
429
|
+
const addExplicitHeader = (explicitHeaders, name) => {
|
|
430
|
+
explicitHeaders.add(name);
|
|
431
|
+
};
|
|
432
|
+
const markHeaderAsExplicit = (explicitHeaders, trackedStateMutations, name) => {
|
|
433
|
+
addExplicitHeader(explicitHeaders, name);
|
|
434
|
+
trackStateMutation(trackedStateMutations, name);
|
|
435
|
+
};
|
|
436
|
+
const trackReplacedHeaderMutations = (trackedStateMutations, previousHeaders, nextHeaders) => {
|
|
437
|
+
if (!trackedStateMutations) {
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
for (const header of new Set([...Object.keys(previousHeaders), ...Object.keys(nextHeaders)])) {
|
|
441
|
+
if (previousHeaders[header] !== nextHeaders[header]) {
|
|
442
|
+
trackStateMutation(trackedStateMutations, header);
|
|
443
|
+
}
|
|
369
444
|
}
|
|
370
|
-
return undefined;
|
|
371
445
|
};
|
|
372
446
|
const init = (options, withOptions, self) => {
|
|
373
447
|
const initHooks = options.hooks?.init;
|
|
@@ -377,11 +451,15 @@ const init = (options, withOptions, self) => {
|
|
|
377
451
|
}
|
|
378
452
|
}
|
|
379
453
|
};
|
|
454
|
+
// Keys never merged: got.extend() internals, url (passed as first arg), control flags, security
|
|
455
|
+
const nonMergeableKeys = new Set(['mutableDefaults', 'handlers', 'url', 'preserveHooks', 'isStream', '__proto__']);
|
|
380
456
|
export default class Options {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
457
|
+
#internals;
|
|
458
|
+
#headersProxy;
|
|
459
|
+
#merging = false;
|
|
460
|
+
#init;
|
|
461
|
+
#explicitHeaders;
|
|
462
|
+
#trackedStateMutations;
|
|
385
463
|
constructor(input, options, defaults) {
|
|
386
464
|
assertAny('input', [is.string, is.urlInstance, is.object, is.undefined], input);
|
|
387
465
|
assertAny('options', [is.object, is.undefined], options);
|
|
@@ -389,8 +467,17 @@ export default class Options {
|
|
|
389
467
|
if (input instanceof Options || options instanceof Options) {
|
|
390
468
|
throw new TypeError('The defaults must be passed as the third argument');
|
|
391
469
|
}
|
|
392
|
-
|
|
393
|
-
|
|
470
|
+
if (defaults) {
|
|
471
|
+
this.#internals = cloneInternals(defaults.#internals);
|
|
472
|
+
this.#init = [...defaults.#init];
|
|
473
|
+
this.#explicitHeaders = new Set(defaults.#explicitHeaders);
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
this.#internals = cloneInternals(defaultInternals);
|
|
477
|
+
this.#init = [];
|
|
478
|
+
this.#explicitHeaders = new Set();
|
|
479
|
+
}
|
|
480
|
+
this.#headersProxy = this.#createHeadersProxy();
|
|
394
481
|
// This rule allows `finally` to be considered more important.
|
|
395
482
|
// Meaning no matter the error thrown in the `try` block,
|
|
396
483
|
// if `finally` throws then the `finally` error will be thrown.
|
|
@@ -440,9 +527,9 @@ export default class Options {
|
|
|
440
527
|
return;
|
|
441
528
|
}
|
|
442
529
|
if (options instanceof Options) {
|
|
443
|
-
// Create a copy of the
|
|
530
|
+
// Create a copy of the #init array to avoid infinite loop
|
|
444
531
|
// when merging an Options instance with itself
|
|
445
|
-
const initArray = [...options
|
|
532
|
+
const initArray = [...options.#init];
|
|
446
533
|
for (const init of initArray) {
|
|
447
534
|
this.merge(init);
|
|
448
535
|
}
|
|
@@ -451,24 +538,11 @@ export default class Options {
|
|
|
451
538
|
options = cloneRaw(options);
|
|
452
539
|
init(this, options, this);
|
|
453
540
|
init(options, options, this);
|
|
454
|
-
this
|
|
455
|
-
// Always merge `isStream` first
|
|
456
|
-
if ('isStream' in options) {
|
|
457
|
-
this.isStream = options.isStream;
|
|
458
|
-
}
|
|
541
|
+
this.#merging = true;
|
|
459
542
|
try {
|
|
460
543
|
let push = false;
|
|
461
|
-
for (const key
|
|
462
|
-
|
|
463
|
-
if (key === 'mutableDefaults' || key === 'handlers') {
|
|
464
|
-
continue;
|
|
465
|
-
}
|
|
466
|
-
// Never merge `url`
|
|
467
|
-
if (key === 'url') {
|
|
468
|
-
continue;
|
|
469
|
-
}
|
|
470
|
-
// Never merge `preserveHooks` - it's a control flag, not a persistent option
|
|
471
|
-
if (key === 'preserveHooks') {
|
|
544
|
+
for (const key of Object.keys(options)) {
|
|
545
|
+
if (nonMergeableKeys.has(key)) {
|
|
472
546
|
continue;
|
|
473
547
|
}
|
|
474
548
|
if (!(key in this)) {
|
|
@@ -484,11 +558,11 @@ export default class Options {
|
|
|
484
558
|
push = true;
|
|
485
559
|
}
|
|
486
560
|
if (push) {
|
|
487
|
-
this.
|
|
561
|
+
this.#init.push(options);
|
|
488
562
|
}
|
|
489
563
|
}
|
|
490
564
|
finally {
|
|
491
|
-
this
|
|
565
|
+
this.#merging = false;
|
|
492
566
|
}
|
|
493
567
|
}
|
|
494
568
|
/**
|
|
@@ -498,11 +572,11 @@ export default class Options {
|
|
|
498
572
|
@default http.request | https.request
|
|
499
573
|
*/
|
|
500
574
|
get request() {
|
|
501
|
-
return this.
|
|
575
|
+
return this.#internals.request;
|
|
502
576
|
}
|
|
503
577
|
set request(value) {
|
|
504
578
|
assertAny('request', [is.function, is.undefined], value);
|
|
505
|
-
this.
|
|
579
|
+
this.#internals.request = value;
|
|
506
580
|
}
|
|
507
581
|
/**
|
|
508
582
|
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.
|
|
@@ -527,47 +601,49 @@ export default class Options {
|
|
|
527
601
|
```
|
|
528
602
|
*/
|
|
529
603
|
get agent() {
|
|
530
|
-
return this.
|
|
604
|
+
return this.#internals.agent;
|
|
531
605
|
}
|
|
532
606
|
set agent(value) {
|
|
533
607
|
assertPlainObject('agent', value);
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
608
|
+
for (const key of Object.keys(value)) {
|
|
609
|
+
if (key === '__proto__') {
|
|
610
|
+
continue;
|
|
611
|
+
}
|
|
612
|
+
if (!(key in this.#internals.agent)) {
|
|
537
613
|
throw new TypeError(`Unexpected agent option: ${key}`);
|
|
538
614
|
}
|
|
539
615
|
// @ts-expect-error - No idea why `value[key]` doesn't work here.
|
|
540
616
|
assertAny(`agent.${key}`, [is.object, is.undefined, (v) => v === false], value[key]);
|
|
541
617
|
}
|
|
542
|
-
if (this
|
|
543
|
-
|
|
618
|
+
if (this.#merging) {
|
|
619
|
+
safeObjectAssign(this.#internals.agent, value);
|
|
544
620
|
}
|
|
545
621
|
else {
|
|
546
|
-
this.
|
|
622
|
+
this.#internals.agent = { ...value };
|
|
547
623
|
}
|
|
548
624
|
}
|
|
549
625
|
get h2session() {
|
|
550
|
-
return this.
|
|
626
|
+
return this.#internals.h2session;
|
|
551
627
|
}
|
|
552
628
|
set h2session(value) {
|
|
553
|
-
this.
|
|
629
|
+
this.#internals.h2session = value;
|
|
554
630
|
}
|
|
555
631
|
/**
|
|
556
632
|
Decompress the response automatically.
|
|
557
633
|
|
|
558
634
|
This will set the `accept-encoding` header to `gzip, deflate, br` unless you set it yourself.
|
|
559
635
|
|
|
560
|
-
If this is disabled, a compressed response is returned as a `
|
|
636
|
+
If this is disabled, a compressed response is returned as a `Uint8Array`.
|
|
561
637
|
This may be useful if you want to handle decompression yourself or stream the raw compressed data.
|
|
562
638
|
|
|
563
639
|
@default true
|
|
564
640
|
*/
|
|
565
641
|
get decompress() {
|
|
566
|
-
return this.
|
|
642
|
+
return this.#internals.decompress;
|
|
567
643
|
}
|
|
568
644
|
set decompress(value) {
|
|
569
645
|
assert.boolean(value);
|
|
570
|
-
this.
|
|
646
|
+
this.#internals.decompress = value;
|
|
571
647
|
}
|
|
572
648
|
/**
|
|
573
649
|
Milliseconds to wait for the server to end the response before aborting the request with `got.TimeoutError` error (a.k.a. `request` property).
|
|
@@ -587,23 +663,25 @@ export default class Options {
|
|
|
587
663
|
get timeout() {
|
|
588
664
|
// We always return `Delays` here.
|
|
589
665
|
// It has to be `Delays | number`, otherwise TypeScript will error because the getter and the setter have incompatible types.
|
|
590
|
-
return this.
|
|
666
|
+
return this.#internals.timeout;
|
|
591
667
|
}
|
|
592
668
|
set timeout(value) {
|
|
593
669
|
assertPlainObject('timeout', value);
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
670
|
+
for (const key of Object.keys(value)) {
|
|
671
|
+
if (key === '__proto__') {
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
674
|
+
if (!(key in this.#internals.timeout)) {
|
|
597
675
|
throw new Error(`Unexpected timeout option: ${key}`);
|
|
598
676
|
}
|
|
599
677
|
// @ts-expect-error - No idea why `value[key]` doesn't work here.
|
|
600
678
|
assertAny(`timeout.${key}`, [is.number, is.undefined], value[key]);
|
|
601
679
|
}
|
|
602
|
-
if (this
|
|
603
|
-
|
|
680
|
+
if (this.#merging) {
|
|
681
|
+
safeObjectAssign(this.#internals.timeout, value);
|
|
604
682
|
}
|
|
605
683
|
else {
|
|
606
|
-
this.
|
|
684
|
+
this.#internals.timeout = { ...value };
|
|
607
685
|
}
|
|
608
686
|
}
|
|
609
687
|
/**
|
|
@@ -648,23 +726,23 @@ export default class Options {
|
|
|
648
726
|
get prefixUrl() {
|
|
649
727
|
// We always return `string` here.
|
|
650
728
|
// It has to be `string | URL`, otherwise TypeScript will error because the getter and the setter have incompatible types.
|
|
651
|
-
return this.
|
|
729
|
+
return this.#internals.prefixUrl;
|
|
652
730
|
}
|
|
653
731
|
set prefixUrl(value) {
|
|
654
732
|
assertAny('prefixUrl', [is.string, is.urlInstance], value);
|
|
655
733
|
if (value === '') {
|
|
656
|
-
this.
|
|
734
|
+
this.#internals.prefixUrl = '';
|
|
657
735
|
return;
|
|
658
736
|
}
|
|
659
737
|
value = value.toString();
|
|
660
738
|
if (!value.endsWith('/')) {
|
|
661
739
|
value += '/';
|
|
662
740
|
}
|
|
663
|
-
if (this.
|
|
664
|
-
const { href } = this.
|
|
665
|
-
this.
|
|
741
|
+
if (this.#internals.prefixUrl && this.#internals.url) {
|
|
742
|
+
const { href } = this.#internals.url;
|
|
743
|
+
this.#internals.url.href = value + href.slice(this.#internals.prefixUrl.length);
|
|
666
744
|
}
|
|
667
|
-
this.
|
|
745
|
+
this.#internals.prefixUrl = value;
|
|
668
746
|
}
|
|
669
747
|
/**
|
|
670
748
|
__Note #1__: The `body` option cannot be used with the `json` or `form` option.
|
|
@@ -675,7 +753,7 @@ export default class Options {
|
|
|
675
753
|
|
|
676
754
|
__Note #4__: This option is not enumerable and will not be merged with the instance defaults.
|
|
677
755
|
|
|
678
|
-
The `content-length` header will be automatically set if `body` is a `string` / `
|
|
756
|
+
The `content-length` header will be automatically set if `body` is a `string` / `Uint8Array` / typed array, and `content-length` and `transfer-encoding` are not manually set in `options.headers`.
|
|
679
757
|
|
|
680
758
|
Since Got 12, the `content-length` is not automatically set when `body` is a `fs.createReadStream`.
|
|
681
759
|
|
|
@@ -697,18 +775,19 @@ export default class Options {
|
|
|
697
775
|
```
|
|
698
776
|
*/
|
|
699
777
|
get body() {
|
|
700
|
-
return this.
|
|
778
|
+
return this.#internals.body;
|
|
701
779
|
}
|
|
702
780
|
set body(value) {
|
|
703
|
-
assertAny('body', [is.string, is.buffer, is.nodeStream, is.generator, is.asyncGenerator, is.iterable, is.asyncIterable,
|
|
781
|
+
assertAny('body', [is.string, is.buffer, is.nodeStream, is.generator, is.asyncGenerator, is.iterable, is.asyncIterable, is.typedArray, is.undefined], value);
|
|
704
782
|
if (is.nodeStream(value)) {
|
|
705
783
|
assert.truthy(value.readable);
|
|
706
784
|
}
|
|
707
785
|
if (value !== undefined) {
|
|
708
|
-
assert.undefined(this.
|
|
709
|
-
assert.undefined(this.
|
|
786
|
+
assert.undefined(this.#internals.form);
|
|
787
|
+
assert.undefined(this.#internals.json);
|
|
710
788
|
}
|
|
711
|
-
this.
|
|
789
|
+
this.#internals.body = value;
|
|
790
|
+
trackStateMutation(this.#trackedStateMutations, 'body');
|
|
712
791
|
}
|
|
713
792
|
/**
|
|
714
793
|
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).
|
|
@@ -720,15 +799,16 @@ export default class Options {
|
|
|
720
799
|
__Note #2__: This option is not enumerable and will not be merged with the instance defaults.
|
|
721
800
|
*/
|
|
722
801
|
get form() {
|
|
723
|
-
return this.
|
|
802
|
+
return this.#internals.form;
|
|
724
803
|
}
|
|
725
804
|
set form(value) {
|
|
726
805
|
assertAny('form', [is.plainObject, is.undefined], value);
|
|
727
806
|
if (value !== undefined) {
|
|
728
|
-
assert.undefined(this.
|
|
729
|
-
assert.undefined(this.
|
|
807
|
+
assert.undefined(this.#internals.body);
|
|
808
|
+
assert.undefined(this.#internals.json);
|
|
730
809
|
}
|
|
731
|
-
this.
|
|
810
|
+
this.#internals.form = value;
|
|
811
|
+
trackStateMutation(this.#trackedStateMutations, 'form');
|
|
732
812
|
}
|
|
733
813
|
/**
|
|
734
814
|
JSON request body. If the `content-type` header is not set, it will be set to `application/json`.
|
|
@@ -740,14 +820,15 @@ export default class Options {
|
|
|
740
820
|
__Note #2__: This option is not enumerable and will not be merged with the instance defaults.
|
|
741
821
|
*/
|
|
742
822
|
get json() {
|
|
743
|
-
return this.
|
|
823
|
+
return this.#internals.json;
|
|
744
824
|
}
|
|
745
825
|
set json(value) {
|
|
746
826
|
if (value !== undefined) {
|
|
747
|
-
assert.undefined(this.
|
|
748
|
-
assert.undefined(this.
|
|
827
|
+
assert.undefined(this.#internals.body);
|
|
828
|
+
assert.undefined(this.#internals.form);
|
|
749
829
|
}
|
|
750
|
-
this.
|
|
830
|
+
this.#internals.json = value;
|
|
831
|
+
trackStateMutation(this.#trackedStateMutations, 'json');
|
|
751
832
|
}
|
|
752
833
|
/**
|
|
753
834
|
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).
|
|
@@ -768,24 +849,34 @@ export default class Options {
|
|
|
768
849
|
```
|
|
769
850
|
*/
|
|
770
851
|
get url() {
|
|
771
|
-
return this.
|
|
852
|
+
return this.#internals.url;
|
|
772
853
|
}
|
|
773
854
|
set url(value) {
|
|
774
855
|
assertAny('url', [is.string, is.urlInstance, is.undefined], value);
|
|
775
856
|
if (value === undefined) {
|
|
776
|
-
this.
|
|
857
|
+
this.#internals.url = undefined;
|
|
858
|
+
trackStateMutation(this.#trackedStateMutations, 'url');
|
|
777
859
|
return;
|
|
778
860
|
}
|
|
779
861
|
if (is.string(value) && value.startsWith('/')) {
|
|
780
862
|
throw new Error('`url` must not start with a slash');
|
|
781
863
|
}
|
|
782
|
-
// Detect if URL is already absolute (has a protocol/scheme)
|
|
783
864
|
const valueString = value.toString();
|
|
784
|
-
|
|
865
|
+
if (is.string(value)
|
|
866
|
+
&& !this.prefixUrl
|
|
867
|
+
&& hasHttpProtocolWithoutSlashes(valueString)) {
|
|
868
|
+
throw new Error('`url` protocol must be followed by `//`');
|
|
869
|
+
}
|
|
870
|
+
// Detect if URL is already absolute (has a protocol/scheme)
|
|
871
|
+
const isAbsolute = is.urlInstance(value) || hasProtocolSlashes(valueString);
|
|
785
872
|
// Only concatenate prefixUrl if the URL is relative
|
|
786
873
|
const urlString = isAbsolute ? valueString : `${this.prefixUrl}${valueString}`;
|
|
787
874
|
const url = new URL(urlString);
|
|
788
|
-
this.
|
|
875
|
+
this.#internals.url = url;
|
|
876
|
+
trackStateMutation(this.#trackedStateMutations, 'url');
|
|
877
|
+
if (usesUnixSocket(url) && !this.#internals.enableUnixSockets) {
|
|
878
|
+
throw new Error('Using UNIX domain sockets but option `enableUnixSockets` is not enabled');
|
|
879
|
+
}
|
|
789
880
|
if (url.protocol === 'unix:') {
|
|
790
881
|
url.href = `http://unix${url.pathname}${url.search}`;
|
|
791
882
|
}
|
|
@@ -794,37 +885,18 @@ export default class Options {
|
|
|
794
885
|
error.code = 'ERR_UNSUPPORTED_PROTOCOL';
|
|
795
886
|
throw error;
|
|
796
887
|
}
|
|
797
|
-
if (this.
|
|
798
|
-
url.username = this.
|
|
799
|
-
this.
|
|
888
|
+
if (this.#internals.username) {
|
|
889
|
+
url.username = this.#internals.username;
|
|
890
|
+
this.#internals.username = '';
|
|
800
891
|
}
|
|
801
|
-
if (this.
|
|
802
|
-
url.password = this.
|
|
803
|
-
this.
|
|
892
|
+
if (this.#internals.password) {
|
|
893
|
+
url.password = this.#internals.password;
|
|
894
|
+
this.#internals.password = '';
|
|
804
895
|
}
|
|
805
|
-
if (this.
|
|
806
|
-
url.search = this.
|
|
807
|
-
this.
|
|
808
|
-
}
|
|
809
|
-
if (url.hostname === 'unix') {
|
|
810
|
-
if (!this._internals.enableUnixSockets) {
|
|
811
|
-
throw new Error('Using UNIX domain sockets but option `enableUnixSockets` is not enabled');
|
|
812
|
-
}
|
|
813
|
-
const matches = /(?<socketPath>.+?):(?<path>.+)/.exec(`${url.pathname}${url.search}`);
|
|
814
|
-
if (matches?.groups) {
|
|
815
|
-
const { socketPath, path } = matches.groups;
|
|
816
|
-
this._unixOptions = {
|
|
817
|
-
socketPath,
|
|
818
|
-
path,
|
|
819
|
-
host: '',
|
|
820
|
-
};
|
|
821
|
-
}
|
|
822
|
-
else {
|
|
823
|
-
this._unixOptions = undefined;
|
|
824
|
-
}
|
|
825
|
-
return;
|
|
896
|
+
if (this.#internals.searchParams) {
|
|
897
|
+
url.search = this.#internals.searchParams.toString();
|
|
898
|
+
this.#internals.searchParams = undefined;
|
|
826
899
|
}
|
|
827
|
-
this._unixOptions = undefined;
|
|
828
900
|
}
|
|
829
901
|
/**
|
|
830
902
|
Cookie support. You don't have to care about parsing or how to store them.
|
|
@@ -832,12 +904,12 @@ export default class Options {
|
|
|
832
904
|
__Note__: If you provide this option, `options.headers.cookie` will be overridden.
|
|
833
905
|
*/
|
|
834
906
|
get cookieJar() {
|
|
835
|
-
return this.
|
|
907
|
+
return this.#internals.cookieJar;
|
|
836
908
|
}
|
|
837
909
|
set cookieJar(value) {
|
|
838
910
|
assertAny('cookieJar', [is.object, is.undefined], value);
|
|
839
911
|
if (value === undefined) {
|
|
840
|
-
this.
|
|
912
|
+
this.#internals.cookieJar = undefined;
|
|
841
913
|
return;
|
|
842
914
|
}
|
|
843
915
|
let { setCookie, getCookieString } = value;
|
|
@@ -847,13 +919,13 @@ export default class Options {
|
|
|
847
919
|
if (setCookie.length === 4 && getCookieString.length === 0) {
|
|
848
920
|
setCookie = promisify(setCookie.bind(value));
|
|
849
921
|
getCookieString = promisify(getCookieString.bind(value));
|
|
850
|
-
this.
|
|
922
|
+
this.#internals.cookieJar = {
|
|
851
923
|
setCookie,
|
|
852
924
|
getCookieString: getCookieString,
|
|
853
925
|
};
|
|
854
926
|
}
|
|
855
927
|
else {
|
|
856
|
-
this.
|
|
928
|
+
this.#internals.cookieJar = value;
|
|
857
929
|
}
|
|
858
930
|
}
|
|
859
931
|
/**
|
|
@@ -875,11 +947,11 @@ export default class Options {
|
|
|
875
947
|
```
|
|
876
948
|
*/
|
|
877
949
|
get signal() {
|
|
878
|
-
return this.
|
|
950
|
+
return this.#internals.signal;
|
|
879
951
|
}
|
|
880
952
|
set signal(value) {
|
|
881
|
-
|
|
882
|
-
this.
|
|
953
|
+
assertAny('signal', [is.object, is.undefined], value);
|
|
954
|
+
this.#internals.signal = value;
|
|
883
955
|
}
|
|
884
956
|
/**
|
|
885
957
|
Ignore invalid cookies instead of throwing an error.
|
|
@@ -888,11 +960,11 @@ export default class Options {
|
|
|
888
960
|
@default false
|
|
889
961
|
*/
|
|
890
962
|
get ignoreInvalidCookies() {
|
|
891
|
-
return this.
|
|
963
|
+
return this.#internals.ignoreInvalidCookies;
|
|
892
964
|
}
|
|
893
965
|
set ignoreInvalidCookies(value) {
|
|
894
966
|
assert.boolean(value);
|
|
895
|
-
this.
|
|
967
|
+
this.#internals.ignoreInvalidCookies = value;
|
|
896
968
|
}
|
|
897
969
|
/**
|
|
898
970
|
Query string that will be added to the request URL.
|
|
@@ -913,19 +985,17 @@ export default class Options {
|
|
|
913
985
|
```
|
|
914
986
|
*/
|
|
915
987
|
get searchParams() {
|
|
916
|
-
if (this.
|
|
917
|
-
return this.
|
|
988
|
+
if (this.#internals.url) {
|
|
989
|
+
return this.#internals.url.searchParams;
|
|
918
990
|
}
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
}
|
|
922
|
-
return this._internals.searchParams;
|
|
991
|
+
this.#internals.searchParams ??= new URLSearchParams();
|
|
992
|
+
return this.#internals.searchParams;
|
|
923
993
|
}
|
|
924
994
|
set searchParams(value) {
|
|
925
995
|
assertAny('searchParams', [is.string, is.object, is.undefined], value);
|
|
926
|
-
const url = this.
|
|
996
|
+
const url = this.#internals.url;
|
|
927
997
|
if (value === undefined) {
|
|
928
|
-
this.
|
|
998
|
+
this.#internals.searchParams = undefined;
|
|
929
999
|
if (url) {
|
|
930
1000
|
url.search = '';
|
|
931
1001
|
}
|
|
@@ -942,8 +1012,10 @@ export default class Options {
|
|
|
942
1012
|
else {
|
|
943
1013
|
validateSearchParameters(value);
|
|
944
1014
|
updated = new URLSearchParams();
|
|
945
|
-
|
|
946
|
-
|
|
1015
|
+
for (const key of Object.keys(value)) {
|
|
1016
|
+
if (key === '__proto__') {
|
|
1017
|
+
continue;
|
|
1018
|
+
}
|
|
947
1019
|
const entry = value[key];
|
|
948
1020
|
if (entry === null) {
|
|
949
1021
|
updated.append(key, '');
|
|
@@ -956,7 +1028,7 @@ export default class Options {
|
|
|
956
1028
|
}
|
|
957
1029
|
}
|
|
958
1030
|
}
|
|
959
|
-
if (this
|
|
1031
|
+
if (this.#merging) {
|
|
960
1032
|
// These keys will be replaced
|
|
961
1033
|
for (const key of updated.keys()) {
|
|
962
1034
|
searchParameters.delete(key);
|
|
@@ -969,7 +1041,7 @@ export default class Options {
|
|
|
969
1041
|
url.search = searchParameters.toString();
|
|
970
1042
|
}
|
|
971
1043
|
else {
|
|
972
|
-
this.
|
|
1044
|
+
this.#internals.searchParams = searchParameters;
|
|
973
1045
|
}
|
|
974
1046
|
}
|
|
975
1047
|
get searchParameters() {
|
|
@@ -979,11 +1051,11 @@ export default class Options {
|
|
|
979
1051
|
throw new Error('The `searchParameters` option does not exist. Use `searchParams` instead.');
|
|
980
1052
|
}
|
|
981
1053
|
get dnsLookup() {
|
|
982
|
-
return this.
|
|
1054
|
+
return this.#internals.dnsLookup;
|
|
983
1055
|
}
|
|
984
1056
|
set dnsLookup(value) {
|
|
985
1057
|
assertAny('dnsLookup', [is.function, is.undefined], value);
|
|
986
|
-
this.
|
|
1058
|
+
this.#internals.dnsLookup = value;
|
|
987
1059
|
}
|
|
988
1060
|
/**
|
|
989
1061
|
An instance of [`CacheableLookup`](https://github.com/szmarczak/cacheable-lookup) used for making DNS lookups.
|
|
@@ -996,18 +1068,18 @@ export default class Options {
|
|
|
996
1068
|
@default false
|
|
997
1069
|
*/
|
|
998
1070
|
get dnsCache() {
|
|
999
|
-
return this.
|
|
1071
|
+
return this.#internals.dnsCache;
|
|
1000
1072
|
}
|
|
1001
1073
|
set dnsCache(value) {
|
|
1002
1074
|
assertAny('dnsCache', [is.object, is.boolean, is.undefined], value);
|
|
1003
1075
|
if (value === true) {
|
|
1004
|
-
this.
|
|
1076
|
+
this.#internals.dnsCache = getGlobalDnsCache();
|
|
1005
1077
|
}
|
|
1006
1078
|
else if (value === false) {
|
|
1007
|
-
this.
|
|
1079
|
+
this.#internals.dnsCache = undefined;
|
|
1008
1080
|
}
|
|
1009
1081
|
else {
|
|
1010
|
-
this.
|
|
1082
|
+
this.#internals.dnsCache = value;
|
|
1011
1083
|
}
|
|
1012
1084
|
}
|
|
1013
1085
|
/**
|
|
@@ -1042,15 +1114,15 @@ export default class Options {
|
|
|
1042
1114
|
```
|
|
1043
1115
|
*/
|
|
1044
1116
|
get context() {
|
|
1045
|
-
return this.
|
|
1117
|
+
return this.#internals.context;
|
|
1046
1118
|
}
|
|
1047
1119
|
set context(value) {
|
|
1048
1120
|
assert.object(value);
|
|
1049
|
-
if (this
|
|
1050
|
-
|
|
1121
|
+
if (this.#merging) {
|
|
1122
|
+
safeObjectAssign(this.#internals.context, value);
|
|
1051
1123
|
}
|
|
1052
1124
|
else {
|
|
1053
|
-
this.
|
|
1125
|
+
this.#internals.context = { ...value };
|
|
1054
1126
|
}
|
|
1055
1127
|
}
|
|
1056
1128
|
/**
|
|
@@ -1058,13 +1130,15 @@ export default class Options {
|
|
|
1058
1130
|
Hook functions may be async and are run serially.
|
|
1059
1131
|
*/
|
|
1060
1132
|
get hooks() {
|
|
1061
|
-
return this.
|
|
1133
|
+
return this.#internals.hooks;
|
|
1062
1134
|
}
|
|
1063
1135
|
set hooks(value) {
|
|
1064
1136
|
assert.object(value);
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1137
|
+
for (const knownHookEvent of Object.keys(value)) {
|
|
1138
|
+
if (knownHookEvent === '__proto__') {
|
|
1139
|
+
continue;
|
|
1140
|
+
}
|
|
1141
|
+
if (!(knownHookEvent in this.#internals.hooks)) {
|
|
1068
1142
|
throw new Error(`Unexpected hook event: ${knownHookEvent}`);
|
|
1069
1143
|
}
|
|
1070
1144
|
const typedKnownHookEvent = knownHookEvent;
|
|
@@ -1075,10 +1149,10 @@ export default class Options {
|
|
|
1075
1149
|
assert.function(hook);
|
|
1076
1150
|
}
|
|
1077
1151
|
}
|
|
1078
|
-
if (this
|
|
1152
|
+
if (this.#merging) {
|
|
1079
1153
|
if (hooks) {
|
|
1080
1154
|
// @ts-expect-error FIXME
|
|
1081
|
-
this.
|
|
1155
|
+
this.#internals.hooks[typedKnownHookEvent].push(...hooks);
|
|
1082
1156
|
}
|
|
1083
1157
|
}
|
|
1084
1158
|
else {
|
|
@@ -1086,7 +1160,7 @@ export default class Options {
|
|
|
1086
1160
|
throw new Error(`Missing hook event: ${knownHookEvent}`);
|
|
1087
1161
|
}
|
|
1088
1162
|
// @ts-expect-error FIXME
|
|
1089
|
-
this.
|
|
1163
|
+
this.#internals.hooks[knownHookEvent] = [...hooks];
|
|
1090
1164
|
}
|
|
1091
1165
|
}
|
|
1092
1166
|
}
|
|
@@ -1097,15 +1171,16 @@ export default class Options {
|
|
|
1097
1171
|
|
|
1098
1172
|
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`.
|
|
1099
1173
|
This is in accordance with [the spec](https://tools.ietf.org/html/rfc7231#section-6.4.4). You can optionally turn on this behavior also for other redirect codes - see `methodRewriting`.
|
|
1174
|
+
On cross-origin redirects, Got strips `host`, `cookie`, `cookie2`, `authorization`, and `proxy-authorization`. When a redirect rewrites the request to `GET`, Got also strips request body headers. Use `hooks.beforeRedirect` for app-specific sensitive headers.
|
|
1100
1175
|
|
|
1101
1176
|
@default true
|
|
1102
1177
|
*/
|
|
1103
1178
|
get followRedirect() {
|
|
1104
|
-
return this.
|
|
1179
|
+
return this.#internals.followRedirect;
|
|
1105
1180
|
}
|
|
1106
1181
|
set followRedirect(value) {
|
|
1107
1182
|
assertAny('followRedirect', [is.boolean, is.function], value);
|
|
1108
|
-
this.
|
|
1183
|
+
this.#internals.followRedirect = value;
|
|
1109
1184
|
}
|
|
1110
1185
|
get followRedirects() {
|
|
1111
1186
|
throw new TypeError('The `followRedirects` option does not exist. Use `followRedirect` instead.');
|
|
@@ -1119,11 +1194,11 @@ export default class Options {
|
|
|
1119
1194
|
@default 10
|
|
1120
1195
|
*/
|
|
1121
1196
|
get maxRedirects() {
|
|
1122
|
-
return this.
|
|
1197
|
+
return this.#internals.maxRedirects;
|
|
1123
1198
|
}
|
|
1124
1199
|
set maxRedirects(value) {
|
|
1125
1200
|
assert.number(value);
|
|
1126
|
-
this.
|
|
1201
|
+
this.#internals.maxRedirects = value;
|
|
1127
1202
|
}
|
|
1128
1203
|
/**
|
|
1129
1204
|
A cache adapter instance for storing cached response data.
|
|
@@ -1131,18 +1206,18 @@ export default class Options {
|
|
|
1131
1206
|
@default false
|
|
1132
1207
|
*/
|
|
1133
1208
|
get cache() {
|
|
1134
|
-
return this.
|
|
1209
|
+
return this.#internals.cache;
|
|
1135
1210
|
}
|
|
1136
1211
|
set cache(value) {
|
|
1137
1212
|
assertAny('cache', [is.object, is.string, is.boolean, is.undefined], value);
|
|
1138
1213
|
if (value === true) {
|
|
1139
|
-
this.
|
|
1214
|
+
this.#internals.cache = globalCache;
|
|
1140
1215
|
}
|
|
1141
1216
|
else if (value === false) {
|
|
1142
|
-
this.
|
|
1217
|
+
this.#internals.cache = undefined;
|
|
1143
1218
|
}
|
|
1144
1219
|
else {
|
|
1145
|
-
this.
|
|
1220
|
+
this.#internals.cache = wrapQuickLruIfNeeded(value);
|
|
1146
1221
|
}
|
|
1147
1222
|
}
|
|
1148
1223
|
/**
|
|
@@ -1154,43 +1229,45 @@ export default class Options {
|
|
|
1154
1229
|
@default true
|
|
1155
1230
|
*/
|
|
1156
1231
|
get throwHttpErrors() {
|
|
1157
|
-
return this.
|
|
1232
|
+
return this.#internals.throwHttpErrors;
|
|
1158
1233
|
}
|
|
1159
1234
|
set throwHttpErrors(value) {
|
|
1160
1235
|
assert.boolean(value);
|
|
1161
|
-
this.
|
|
1236
|
+
this.#internals.throwHttpErrors = value;
|
|
1162
1237
|
}
|
|
1163
1238
|
get username() {
|
|
1164
|
-
const url = this.
|
|
1165
|
-
const value = url ? url.username : this.
|
|
1239
|
+
const url = this.#internals.url;
|
|
1240
|
+
const value = url ? url.username : this.#internals.username;
|
|
1166
1241
|
return decodeURIComponent(value);
|
|
1167
1242
|
}
|
|
1168
1243
|
set username(value) {
|
|
1169
1244
|
assert.string(value);
|
|
1170
|
-
const url = this.
|
|
1245
|
+
const url = this.#internals.url;
|
|
1171
1246
|
const fixedValue = encodeURIComponent(value);
|
|
1172
1247
|
if (url) {
|
|
1173
1248
|
url.username = fixedValue;
|
|
1174
1249
|
}
|
|
1175
1250
|
else {
|
|
1176
|
-
this.
|
|
1251
|
+
this.#internals.username = fixedValue;
|
|
1177
1252
|
}
|
|
1253
|
+
trackStateMutation(this.#trackedStateMutations, 'username');
|
|
1178
1254
|
}
|
|
1179
1255
|
get password() {
|
|
1180
|
-
const url = this.
|
|
1181
|
-
const value = url ? url.password : this.
|
|
1256
|
+
const url = this.#internals.url;
|
|
1257
|
+
const value = url ? url.password : this.#internals.password;
|
|
1182
1258
|
return decodeURIComponent(value);
|
|
1183
1259
|
}
|
|
1184
1260
|
set password(value) {
|
|
1185
1261
|
assert.string(value);
|
|
1186
|
-
const url = this.
|
|
1262
|
+
const url = this.#internals.url;
|
|
1187
1263
|
const fixedValue = encodeURIComponent(value);
|
|
1188
1264
|
if (url) {
|
|
1189
1265
|
url.password = fixedValue;
|
|
1190
1266
|
}
|
|
1191
1267
|
else {
|
|
1192
|
-
this.
|
|
1268
|
+
this.#internals.password = fixedValue;
|
|
1193
1269
|
}
|
|
1270
|
+
trackStateMutation(this.#trackedStateMutations, 'password');
|
|
1194
1271
|
}
|
|
1195
1272
|
/**
|
|
1196
1273
|
If set to `true`, Got will additionally accept HTTP2 requests.
|
|
@@ -1214,11 +1291,11 @@ export default class Options {
|
|
|
1214
1291
|
```
|
|
1215
1292
|
*/
|
|
1216
1293
|
get http2() {
|
|
1217
|
-
return this.
|
|
1294
|
+
return this.#internals.http2;
|
|
1218
1295
|
}
|
|
1219
1296
|
set http2(value) {
|
|
1220
1297
|
assert.boolean(value);
|
|
1221
|
-
this.
|
|
1298
|
+
this.#internals.http2 = value;
|
|
1222
1299
|
}
|
|
1223
1300
|
/**
|
|
1224
1301
|
Set this to `true` to allow sending body for the `GET` method.
|
|
@@ -1230,36 +1307,35 @@ export default class Options {
|
|
|
1230
1307
|
@default false
|
|
1231
1308
|
*/
|
|
1232
1309
|
get allowGetBody() {
|
|
1233
|
-
return this.
|
|
1310
|
+
return this.#internals.allowGetBody;
|
|
1234
1311
|
}
|
|
1235
1312
|
set allowGetBody(value) {
|
|
1236
1313
|
assert.boolean(value);
|
|
1237
|
-
this.
|
|
1314
|
+
this.#internals.allowGetBody = value;
|
|
1238
1315
|
}
|
|
1239
1316
|
/**
|
|
1240
1317
|
Automatically copy headers from piped streams.
|
|
1241
1318
|
|
|
1242
1319
|
When piping a request into a Got stream (e.g., `request.pipe(got.stream(url))`), this controls whether headers from the source stream are automatically merged into the Got request headers.
|
|
1243
1320
|
|
|
1244
|
-
Note:
|
|
1321
|
+
Note: Explicitly set headers take precedence over piped headers. Piped headers are only copied when a header is not already explicitly set.
|
|
1245
1322
|
|
|
1246
|
-
Useful for proxy scenarios, but you may want to
|
|
1323
|
+
Useful for proxy scenarios when explicitly enabled, but you may still want to filter out headers like `Host`, `Connection`, `Authorization`, etc.
|
|
1247
1324
|
|
|
1248
|
-
@default
|
|
1325
|
+
@default false
|
|
1249
1326
|
|
|
1250
1327
|
@example
|
|
1251
1328
|
```
|
|
1252
1329
|
import got from 'got';
|
|
1253
1330
|
import {pipeline} from 'node:stream/promises';
|
|
1254
1331
|
|
|
1255
|
-
//
|
|
1332
|
+
// Opt in to automatic header copying for proxy scenarios
|
|
1256
1333
|
server.get('/proxy', async (request, response) => {
|
|
1257
1334
|
const gotStream = got.stream('https://example.com', {
|
|
1258
|
-
copyPipedHeaders:
|
|
1335
|
+
copyPipedHeaders: true,
|
|
1336
|
+
// Explicit headers win over piped headers
|
|
1259
1337
|
headers: {
|
|
1260
|
-
|
|
1261
|
-
'accept': request.headers['accept'],
|
|
1262
|
-
// Explicitly NOT copying host, connection, authorization, etc.
|
|
1338
|
+
host: 'example.com',
|
|
1263
1339
|
}
|
|
1264
1340
|
});
|
|
1265
1341
|
|
|
@@ -1270,27 +1346,114 @@ export default class Options {
|
|
|
1270
1346
|
@example
|
|
1271
1347
|
```
|
|
1272
1348
|
import got from 'got';
|
|
1349
|
+
import {pipeline} from 'node:stream/promises';
|
|
1273
1350
|
|
|
1274
|
-
//
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1351
|
+
// Keep it disabled and manually copy only safe headers
|
|
1352
|
+
server.get('/proxy', async (request, response) => {
|
|
1353
|
+
const gotStream = got.stream('https://example.com', {
|
|
1354
|
+
headers: {
|
|
1355
|
+
'user-agent': request.headers['user-agent'],
|
|
1356
|
+
'accept': request.headers['accept'],
|
|
1357
|
+
// Explicitly NOT copying host, connection, authorization, etc.
|
|
1358
|
+
}
|
|
1359
|
+
});
|
|
1360
|
+
|
|
1361
|
+
await pipeline(request, gotStream, response);
|
|
1285
1362
|
});
|
|
1286
1363
|
```
|
|
1287
1364
|
*/
|
|
1288
1365
|
get copyPipedHeaders() {
|
|
1289
|
-
return this.
|
|
1366
|
+
return this.#internals.copyPipedHeaders;
|
|
1290
1367
|
}
|
|
1291
1368
|
set copyPipedHeaders(value) {
|
|
1292
1369
|
assert.boolean(value);
|
|
1293
|
-
this.
|
|
1370
|
+
this.#internals.copyPipedHeaders = value;
|
|
1371
|
+
}
|
|
1372
|
+
isHeaderExplicitlySet(name) {
|
|
1373
|
+
return this.#explicitHeaders.has(name.toLowerCase());
|
|
1374
|
+
}
|
|
1375
|
+
shouldCopyPipedHeader(name) {
|
|
1376
|
+
return !this.isHeaderExplicitlySet(name);
|
|
1377
|
+
}
|
|
1378
|
+
setPipedHeader(name, value) {
|
|
1379
|
+
assertValidHeaderName(name);
|
|
1380
|
+
this.#internals.headers[name.toLowerCase()] = value;
|
|
1381
|
+
}
|
|
1382
|
+
getInternalHeaders() {
|
|
1383
|
+
return this.#internals.headers;
|
|
1384
|
+
}
|
|
1385
|
+
setInternalHeader(name, value) {
|
|
1386
|
+
assertValidHeaderName(name);
|
|
1387
|
+
this.#internals.headers[name.toLowerCase()] = value;
|
|
1388
|
+
}
|
|
1389
|
+
deleteInternalHeader(name) {
|
|
1390
|
+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
1391
|
+
delete this.#internals.headers[name.toLowerCase()];
|
|
1392
|
+
}
|
|
1393
|
+
async trackStateMutations(operation) {
|
|
1394
|
+
const changedState = new Set();
|
|
1395
|
+
this.#trackedStateMutations = changedState;
|
|
1396
|
+
try {
|
|
1397
|
+
return await operation(changedState);
|
|
1398
|
+
}
|
|
1399
|
+
finally {
|
|
1400
|
+
this.#trackedStateMutations = undefined;
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
clearBody() {
|
|
1404
|
+
this.body = undefined;
|
|
1405
|
+
this.json = undefined;
|
|
1406
|
+
this.form = undefined;
|
|
1407
|
+
for (const header of bodyHeaderNames) {
|
|
1408
|
+
this.deleteInternalHeader(header);
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
stripUnchangedCrossOriginState(previousState, changedState, { clearBody = true } = {}) {
|
|
1412
|
+
const headers = this.getInternalHeaders();
|
|
1413
|
+
const url = this.#internals.url;
|
|
1414
|
+
for (const header of crossOriginStripHeaders) {
|
|
1415
|
+
if (!changedState.has(header) && headers[header] === previousState.headers[header]) {
|
|
1416
|
+
this.deleteInternalHeader(header);
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
if (!hasExplicitCredentialInUrlChange(changedState, url, 'username')) {
|
|
1420
|
+
this.username = '';
|
|
1421
|
+
}
|
|
1422
|
+
if (!hasExplicitCredentialInUrlChange(changedState, url, 'password')) {
|
|
1423
|
+
this.password = '';
|
|
1424
|
+
}
|
|
1425
|
+
if (clearBody && !changedState.has('body') && !changedState.has('json') && !changedState.has('form') && isBodyUnchanged(this, previousState)) {
|
|
1426
|
+
this.clearBody();
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
/**
|
|
1430
|
+
Strip sensitive headers and credentials when navigating to a different origin.
|
|
1431
|
+
Headers and credentials explicitly provided in `userOptions` are preserved.
|
|
1432
|
+
*/
|
|
1433
|
+
stripSensitiveHeaders(previousUrl, nextUrl, userOptions) {
|
|
1434
|
+
if (isSameOrigin(previousUrl, nextUrl)) {
|
|
1435
|
+
return;
|
|
1436
|
+
}
|
|
1437
|
+
const headers = lowercaseKeys(userOptions.headers ?? {});
|
|
1438
|
+
for (const header of crossOriginStripHeaders) {
|
|
1439
|
+
if (headers[header] === undefined) {
|
|
1440
|
+
this.deleteInternalHeader(header);
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
const explicitUsername = Object.hasOwn(userOptions, 'username') ? userOptions.username : undefined;
|
|
1444
|
+
const explicitPassword = Object.hasOwn(userOptions, 'password') ? userOptions.password : undefined;
|
|
1445
|
+
const hasExplicitUsername = explicitUsername !== undefined
|
|
1446
|
+
|| hasCredentialInUrl(userOptions.url, 'username')
|
|
1447
|
+
|| isCrossOriginCredentialChanged(previousUrl, nextUrl, 'username');
|
|
1448
|
+
const hasExplicitPassword = explicitPassword !== undefined
|
|
1449
|
+
|| hasCredentialInUrl(userOptions.url, 'password')
|
|
1450
|
+
|| isCrossOriginCredentialChanged(previousUrl, nextUrl, 'password');
|
|
1451
|
+
if (!hasExplicitUsername && this.username) {
|
|
1452
|
+
this.username = '';
|
|
1453
|
+
}
|
|
1454
|
+
if (!hasExplicitPassword && this.password) {
|
|
1455
|
+
this.password = '';
|
|
1456
|
+
}
|
|
1294
1457
|
}
|
|
1295
1458
|
/**
|
|
1296
1459
|
Request headers.
|
|
@@ -1300,33 +1463,49 @@ export default class Options {
|
|
|
1300
1463
|
@default {}
|
|
1301
1464
|
*/
|
|
1302
1465
|
get headers() {
|
|
1303
|
-
return this
|
|
1466
|
+
return this.#headersProxy;
|
|
1304
1467
|
}
|
|
1305
1468
|
set headers(value) {
|
|
1306
1469
|
assertPlainObject('headers', value);
|
|
1307
|
-
|
|
1308
|
-
|
|
1470
|
+
const normalizedHeaders = lowercaseKeys(value);
|
|
1471
|
+
for (const header of Object.keys(normalizedHeaders)) {
|
|
1472
|
+
assertValidHeaderName(header);
|
|
1473
|
+
}
|
|
1474
|
+
if (this.#merging) {
|
|
1475
|
+
safeObjectAssign(this.#internals.headers, normalizedHeaders);
|
|
1309
1476
|
}
|
|
1310
1477
|
else {
|
|
1311
|
-
this.
|
|
1478
|
+
const previousHeaders = this.#internals.headers;
|
|
1479
|
+
this.#internals.headers = normalizedHeaders;
|
|
1480
|
+
this.#headersProxy = this.#createHeadersProxy();
|
|
1481
|
+
this.#explicitHeaders.clear();
|
|
1482
|
+
trackReplacedHeaderMutations(this.#trackedStateMutations, previousHeaders, normalizedHeaders);
|
|
1483
|
+
}
|
|
1484
|
+
for (const header of Object.keys(normalizedHeaders)) {
|
|
1485
|
+
if (this.#merging) {
|
|
1486
|
+
markHeaderAsExplicit(this.#explicitHeaders, this.#trackedStateMutations, header);
|
|
1487
|
+
}
|
|
1488
|
+
else {
|
|
1489
|
+
addExplicitHeader(this.#explicitHeaders, header);
|
|
1490
|
+
}
|
|
1312
1491
|
}
|
|
1313
1492
|
}
|
|
1314
1493
|
/**
|
|
1315
1494
|
Specifies if the HTTP request method should be [rewritten as `GET`](https://tools.ietf.org/html/rfc7231#section-6.4) on redirects.
|
|
1316
1495
|
|
|
1317
|
-
As the [specification](https://tools.ietf.org/html/rfc7231#section-6.4) prefers to rewrite the HTTP method only on `303` responses, this is Got's default behavior.
|
|
1318
|
-
Setting `methodRewriting` to `true` will also rewrite `301` and `302` responses, as allowed by the spec. This is the behavior followed by `curl` and browsers.
|
|
1496
|
+
As the [specification](https://tools.ietf.org/html/rfc7231#section-6.4) prefers to rewrite the HTTP method only on `303` responses, this is Got's default behavior. Cross-origin `301` and `302` redirects also rewrite `POST` requests to `GET` by default to avoid forwarding request bodies to another origin.
|
|
1497
|
+
Setting `methodRewriting` to `true` will also rewrite same-origin `301` and `302` responses, as allowed by the spec. This is the behavior followed by `curl` and browsers.
|
|
1319
1498
|
|
|
1320
1499
|
__Note__: Got never performs method rewriting on `307` and `308` responses, as this is [explicitly prohibited by the specification](https://www.rfc-editor.org/rfc/rfc7231#section-6.4.7).
|
|
1321
1500
|
|
|
1322
1501
|
@default false
|
|
1323
1502
|
*/
|
|
1324
1503
|
get methodRewriting() {
|
|
1325
|
-
return this.
|
|
1504
|
+
return this.#internals.methodRewriting;
|
|
1326
1505
|
}
|
|
1327
1506
|
set methodRewriting(value) {
|
|
1328
1507
|
assert.boolean(value);
|
|
1329
|
-
this.
|
|
1508
|
+
this.#internals.methodRewriting = value;
|
|
1330
1509
|
}
|
|
1331
1510
|
/**
|
|
1332
1511
|
Indicates which DNS record family to use.
|
|
@@ -1339,13 +1518,13 @@ export default class Options {
|
|
|
1339
1518
|
@default undefined
|
|
1340
1519
|
*/
|
|
1341
1520
|
get dnsLookupIpVersion() {
|
|
1342
|
-
return this.
|
|
1521
|
+
return this.#internals.dnsLookupIpVersion;
|
|
1343
1522
|
}
|
|
1344
1523
|
set dnsLookupIpVersion(value) {
|
|
1345
1524
|
if (value !== undefined && value !== 4 && value !== 6) {
|
|
1346
1525
|
throw new TypeError(`Invalid DNS lookup IP version: ${value}`);
|
|
1347
1526
|
}
|
|
1348
|
-
this.
|
|
1527
|
+
this.#internals.dnsLookupIpVersion = value;
|
|
1349
1528
|
}
|
|
1350
1529
|
/**
|
|
1351
1530
|
A function used to parse JSON responses.
|
|
@@ -1363,11 +1542,11 @@ export default class Options {
|
|
|
1363
1542
|
```
|
|
1364
1543
|
*/
|
|
1365
1544
|
get parseJson() {
|
|
1366
|
-
return this.
|
|
1545
|
+
return this.#internals.parseJson;
|
|
1367
1546
|
}
|
|
1368
1547
|
set parseJson(value) {
|
|
1369
1548
|
assert.function(value);
|
|
1370
|
-
this.
|
|
1549
|
+
this.#internals.parseJson = value;
|
|
1371
1550
|
}
|
|
1372
1551
|
/**
|
|
1373
1552
|
A function used to stringify the body of JSON requests.
|
|
@@ -1411,11 +1590,11 @@ export default class Options {
|
|
|
1411
1590
|
```
|
|
1412
1591
|
*/
|
|
1413
1592
|
get stringifyJson() {
|
|
1414
|
-
return this.
|
|
1593
|
+
return this.#internals.stringifyJson;
|
|
1415
1594
|
}
|
|
1416
1595
|
set stringifyJson(value) {
|
|
1417
1596
|
assert.function(value);
|
|
1418
|
-
this.
|
|
1597
|
+
this.#internals.stringifyJson = value;
|
|
1419
1598
|
}
|
|
1420
1599
|
/**
|
|
1421
1600
|
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.
|
|
@@ -1425,9 +1604,9 @@ export default class Options {
|
|
|
1425
1604
|
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.
|
|
1426
1605
|
The function must return a delay in milliseconds (or a Promise resolving with it) (`0` return value cancels retry).
|
|
1427
1606
|
|
|
1428
|
-
The `enforceRetryRules` property is a `boolean` that, when set to `true
|
|
1607
|
+
The `enforceRetryRules` property is a `boolean` that, when set to `true` (default), enforces the `limit`, `methods`, `statusCodes`, and `errorCodes` options before calling `calculateDelay`. Your `calculateDelay` function is only invoked when a retry is allowed based on these criteria. When `false`, `calculateDelay` receives the computed value but can override all retry logic.
|
|
1429
1608
|
|
|
1430
|
-
__Note:__ When `enforceRetryRules` is `false`, you must check `computedValue` in your `calculateDelay` function to respect
|
|
1609
|
+
__Note:__ When `enforceRetryRules` is `false`, you must check `computedValue` in your `calculateDelay` function to respect retry rules. When `true` (default), the retry rules are enforced automatically.
|
|
1431
1610
|
|
|
1432
1611
|
By default, it retries *only* on the specified methods, status codes, and on these network errors:
|
|
1433
1612
|
|
|
@@ -1444,7 +1623,7 @@ export default class Options {
|
|
|
1444
1623
|
__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.
|
|
1445
1624
|
*/
|
|
1446
1625
|
get retry() {
|
|
1447
|
-
return this.
|
|
1626
|
+
return this.#internals.retry;
|
|
1448
1627
|
}
|
|
1449
1628
|
set retry(value) {
|
|
1450
1629
|
assertPlainObject('retry', value);
|
|
@@ -1459,18 +1638,21 @@ export default class Options {
|
|
|
1459
1638
|
if (value.noise && Math.abs(value.noise) > 100) {
|
|
1460
1639
|
throw new Error(`The maximum acceptable retry noise is +/- 100ms, got ${value.noise}`);
|
|
1461
1640
|
}
|
|
1462
|
-
for (const key
|
|
1463
|
-
if (
|
|
1641
|
+
for (const key of Object.keys(value)) {
|
|
1642
|
+
if (key === '__proto__') {
|
|
1643
|
+
continue;
|
|
1644
|
+
}
|
|
1645
|
+
if (!(key in this.#internals.retry)) {
|
|
1464
1646
|
throw new Error(`Unexpected retry option: ${key}`);
|
|
1465
1647
|
}
|
|
1466
1648
|
}
|
|
1467
|
-
if (this
|
|
1468
|
-
|
|
1649
|
+
if (this.#merging) {
|
|
1650
|
+
safeObjectAssign(this.#internals.retry, value);
|
|
1469
1651
|
}
|
|
1470
1652
|
else {
|
|
1471
|
-
this.
|
|
1653
|
+
this.#internals.retry = { ...value };
|
|
1472
1654
|
}
|
|
1473
|
-
const { retry } = this
|
|
1655
|
+
const { retry } = this.#internals;
|
|
1474
1656
|
retry.methods = [...new Set(retry.methods.map(method => method.toUpperCase()))];
|
|
1475
1657
|
retry.statusCodes = [...new Set(retry.statusCodes)];
|
|
1476
1658
|
retry.errorCodes = [...new Set(retry.errorCodes)];
|
|
@@ -1481,11 +1663,11 @@ export default class Options {
|
|
|
1481
1663
|
The IP address used to send the request from.
|
|
1482
1664
|
*/
|
|
1483
1665
|
get localAddress() {
|
|
1484
|
-
return this.
|
|
1666
|
+
return this.#internals.localAddress;
|
|
1485
1667
|
}
|
|
1486
1668
|
set localAddress(value) {
|
|
1487
1669
|
assertAny('localAddress', [is.string, is.undefined], value);
|
|
1488
|
-
this.
|
|
1670
|
+
this.#internals.localAddress = value;
|
|
1489
1671
|
}
|
|
1490
1672
|
/**
|
|
1491
1673
|
The HTTP method used to make the request.
|
|
@@ -1493,18 +1675,18 @@ export default class Options {
|
|
|
1493
1675
|
@default 'GET'
|
|
1494
1676
|
*/
|
|
1495
1677
|
get method() {
|
|
1496
|
-
return this.
|
|
1678
|
+
return this.#internals.method;
|
|
1497
1679
|
}
|
|
1498
1680
|
set method(value) {
|
|
1499
1681
|
assert.string(value);
|
|
1500
|
-
this.
|
|
1682
|
+
this.#internals.method = value.toUpperCase();
|
|
1501
1683
|
}
|
|
1502
1684
|
get createConnection() {
|
|
1503
|
-
return this.
|
|
1685
|
+
return this.#internals.createConnection;
|
|
1504
1686
|
}
|
|
1505
1687
|
set createConnection(value) {
|
|
1506
1688
|
assertAny('createConnection', [is.function, is.undefined], value);
|
|
1507
|
-
this.
|
|
1689
|
+
this.#internals.createConnection = value;
|
|
1508
1690
|
}
|
|
1509
1691
|
/**
|
|
1510
1692
|
From `http-cache-semantics`
|
|
@@ -1512,7 +1694,7 @@ export default class Options {
|
|
|
1512
1694
|
@default {}
|
|
1513
1695
|
*/
|
|
1514
1696
|
get cacheOptions() {
|
|
1515
|
-
return this.
|
|
1697
|
+
return this.#internals.cacheOptions;
|
|
1516
1698
|
}
|
|
1517
1699
|
set cacheOptions(value) {
|
|
1518
1700
|
assertPlainObject('cacheOptions', value);
|
|
@@ -1520,23 +1702,26 @@ export default class Options {
|
|
|
1520
1702
|
assertAny('cacheOptions.cacheHeuristic', [is.number, is.undefined], value.cacheHeuristic);
|
|
1521
1703
|
assertAny('cacheOptions.immutableMinTimeToLive', [is.number, is.undefined], value.immutableMinTimeToLive);
|
|
1522
1704
|
assertAny('cacheOptions.ignoreCargoCult', [is.boolean, is.undefined], value.ignoreCargoCult);
|
|
1523
|
-
for (const key
|
|
1524
|
-
if (
|
|
1705
|
+
for (const key of Object.keys(value)) {
|
|
1706
|
+
if (key === '__proto__') {
|
|
1707
|
+
continue;
|
|
1708
|
+
}
|
|
1709
|
+
if (!(key in this.#internals.cacheOptions)) {
|
|
1525
1710
|
throw new Error(`Cache option \`${key}\` does not exist`);
|
|
1526
1711
|
}
|
|
1527
1712
|
}
|
|
1528
|
-
if (this
|
|
1529
|
-
|
|
1713
|
+
if (this.#merging) {
|
|
1714
|
+
safeObjectAssign(this.#internals.cacheOptions, value);
|
|
1530
1715
|
}
|
|
1531
1716
|
else {
|
|
1532
|
-
this.
|
|
1717
|
+
this.#internals.cacheOptions = { ...value };
|
|
1533
1718
|
}
|
|
1534
1719
|
}
|
|
1535
1720
|
/**
|
|
1536
1721
|
Options for the advanced HTTPS API.
|
|
1537
1722
|
*/
|
|
1538
1723
|
get https() {
|
|
1539
|
-
return this.
|
|
1724
|
+
return this.#internals.https;
|
|
1540
1725
|
}
|
|
1541
1726
|
set https(value) {
|
|
1542
1727
|
assertPlainObject('https', value);
|
|
@@ -1559,22 +1744,25 @@ export default class Options {
|
|
|
1559
1744
|
assertAny('https.ecdhCurve', [is.string, is.undefined], value.ecdhCurve);
|
|
1560
1745
|
assertAny('https.certificateRevocationLists', [is.string, is.buffer, is.array, is.undefined], value.certificateRevocationLists);
|
|
1561
1746
|
assertAny('https.secureOptions', [is.number, is.undefined], value.secureOptions);
|
|
1562
|
-
for (const key
|
|
1563
|
-
if (
|
|
1747
|
+
for (const key of Object.keys(value)) {
|
|
1748
|
+
if (key === '__proto__') {
|
|
1749
|
+
continue;
|
|
1750
|
+
}
|
|
1751
|
+
if (!(key in this.#internals.https)) {
|
|
1564
1752
|
throw new Error(`HTTPS option \`${key}\` does not exist`);
|
|
1565
1753
|
}
|
|
1566
1754
|
}
|
|
1567
|
-
if (this
|
|
1568
|
-
|
|
1755
|
+
if (this.#merging) {
|
|
1756
|
+
safeObjectAssign(this.#internals.https, value);
|
|
1569
1757
|
}
|
|
1570
1758
|
else {
|
|
1571
|
-
this.
|
|
1759
|
+
this.#internals.https = { ...value };
|
|
1572
1760
|
}
|
|
1573
1761
|
}
|
|
1574
1762
|
/**
|
|
1575
1763
|
[Encoding](https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings) to be used on `setEncoding` of the response data.
|
|
1576
1764
|
|
|
1577
|
-
To get a [`
|
|
1765
|
+
To get a [`Uint8Array`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array), you need to set `responseType` to `buffer` instead.
|
|
1578
1766
|
Don't set this option to `null`.
|
|
1579
1767
|
|
|
1580
1768
|
__Note__: This doesn't affect streams! Instead, you need to do `got.stream(...).setEncoding(encoding)`.
|
|
@@ -1582,14 +1770,14 @@ export default class Options {
|
|
|
1582
1770
|
@default 'utf-8'
|
|
1583
1771
|
*/
|
|
1584
1772
|
get encoding() {
|
|
1585
|
-
return this.
|
|
1773
|
+
return this.#internals.encoding;
|
|
1586
1774
|
}
|
|
1587
1775
|
set encoding(value) {
|
|
1588
1776
|
if (value === null) {
|
|
1589
|
-
throw new TypeError('To get a
|
|
1777
|
+
throw new TypeError('To get a Uint8Array, set `options.responseType` to `buffer` instead');
|
|
1590
1778
|
}
|
|
1591
1779
|
assertAny('encoding', [is.string, is.undefined], value);
|
|
1592
|
-
this.
|
|
1780
|
+
this.#internals.encoding = value;
|
|
1593
1781
|
}
|
|
1594
1782
|
/**
|
|
1595
1783
|
When set to `true` the promise will return the Response body instead of the Response object.
|
|
@@ -1597,24 +1785,25 @@ export default class Options {
|
|
|
1597
1785
|
@default false
|
|
1598
1786
|
*/
|
|
1599
1787
|
get resolveBodyOnly() {
|
|
1600
|
-
return this.
|
|
1788
|
+
return this.#internals.resolveBodyOnly;
|
|
1601
1789
|
}
|
|
1602
1790
|
set resolveBodyOnly(value) {
|
|
1603
1791
|
assert.boolean(value);
|
|
1604
|
-
this.
|
|
1792
|
+
this.#internals.resolveBodyOnly = value;
|
|
1605
1793
|
}
|
|
1606
1794
|
/**
|
|
1795
|
+
@internal
|
|
1607
1796
|
Returns a `Stream` instead of a `Promise`.
|
|
1608
|
-
|
|
1797
|
+
Set internally by `got.stream()`.
|
|
1609
1798
|
|
|
1610
1799
|
@default false
|
|
1611
1800
|
*/
|
|
1612
1801
|
get isStream() {
|
|
1613
|
-
return this.
|
|
1802
|
+
return this.#internals.isStream;
|
|
1614
1803
|
}
|
|
1615
1804
|
set isStream(value) {
|
|
1616
1805
|
assert.boolean(value);
|
|
1617
|
-
this.
|
|
1806
|
+
this.#internals.isStream = value;
|
|
1618
1807
|
}
|
|
1619
1808
|
/**
|
|
1620
1809
|
The parsing method.
|
|
@@ -1633,7 +1822,7 @@ export default class Options {
|
|
|
1633
1822
|
|
|
1634
1823
|
const [response, buffer, json] = Promise.all([responsePromise, bufferPromise, jsonPromise]);
|
|
1635
1824
|
// `response` is an instance of Got Response
|
|
1636
|
-
// `buffer` is an instance of
|
|
1825
|
+
// `buffer` is an instance of Uint8Array
|
|
1637
1826
|
// `json` is an object
|
|
1638
1827
|
```
|
|
1639
1828
|
|
|
@@ -1647,28 +1836,28 @@ export default class Options {
|
|
|
1647
1836
|
```
|
|
1648
1837
|
*/
|
|
1649
1838
|
get responseType() {
|
|
1650
|
-
return this.
|
|
1839
|
+
return this.#internals.responseType;
|
|
1651
1840
|
}
|
|
1652
1841
|
set responseType(value) {
|
|
1653
1842
|
if (value === undefined) {
|
|
1654
|
-
this.
|
|
1843
|
+
this.#internals.responseType = 'text';
|
|
1655
1844
|
return;
|
|
1656
1845
|
}
|
|
1657
1846
|
if (value !== 'text' && value !== 'buffer' && value !== 'json') {
|
|
1658
1847
|
throw new Error(`Invalid \`responseType\` option: ${value}`);
|
|
1659
1848
|
}
|
|
1660
|
-
this.
|
|
1849
|
+
this.#internals.responseType = value;
|
|
1661
1850
|
}
|
|
1662
1851
|
get pagination() {
|
|
1663
|
-
return this.
|
|
1852
|
+
return this.#internals.pagination;
|
|
1664
1853
|
}
|
|
1665
1854
|
set pagination(value) {
|
|
1666
1855
|
assert.object(value);
|
|
1667
|
-
if (this
|
|
1668
|
-
|
|
1856
|
+
if (this.#merging) {
|
|
1857
|
+
safeObjectAssign(this.#internals.pagination, value);
|
|
1669
1858
|
}
|
|
1670
1859
|
else {
|
|
1671
|
-
this.
|
|
1860
|
+
this.#internals.pagination = value;
|
|
1672
1861
|
}
|
|
1673
1862
|
}
|
|
1674
1863
|
get auth() {
|
|
@@ -1678,25 +1867,25 @@ export default class Options {
|
|
|
1678
1867
|
throw new Error('Parameter `auth` is deprecated. Use `username` / `password` instead.');
|
|
1679
1868
|
}
|
|
1680
1869
|
get setHost() {
|
|
1681
|
-
return this.
|
|
1870
|
+
return this.#internals.setHost;
|
|
1682
1871
|
}
|
|
1683
1872
|
set setHost(value) {
|
|
1684
1873
|
assert.boolean(value);
|
|
1685
|
-
this.
|
|
1874
|
+
this.#internals.setHost = value;
|
|
1686
1875
|
}
|
|
1687
1876
|
get maxHeaderSize() {
|
|
1688
|
-
return this.
|
|
1877
|
+
return this.#internals.maxHeaderSize;
|
|
1689
1878
|
}
|
|
1690
1879
|
set maxHeaderSize(value) {
|
|
1691
1880
|
assertAny('maxHeaderSize', [is.number, is.undefined], value);
|
|
1692
|
-
this.
|
|
1881
|
+
this.#internals.maxHeaderSize = value;
|
|
1693
1882
|
}
|
|
1694
1883
|
get enableUnixSockets() {
|
|
1695
|
-
return this.
|
|
1884
|
+
return this.#internals.enableUnixSockets;
|
|
1696
1885
|
}
|
|
1697
1886
|
set enableUnixSockets(value) {
|
|
1698
1887
|
assert.boolean(value);
|
|
1699
|
-
this.
|
|
1888
|
+
this.#internals.enableUnixSockets = value;
|
|
1700
1889
|
}
|
|
1701
1890
|
/**
|
|
1702
1891
|
Throw an error if the server response's `content-length` header value doesn't match the number of bytes received.
|
|
@@ -1706,24 +1895,24 @@ export default class Options {
|
|
|
1706
1895
|
__Note__: Responses without a `content-length` header are not validated.
|
|
1707
1896
|
__Note__: When enabled and validation fails, a `ReadError` with code `ERR_HTTP_CONTENT_LENGTH_MISMATCH` will be thrown.
|
|
1708
1897
|
|
|
1709
|
-
@default
|
|
1898
|
+
@default true
|
|
1710
1899
|
*/
|
|
1711
1900
|
get strictContentLength() {
|
|
1712
|
-
return this.
|
|
1901
|
+
return this.#internals.strictContentLength;
|
|
1713
1902
|
}
|
|
1714
1903
|
set strictContentLength(value) {
|
|
1715
1904
|
assert.boolean(value);
|
|
1716
|
-
this.
|
|
1905
|
+
this.#internals.strictContentLength = value;
|
|
1717
1906
|
}
|
|
1718
1907
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1719
1908
|
toJSON() {
|
|
1720
|
-
return { ...this
|
|
1909
|
+
return { ...this.#internals };
|
|
1721
1910
|
}
|
|
1722
1911
|
[Symbol.for('nodejs.util.inspect.custom')](_depth, options) {
|
|
1723
|
-
return inspect(this
|
|
1912
|
+
return inspect(this.#internals, options);
|
|
1724
1913
|
}
|
|
1725
1914
|
createNativeRequestOptions() {
|
|
1726
|
-
const internals = this
|
|
1915
|
+
const internals = this.#internals;
|
|
1727
1916
|
const url = internals.url;
|
|
1728
1917
|
let agent;
|
|
1729
1918
|
if (url.protocol === 'https:') {
|
|
@@ -1750,9 +1939,20 @@ export default class Options {
|
|
|
1750
1939
|
passphrase: object.passphrase,
|
|
1751
1940
|
}));
|
|
1752
1941
|
}
|
|
1942
|
+
const unixSocketPath = getUnixSocketPath(url);
|
|
1943
|
+
if (usesUnixSocket(url) && !internals.enableUnixSockets) {
|
|
1944
|
+
throw new Error('Using UNIX domain sockets but option `enableUnixSockets` is not enabled');
|
|
1945
|
+
}
|
|
1946
|
+
let unixSocketGroups;
|
|
1947
|
+
if (unixSocketPath !== undefined) {
|
|
1948
|
+
unixSocketGroups = /(?<socketPath>.+?):(?<path>.+)/.exec(`${url.pathname}${url.search}`)?.groups;
|
|
1949
|
+
}
|
|
1950
|
+
const unixOptions = unixSocketGroups
|
|
1951
|
+
? { socketPath: unixSocketGroups.socketPath, path: unixSocketGroups.path, host: '' }
|
|
1952
|
+
: undefined;
|
|
1753
1953
|
return {
|
|
1754
1954
|
...internals.cacheOptions,
|
|
1755
|
-
...
|
|
1955
|
+
...unixOptions,
|
|
1756
1956
|
// HTTPS options
|
|
1757
1957
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1758
1958
|
ALPNProtocols: https.alpnProtocols,
|
|
@@ -1760,7 +1960,7 @@ export default class Options {
|
|
|
1760
1960
|
cert: https.certificate,
|
|
1761
1961
|
key: https.key,
|
|
1762
1962
|
passphrase: https.passphrase,
|
|
1763
|
-
pfx
|
|
1963
|
+
pfx,
|
|
1764
1964
|
rejectUnauthorized: https.rejectUnauthorized,
|
|
1765
1965
|
checkServerIdentity: https.checkServerIdentity ?? checkServerIdentity,
|
|
1766
1966
|
servername: https.serverName,
|
|
@@ -1790,33 +1990,24 @@ export default class Options {
|
|
|
1790
1990
|
};
|
|
1791
1991
|
}
|
|
1792
1992
|
getRequestFunction() {
|
|
1793
|
-
const
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
const url = this._internals.url;
|
|
1802
|
-
if (!url) {
|
|
1803
|
-
return;
|
|
1804
|
-
}
|
|
1805
|
-
if (url.protocol === 'https:') {
|
|
1806
|
-
if (this._internals.http2) {
|
|
1807
|
-
if (major < 15 || (major === 15 && minor < 10)) {
|
|
1808
|
-
const error = new Error('To use the `http2` option, install Node.js 15.10.0 or above');
|
|
1809
|
-
error.code = 'EUNSUPPORTED';
|
|
1810
|
-
throw error;
|
|
1811
|
-
}
|
|
1812
|
-
return http2wrapper.auto;
|
|
1993
|
+
const { request: customRequest } = this.#internals;
|
|
1994
|
+
if (!customRequest) {
|
|
1995
|
+
return this.#getFallbackRequestFunction();
|
|
1996
|
+
}
|
|
1997
|
+
const requestWithFallback = (url, options, callback) => {
|
|
1998
|
+
const result = customRequest(url, options, callback);
|
|
1999
|
+
if (is.promise(result)) {
|
|
2000
|
+
return this.#resolveRequestWithFallback(result, url, options, callback);
|
|
1813
2001
|
}
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
2002
|
+
if (result !== undefined) {
|
|
2003
|
+
return result;
|
|
2004
|
+
}
|
|
2005
|
+
return this.#callFallbackRequest(url, options, callback);
|
|
2006
|
+
};
|
|
2007
|
+
return requestWithFallback;
|
|
1817
2008
|
}
|
|
1818
2009
|
freeze() {
|
|
1819
|
-
const options = this
|
|
2010
|
+
const options = this.#internals;
|
|
1820
2011
|
Object.freeze(options);
|
|
1821
2012
|
Object.freeze(options.hooks);
|
|
1822
2013
|
Object.freeze(options.hooks.afterResponse);
|
|
@@ -1835,4 +2026,126 @@ export default class Options {
|
|
|
1835
2026
|
Object.freeze(options.retry.methods);
|
|
1836
2027
|
Object.freeze(options.retry.statusCodes);
|
|
1837
2028
|
}
|
|
2029
|
+
#createHeadersProxy() {
|
|
2030
|
+
return new Proxy(this.#internals.headers, {
|
|
2031
|
+
get(target, property, receiver) {
|
|
2032
|
+
if (typeof property === 'string') {
|
|
2033
|
+
if (Reflect.has(target, property)) {
|
|
2034
|
+
return Reflect.get(target, property, receiver);
|
|
2035
|
+
}
|
|
2036
|
+
const normalizedProperty = property.toLowerCase();
|
|
2037
|
+
return Reflect.get(target, normalizedProperty, receiver);
|
|
2038
|
+
}
|
|
2039
|
+
return Reflect.get(target, property, receiver);
|
|
2040
|
+
},
|
|
2041
|
+
set: (target, property, value) => {
|
|
2042
|
+
if (typeof property === 'string') {
|
|
2043
|
+
const normalizedProperty = property.toLowerCase();
|
|
2044
|
+
assertValidHeaderName(normalizedProperty);
|
|
2045
|
+
const isSuccess = Reflect.set(target, normalizedProperty, value);
|
|
2046
|
+
if (isSuccess) {
|
|
2047
|
+
markHeaderAsExplicit(this.#explicitHeaders, this.#trackedStateMutations, normalizedProperty);
|
|
2048
|
+
}
|
|
2049
|
+
return isSuccess;
|
|
2050
|
+
}
|
|
2051
|
+
return Reflect.set(target, property, value);
|
|
2052
|
+
},
|
|
2053
|
+
deleteProperty: (target, property) => {
|
|
2054
|
+
if (typeof property === 'string') {
|
|
2055
|
+
const normalizedProperty = property.toLowerCase();
|
|
2056
|
+
const isSuccess = Reflect.deleteProperty(target, normalizedProperty);
|
|
2057
|
+
if (isSuccess) {
|
|
2058
|
+
this.#explicitHeaders.delete(normalizedProperty);
|
|
2059
|
+
trackStateMutation(this.#trackedStateMutations, normalizedProperty);
|
|
2060
|
+
}
|
|
2061
|
+
return isSuccess;
|
|
2062
|
+
}
|
|
2063
|
+
return Reflect.deleteProperty(target, property);
|
|
2064
|
+
},
|
|
2065
|
+
});
|
|
2066
|
+
}
|
|
2067
|
+
#getFallbackRequestFunction() {
|
|
2068
|
+
const url = this.#internals.url;
|
|
2069
|
+
if (!url) {
|
|
2070
|
+
return;
|
|
2071
|
+
}
|
|
2072
|
+
if (url.protocol === 'https:') {
|
|
2073
|
+
if (this.#internals.http2) {
|
|
2074
|
+
if (major < 15 || (major === 15 && minor < 10)) {
|
|
2075
|
+
const error = new Error('To use the `http2` option, install Node.js 15.10.0 or above');
|
|
2076
|
+
error.code = 'EUNSUPPORTED';
|
|
2077
|
+
throw error;
|
|
2078
|
+
}
|
|
2079
|
+
return http2wrapper.auto;
|
|
2080
|
+
}
|
|
2081
|
+
return https.request;
|
|
2082
|
+
}
|
|
2083
|
+
return http.request;
|
|
2084
|
+
}
|
|
2085
|
+
#callFallbackRequest(url, options, callback) {
|
|
2086
|
+
const fallbackRequest = this.#getFallbackRequestFunction();
|
|
2087
|
+
if (!fallbackRequest) {
|
|
2088
|
+
throw new TypeError('The request function must return a value');
|
|
2089
|
+
}
|
|
2090
|
+
const fallbackResult = fallbackRequest(url, options, callback);
|
|
2091
|
+
if (fallbackResult === undefined) {
|
|
2092
|
+
throw new TypeError('The request function must return a value');
|
|
2093
|
+
}
|
|
2094
|
+
if (is.promise(fallbackResult)) {
|
|
2095
|
+
return this.#resolveFallbackRequestResult(fallbackResult);
|
|
2096
|
+
}
|
|
2097
|
+
return fallbackResult;
|
|
2098
|
+
}
|
|
2099
|
+
async #resolveRequestWithFallback(requestResult, url, options, callback) {
|
|
2100
|
+
const result = await requestResult;
|
|
2101
|
+
if (result !== undefined) {
|
|
2102
|
+
return result;
|
|
2103
|
+
}
|
|
2104
|
+
return this.#callFallbackRequest(url, options, callback);
|
|
2105
|
+
}
|
|
2106
|
+
async #resolveFallbackRequestResult(fallbackResult) {
|
|
2107
|
+
const resolvedFallbackResult = await fallbackResult;
|
|
2108
|
+
if (resolvedFallbackResult === undefined) {
|
|
2109
|
+
throw new TypeError('The request function must return a value');
|
|
2110
|
+
}
|
|
2111
|
+
return resolvedFallbackResult;
|
|
2112
|
+
}
|
|
1838
2113
|
}
|
|
2114
|
+
export const snapshotCrossOriginState = (options) => ({
|
|
2115
|
+
headers: { ...options.getInternalHeaders() },
|
|
2116
|
+
username: options.username,
|
|
2117
|
+
password: options.password,
|
|
2118
|
+
body: options.body,
|
|
2119
|
+
json: options.json,
|
|
2120
|
+
form: options.form,
|
|
2121
|
+
bodySnapshot: cloneCrossOriginBodyValue(options.body),
|
|
2122
|
+
jsonSnapshot: cloneCrossOriginBodyValue(options.json),
|
|
2123
|
+
formSnapshot: cloneCrossOriginBodyValue(options.form),
|
|
2124
|
+
});
|
|
2125
|
+
const cloneCrossOriginBodyValue = (value) => {
|
|
2126
|
+
if (value === undefined || value === null || typeof value !== 'object') {
|
|
2127
|
+
return value;
|
|
2128
|
+
}
|
|
2129
|
+
try {
|
|
2130
|
+
return structuredClone(value);
|
|
2131
|
+
}
|
|
2132
|
+
catch {
|
|
2133
|
+
return undefined;
|
|
2134
|
+
}
|
|
2135
|
+
};
|
|
2136
|
+
const isUnchangedCrossOriginBodyValue = (currentValue, previousValue, previousSnapshot) => {
|
|
2137
|
+
if (currentValue !== previousValue) {
|
|
2138
|
+
return false;
|
|
2139
|
+
}
|
|
2140
|
+
if (currentValue === undefined || currentValue === null || typeof currentValue !== 'object') {
|
|
2141
|
+
return true;
|
|
2142
|
+
}
|
|
2143
|
+
if (previousSnapshot === undefined) {
|
|
2144
|
+
return true;
|
|
2145
|
+
}
|
|
2146
|
+
return isDeepStrictEqual(currentValue, previousSnapshot);
|
|
2147
|
+
};
|
|
2148
|
+
export const isCrossOriginCredentialChanged = (previousUrl, nextUrl, credential) => (nextUrl[credential] !== '' && nextUrl[credential] !== previousUrl[credential]);
|
|
2149
|
+
export const isBodyUnchanged = (options, previousState) => isUnchangedCrossOriginBodyValue(options.body, previousState.body, previousState.bodySnapshot)
|
|
2150
|
+
&& isUnchangedCrossOriginBodyValue(options.json, previousState.json, previousState.jsonSnapshot)
|
|
2151
|
+
&& isUnchangedCrossOriginBodyValue(options.form, previousState.form, previousState.formSnapshot);
|