axios 1.16.1 → 1.18.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/CHANGELOG.md +94 -1
- package/README.md +267 -239
- package/dist/axios.js +454 -146
- package/dist/axios.min.js +3 -3
- package/dist/axios.min.js.map +1 -1
- package/dist/browser/axios.cjs +470 -99
- package/dist/esm/axios.js +470 -99
- package/dist/esm/axios.min.js +2 -2
- package/dist/esm/axios.min.js.map +1 -1
- package/dist/node/axios.cjs +638 -201
- package/index.d.cts +10 -3
- package/index.d.ts +6 -1
- package/lib/adapters/fetch.js +190 -35
- package/lib/adapters/http.js +192 -159
- package/lib/core/Axios.js +4 -2
- package/lib/core/AxiosHeaders.js +12 -9
- package/lib/core/buildFullPath.js +29 -1
- package/lib/core/mergeConfig.js +34 -0
- package/lib/defaults/transitional.js +2 -0
- package/lib/env/data.js +1 -1
- package/lib/helpers/Http2Sessions.js +119 -0
- package/lib/helpers/buildURL.js +6 -4
- package/lib/helpers/estimateDataURLDecodedBytes.js +16 -11
- package/lib/helpers/formDataToJSON.js +25 -3
- package/lib/helpers/formDataToStream.js +2 -2
- package/lib/helpers/resolveConfig.js +17 -9
- package/lib/helpers/shouldBypassProxy.js +33 -1
- package/lib/helpers/toFormData.js +41 -11
- package/lib/utils.js +97 -12
- package/package.json +29 -13
- package/dist/axios.js.map +0 -1
- package/dist/browser/axios.cjs.map +0 -1
- package/dist/esm/axios.js.map +0 -1
- package/dist/node/axios.cjs.map +0 -1
package/dist/node/axios.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! Axios v1.
|
|
1
|
+
/*! Axios v1.18.0 Copyright (c) 2026 Matt Zabriskie and contributors */
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var FormData$1 = require('form-data');
|
|
@@ -40,6 +40,52 @@ const {
|
|
|
40
40
|
iterator,
|
|
41
41
|
toStringTag
|
|
42
42
|
} = Symbol;
|
|
43
|
+
|
|
44
|
+
/* Creating a function that will check if an object has a property. */
|
|
45
|
+
const hasOwnProperty = (({
|
|
46
|
+
hasOwnProperty
|
|
47
|
+
}) => (obj, prop) => hasOwnProperty.call(obj, prop))(Object.prototype);
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Walk the prototype chain (excluding the shared Object.prototype) looking for
|
|
51
|
+
* an own `prop`. This distinguishes genuine own/inherited members — including
|
|
52
|
+
* class accessors and template prototypes — from members injected via
|
|
53
|
+
* Object.prototype pollution (e.g. `Object.prototype.username = '...'`), which
|
|
54
|
+
* live on Object.prototype itself and are therefore never matched.
|
|
55
|
+
*
|
|
56
|
+
* @param {*} thing The value whose chain to inspect
|
|
57
|
+
* @param {string|symbol} prop The property key to look for
|
|
58
|
+
*
|
|
59
|
+
* @returns {boolean} True when `prop` is owned below Object.prototype
|
|
60
|
+
*/
|
|
61
|
+
const hasOwnInPrototypeChain = (thing, prop) => {
|
|
62
|
+
let obj = thing;
|
|
63
|
+
const seen = [];
|
|
64
|
+
while (obj != null && obj !== Object.prototype) {
|
|
65
|
+
if (seen.indexOf(obj) !== -1) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
seen.push(obj);
|
|
69
|
+
if (hasOwnProperty(obj, prop)) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
obj = getPrototypeOf(obj);
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Read `obj[prop]` only when it is safe from Object.prototype pollution. Own
|
|
79
|
+
* properties and members inherited from a non-Object.prototype source (a class
|
|
80
|
+
* instance or template object) are honored; a value reachable only through a
|
|
81
|
+
* polluted Object.prototype is ignored and `undefined` is returned.
|
|
82
|
+
*
|
|
83
|
+
* @param {*} obj The source object
|
|
84
|
+
* @param {string|symbol} prop The property key to read
|
|
85
|
+
*
|
|
86
|
+
* @returns {*} The resolved value, or undefined when unsafe/absent
|
|
87
|
+
*/
|
|
88
|
+
const getSafeProp = (obj, prop) => obj != null && hasOwnInPrototypeChain(obj, prop) ? obj[prop] : undefined;
|
|
43
89
|
const kindOf = (cache => thing => {
|
|
44
90
|
const str = toString.call(thing);
|
|
45
91
|
return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());
|
|
@@ -158,11 +204,15 @@ const isBoolean = thing => thing === true || thing === false;
|
|
|
158
204
|
* @returns {boolean} True if value is a plain Object, otherwise false
|
|
159
205
|
*/
|
|
160
206
|
const isPlainObject = val => {
|
|
161
|
-
if (
|
|
207
|
+
if (!isObject(val)) {
|
|
162
208
|
return false;
|
|
163
209
|
}
|
|
164
210
|
const prototype = getPrototypeOf(val);
|
|
165
|
-
return (prototype === null || prototype === Object.prototype ||
|
|
211
|
+
return (prototype === null || prototype === Object.prototype || getPrototypeOf(prototype) === null) &&
|
|
212
|
+
// Treat any genuine (non-Object.prototype-polluted) Symbol.toStringTag or
|
|
213
|
+
// Symbol.iterator as evidence the value is a tagged/iterable type rather
|
|
214
|
+
// than a plain object, while ignoring keys injected onto Object.prototype.
|
|
215
|
+
!hasOwnInPrototypeChain(val, toStringTag) && !hasOwnInPrototypeChain(val, iterator);
|
|
166
216
|
};
|
|
167
217
|
|
|
168
218
|
/**
|
|
@@ -417,7 +467,10 @@ function merge(...objs) {
|
|
|
417
467
|
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
|
|
418
468
|
return;
|
|
419
469
|
}
|
|
420
|
-
|
|
470
|
+
|
|
471
|
+
// findKey lowercases the key, so caseless lookup only applies to strings —
|
|
472
|
+
// symbol keys are identity-matched.
|
|
473
|
+
const targetKey = caseless && typeof key === 'string' && findKey(result, key) || key;
|
|
421
474
|
// Read via own-prop only — a bare `result[targetKey]` walks the prototype
|
|
422
475
|
// chain, so a polluted Object.prototype value could surface here and get
|
|
423
476
|
// copied into the merged result.
|
|
@@ -433,7 +486,21 @@ function merge(...objs) {
|
|
|
433
486
|
}
|
|
434
487
|
};
|
|
435
488
|
for (let i = 0, l = objs.length; i < l; i++) {
|
|
436
|
-
|
|
489
|
+
const source = objs[i];
|
|
490
|
+
if (!source || isBuffer(source)) {
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
forEach(source, assignValue);
|
|
494
|
+
if (typeof source !== 'object' || isArray(source)) {
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
const symbols = Object.getOwnPropertySymbols(source);
|
|
498
|
+
for (let j = 0; j < symbols.length; j++) {
|
|
499
|
+
const symbol = symbols[j];
|
|
500
|
+
if (propertyIsEnumerable.call(source, symbol)) {
|
|
501
|
+
assignValue(source[symbol], symbol);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
437
504
|
}
|
|
438
505
|
return result;
|
|
439
506
|
}
|
|
@@ -645,11 +712,9 @@ const toCamelCase = str => {
|
|
|
645
712
|
return p1.toUpperCase() + p2;
|
|
646
713
|
});
|
|
647
714
|
};
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
hasOwnProperty
|
|
652
|
-
}) => (obj, prop) => hasOwnProperty.call(obj, prop))(Object.prototype);
|
|
715
|
+
const {
|
|
716
|
+
propertyIsEnumerable
|
|
717
|
+
} = Object.prototype;
|
|
653
718
|
|
|
654
719
|
/**
|
|
655
720
|
* Determine if a value is a RegExp object
|
|
@@ -824,6 +889,19 @@ const asap = typeof queueMicrotask !== 'undefined' ? queueMicrotask.bind(_global
|
|
|
824
889
|
// *********************
|
|
825
890
|
|
|
826
891
|
const isIterable = thing => thing != null && isFunction$1(thing[iterator]);
|
|
892
|
+
|
|
893
|
+
/**
|
|
894
|
+
* Determine if a value is iterable via an iterator that is NOT sourced solely
|
|
895
|
+
* from a polluted Object.prototype. Use this instead of `isIterable` whenever
|
|
896
|
+
* the iterable comes from untrusted input (e.g. user-supplied header sources),
|
|
897
|
+
* so `Object.prototype[Symbol.iterator] = ...` cannot turn an ordinary object
|
|
898
|
+
* into an attacker-controlled entries iterator.
|
|
899
|
+
*
|
|
900
|
+
* @param {*} thing The value to test
|
|
901
|
+
*
|
|
902
|
+
* @returns {boolean} True if value has a non-polluted iterator
|
|
903
|
+
*/
|
|
904
|
+
const isSafeIterable = thing => thing != null && hasOwnInPrototypeChain(thing, iterator) && isIterable(thing);
|
|
827
905
|
var utils$1 = {
|
|
828
906
|
isArray,
|
|
829
907
|
isArrayBuffer,
|
|
@@ -869,6 +947,8 @@ var utils$1 = {
|
|
|
869
947
|
hasOwnProperty,
|
|
870
948
|
hasOwnProp: hasOwnProperty,
|
|
871
949
|
// an alias to avoid ESLint no-prototype-builtins detection
|
|
950
|
+
hasOwnInPrototypeChain,
|
|
951
|
+
getSafeProp,
|
|
872
952
|
reduceDescriptors,
|
|
873
953
|
freezeMethods,
|
|
874
954
|
toObjectSet,
|
|
@@ -884,7 +964,8 @@ var utils$1 = {
|
|
|
884
964
|
isThenable,
|
|
885
965
|
setImmediate: _setImmediate,
|
|
886
966
|
asap,
|
|
887
|
-
isIterable
|
|
967
|
+
isIterable,
|
|
968
|
+
isSafeIterable
|
|
888
969
|
};
|
|
889
970
|
|
|
890
971
|
// RawAxiosHeaders whose duplicates are ignored by node
|
|
@@ -1034,7 +1115,7 @@ class AxiosHeaders {
|
|
|
1034
1115
|
function setHeader(_value, _header, _rewrite) {
|
|
1035
1116
|
const lHeader = normalizeHeader(_header);
|
|
1036
1117
|
if (!lHeader) {
|
|
1037
|
-
|
|
1118
|
+
return;
|
|
1038
1119
|
}
|
|
1039
1120
|
const key = utils$1.findKey(self, lHeader);
|
|
1040
1121
|
if (!key || self[key] === undefined || _rewrite === true || _rewrite === undefined && self[key] !== false) {
|
|
@@ -1046,15 +1127,21 @@ class AxiosHeaders {
|
|
|
1046
1127
|
setHeaders(header, valueOrRewrite);
|
|
1047
1128
|
} else if (utils$1.isString(header) && (header = header.trim()) && !isValidHeaderName(header)) {
|
|
1048
1129
|
setHeaders(parseHeaders(header), valueOrRewrite);
|
|
1049
|
-
} else if (utils$1.isObject(header) && utils$1.
|
|
1050
|
-
let obj =
|
|
1130
|
+
} else if (utils$1.isObject(header) && utils$1.isSafeIterable(header)) {
|
|
1131
|
+
let obj = Object.create(null),
|
|
1051
1132
|
dest,
|
|
1052
1133
|
key;
|
|
1053
1134
|
for (const entry of header) {
|
|
1054
1135
|
if (!utils$1.isArray(entry)) {
|
|
1055
|
-
throw TypeError('Object iterator must return a key-value pair');
|
|
1136
|
+
throw new TypeError('Object iterator must return a key-value pair');
|
|
1137
|
+
}
|
|
1138
|
+
key = entry[0];
|
|
1139
|
+
if (utils$1.hasOwnProp(obj, key)) {
|
|
1140
|
+
dest = obj[key];
|
|
1141
|
+
obj[key] = utils$1.isArray(dest) ? [...dest, entry[1]] : [dest, entry[1]];
|
|
1142
|
+
} else {
|
|
1143
|
+
obj[key] = entry[1];
|
|
1056
1144
|
}
|
|
1057
|
-
obj[key = entry[0]] = (dest = obj[key]) ? utils$1.isArray(dest) ? [...dest, entry[1]] : [dest, entry[1]] : entry[1];
|
|
1058
1145
|
}
|
|
1059
1146
|
setHeaders(obj, valueOrRewrite);
|
|
1060
1147
|
} else {
|
|
@@ -1357,6 +1444,10 @@ AxiosError.ERR_NOT_SUPPORT = 'ERR_NOT_SUPPORT';
|
|
|
1357
1444
|
AxiosError.ERR_INVALID_URL = 'ERR_INVALID_URL';
|
|
1358
1445
|
AxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED = 'ERR_FORM_DATA_DEPTH_EXCEEDED';
|
|
1359
1446
|
|
|
1447
|
+
// Default nesting limit shared with the inverse transform (formDataToJSON) so
|
|
1448
|
+
// the FormData <-> JSON round-trip stays symmetric.
|
|
1449
|
+
const DEFAULT_FORM_DATA_MAX_DEPTH = 100;
|
|
1450
|
+
|
|
1360
1451
|
/**
|
|
1361
1452
|
* Determines if the given thing is a array or js object.
|
|
1362
1453
|
*
|
|
@@ -1457,8 +1548,9 @@ function toFormData(obj, formData, options) {
|
|
|
1457
1548
|
const dots = options.dots;
|
|
1458
1549
|
const indexes = options.indexes;
|
|
1459
1550
|
const _Blob = options.Blob || typeof Blob !== 'undefined' && Blob;
|
|
1460
|
-
const maxDepth = options.maxDepth === undefined ?
|
|
1551
|
+
const maxDepth = options.maxDepth === undefined ? DEFAULT_FORM_DATA_MAX_DEPTH : options.maxDepth;
|
|
1461
1552
|
const useBlob = _Blob && utils$1.isSpecCompliantForm(formData);
|
|
1553
|
+
const stack = [];
|
|
1462
1554
|
if (!utils$1.isFunction(visitor)) {
|
|
1463
1555
|
throw new TypeError('visitor must be a function');
|
|
1464
1556
|
}
|
|
@@ -1478,6 +1570,28 @@ function toFormData(obj, formData, options) {
|
|
|
1478
1570
|
}
|
|
1479
1571
|
return value;
|
|
1480
1572
|
}
|
|
1573
|
+
function throwIfMaxDepthExceeded(depth) {
|
|
1574
|
+
if (depth > maxDepth) {
|
|
1575
|
+
throw new AxiosError('Object is too deeply nested (' + depth + ' levels). Max depth: ' + maxDepth, AxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED);
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
function stringifyWithDepthLimit(value, depth) {
|
|
1579
|
+
if (maxDepth === Infinity) {
|
|
1580
|
+
return JSON.stringify(value);
|
|
1581
|
+
}
|
|
1582
|
+
const ancestors = [];
|
|
1583
|
+
return JSON.stringify(value, function limitDepth(_key, currentValue) {
|
|
1584
|
+
if (!utils$1.isObject(currentValue)) {
|
|
1585
|
+
return currentValue;
|
|
1586
|
+
}
|
|
1587
|
+
while (ancestors.length && ancestors[ancestors.length - 1] !== this) {
|
|
1588
|
+
ancestors.pop();
|
|
1589
|
+
}
|
|
1590
|
+
ancestors.push(currentValue);
|
|
1591
|
+
throwIfMaxDepthExceeded(depth + ancestors.length - 1);
|
|
1592
|
+
return currentValue;
|
|
1593
|
+
});
|
|
1594
|
+
}
|
|
1481
1595
|
|
|
1482
1596
|
/**
|
|
1483
1597
|
* Default visitor.
|
|
@@ -1500,7 +1614,7 @@ function toFormData(obj, formData, options) {
|
|
|
1500
1614
|
// eslint-disable-next-line no-param-reassign
|
|
1501
1615
|
key = metaTokens ? key : key.slice(0, -2);
|
|
1502
1616
|
// eslint-disable-next-line no-param-reassign
|
|
1503
|
-
value =
|
|
1617
|
+
value = stringifyWithDepthLimit(value, 1);
|
|
1504
1618
|
} else if (utils$1.isArray(value) && isFlatArray(value) || (utils$1.isFileList(value) || utils$1.endsWith(key, '[]')) && (arr = utils$1.toArray(value))) {
|
|
1505
1619
|
// eslint-disable-next-line no-param-reassign
|
|
1506
1620
|
key = removeBrackets(key);
|
|
@@ -1518,7 +1632,6 @@ function toFormData(obj, formData, options) {
|
|
|
1518
1632
|
formData.append(renderKey(path, key, dots), convertValue(value));
|
|
1519
1633
|
return false;
|
|
1520
1634
|
}
|
|
1521
|
-
const stack = [];
|
|
1522
1635
|
const exposedHelpers = Object.assign(predicates, {
|
|
1523
1636
|
defaultVisitor,
|
|
1524
1637
|
convertValue,
|
|
@@ -1526,11 +1639,9 @@ function toFormData(obj, formData, options) {
|
|
|
1526
1639
|
});
|
|
1527
1640
|
function build(value, path, depth = 0) {
|
|
1528
1641
|
if (utils$1.isUndefined(value)) return;
|
|
1529
|
-
|
|
1530
|
-
throw new AxiosError('Object is too deeply nested (' + depth + ' levels). Max depth: ' + maxDepth, AxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED);
|
|
1531
|
-
}
|
|
1642
|
+
throwIfMaxDepthExceeded(depth);
|
|
1532
1643
|
if (stack.indexOf(value) !== -1) {
|
|
1533
|
-
throw Error('Circular reference detected in ' + path.join('.'));
|
|
1644
|
+
throw new Error('Circular reference detected in ' + path.join('.'));
|
|
1534
1645
|
}
|
|
1535
1646
|
stack.push(value);
|
|
1536
1647
|
utils$1.forEach(value, function each(el, key) {
|
|
@@ -1620,11 +1731,15 @@ function buildURL(url, params, options) {
|
|
|
1620
1731
|
if (!params) {
|
|
1621
1732
|
return url;
|
|
1622
1733
|
}
|
|
1623
|
-
const _encode = options && options.encode || encode;
|
|
1624
1734
|
const _options = utils$1.isFunction(options) ? {
|
|
1625
1735
|
serialize: options
|
|
1626
1736
|
} : options;
|
|
1627
|
-
|
|
1737
|
+
|
|
1738
|
+
// Read serializer options pollution-safely: own properties and methods on a
|
|
1739
|
+
// class/template prototype are honored, but values injected onto a polluted
|
|
1740
|
+
// Object.prototype are ignored.
|
|
1741
|
+
const _encode = utils$1.getSafeProp(_options, 'encode') || encode;
|
|
1742
|
+
const serializeFn = utils$1.getSafeProp(_options, 'serialize');
|
|
1628
1743
|
let serializedParams;
|
|
1629
1744
|
if (serializeFn) {
|
|
1630
1745
|
serializedParams = serializeFn(params, _options);
|
|
@@ -1712,7 +1827,9 @@ var transitionalDefaults = {
|
|
|
1712
1827
|
silentJSONParsing: true,
|
|
1713
1828
|
forcedJSONParsing: true,
|
|
1714
1829
|
clarifyTimeoutError: false,
|
|
1715
|
-
legacyInterceptorReqResOrdering: true
|
|
1830
|
+
legacyInterceptorReqResOrdering: true,
|
|
1831
|
+
advertiseZstdAcceptEncoding: false,
|
|
1832
|
+
validateStatusUndefinedResolves: true
|
|
1716
1833
|
};
|
|
1717
1834
|
|
|
1718
1835
|
var URLSearchParams = url.URLSearchParams;
|
|
@@ -1813,6 +1930,13 @@ function toURLEncodedForm(data, options) {
|
|
|
1813
1930
|
});
|
|
1814
1931
|
}
|
|
1815
1932
|
|
|
1933
|
+
const MAX_DEPTH = DEFAULT_FORM_DATA_MAX_DEPTH;
|
|
1934
|
+
function throwIfDepthExceeded(index) {
|
|
1935
|
+
if (index > MAX_DEPTH) {
|
|
1936
|
+
throw new AxiosError('FormData field is too deeply nested (' + index + ' levels). Max depth: ' + MAX_DEPTH, AxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED);
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1816
1940
|
/**
|
|
1817
1941
|
* It takes a string like `foo[x][y][z]` and returns an array like `['foo', 'x', 'y', 'z']
|
|
1818
1942
|
*
|
|
@@ -1825,9 +1949,14 @@ function parsePropPath(name) {
|
|
|
1825
1949
|
// foo.x.y.z
|
|
1826
1950
|
// foo-x-y-z
|
|
1827
1951
|
// foo x y z
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1952
|
+
const path = [];
|
|
1953
|
+
const pattern = /\w+|\[(\w*)]/g;
|
|
1954
|
+
let match;
|
|
1955
|
+
while ((match = pattern.exec(name)) !== null) {
|
|
1956
|
+
throwIfDepthExceeded(path.length);
|
|
1957
|
+
path.push(match[0] === '[]' ? '' : match[1] || match[0]);
|
|
1958
|
+
}
|
|
1959
|
+
return path;
|
|
1831
1960
|
}
|
|
1832
1961
|
|
|
1833
1962
|
/**
|
|
@@ -1859,6 +1988,7 @@ function arrayToObject(arr) {
|
|
|
1859
1988
|
*/
|
|
1860
1989
|
function formDataToJSON(formData) {
|
|
1861
1990
|
function buildPath(path, value, target, index) {
|
|
1991
|
+
throwIfDepthExceeded(index);
|
|
1862
1992
|
let name = path[index++];
|
|
1863
1993
|
if (name === '__proto__') return true;
|
|
1864
1994
|
const isNumericKey = Number.isFinite(+name);
|
|
@@ -2099,6 +2229,24 @@ function combineURLs(baseURL, relativeURL) {
|
|
|
2099
2229
|
return relativeURL ? baseURL.replace(/\/?\/$/, '') + '/' + relativeURL.replace(/^\/+/, '') : baseURL;
|
|
2100
2230
|
}
|
|
2101
2231
|
|
|
2232
|
+
const malformedHttpProtocol = /^https?:(?!\/\/)/i;
|
|
2233
|
+
const httpProtocolControlCharacters = /[\t\n\r]/g;
|
|
2234
|
+
function stripLeadingC0ControlOrSpace(url) {
|
|
2235
|
+
let i = 0;
|
|
2236
|
+
while (i < url.length && url.charCodeAt(i) <= 0x20) {
|
|
2237
|
+
i++;
|
|
2238
|
+
}
|
|
2239
|
+
return url.slice(i);
|
|
2240
|
+
}
|
|
2241
|
+
function normalizeURLForProtocolCheck(url) {
|
|
2242
|
+
return stripLeadingC0ControlOrSpace(url).replace(httpProtocolControlCharacters, '');
|
|
2243
|
+
}
|
|
2244
|
+
function assertValidHttpProtocolURL(url, config) {
|
|
2245
|
+
if (typeof url === 'string' && malformedHttpProtocol.test(normalizeURLForProtocolCheck(url))) {
|
|
2246
|
+
throw new AxiosError('Invalid URL: missing "//" after protocol', AxiosError.ERR_INVALID_URL, config);
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
|
|
2102
2250
|
/**
|
|
2103
2251
|
* Creates a new URL by combining the baseURL with the requestedURL,
|
|
2104
2252
|
* only when the requestedURL is not already an absolute URL.
|
|
@@ -2109,9 +2257,11 @@ function combineURLs(baseURL, relativeURL) {
|
|
|
2109
2257
|
*
|
|
2110
2258
|
* @returns {string} The combined full path
|
|
2111
2259
|
*/
|
|
2112
|
-
function buildFullPath(baseURL, requestedURL, allowAbsoluteUrls) {
|
|
2260
|
+
function buildFullPath(baseURL, requestedURL, allowAbsoluteUrls, config) {
|
|
2261
|
+
assertValidHttpProtocolURL(requestedURL, config);
|
|
2113
2262
|
let isRelativeUrl = !isAbsoluteURL(requestedURL);
|
|
2114
2263
|
if (baseURL && (isRelativeUrl || allowAbsoluteUrls === false)) {
|
|
2264
|
+
assertValidHttpProtocolURL(baseURL, config);
|
|
2115
2265
|
return combineURLs(baseURL, requestedURL);
|
|
2116
2266
|
}
|
|
2117
2267
|
return requestedURL;
|
|
@@ -2213,7 +2363,7 @@ function getEnv(key) {
|
|
|
2213
2363
|
return process.env[key.toLowerCase()] || process.env[key.toUpperCase()] || '';
|
|
2214
2364
|
}
|
|
2215
2365
|
|
|
2216
|
-
const VERSION = "1.
|
|
2366
|
+
const VERSION = "1.18.0";
|
|
2217
2367
|
|
|
2218
2368
|
function parseProtocol(url) {
|
|
2219
2369
|
const match = /^([-+\w]{1,25}):(?:\/\/)?/.exec(url);
|
|
@@ -2452,10 +2602,10 @@ const formDataToStream = (form, headersHandler, options) => {
|
|
|
2452
2602
|
boundary = tag + '-' + platform.generateString(size, BOUNDARY_ALPHABET)
|
|
2453
2603
|
} = options || {};
|
|
2454
2604
|
if (!utils$1.isFormData(form)) {
|
|
2455
|
-
throw TypeError('FormData instance required');
|
|
2605
|
+
throw new TypeError('FormData instance required');
|
|
2456
2606
|
}
|
|
2457
2607
|
if (boundary.length < 1 || boundary.length > 70) {
|
|
2458
|
-
throw Error('boundary must be 1-70 characters long');
|
|
2608
|
+
throw new Error('boundary must be 1-70 characters long');
|
|
2459
2609
|
}
|
|
2460
2610
|
const boundaryBytes = textEncoder.encode('--' + boundary + CRLF);
|
|
2461
2611
|
const footerBytes = textEncoder.encode('--' + boundary + '--' + CRLF);
|
|
@@ -2505,6 +2655,84 @@ class ZlibHeaderTransformStream extends stream.Transform {
|
|
|
2505
2655
|
}
|
|
2506
2656
|
}
|
|
2507
2657
|
|
|
2658
|
+
class Http2Sessions {
|
|
2659
|
+
constructor() {
|
|
2660
|
+
this.sessions = Object.create(null);
|
|
2661
|
+
}
|
|
2662
|
+
getSession(authority, options) {
|
|
2663
|
+
options = Object.assign({
|
|
2664
|
+
sessionTimeout: 1000
|
|
2665
|
+
}, options);
|
|
2666
|
+
let authoritySessions = this.sessions[authority];
|
|
2667
|
+
if (authoritySessions) {
|
|
2668
|
+
let len = authoritySessions.length;
|
|
2669
|
+
for (let i = 0; i < len; i++) {
|
|
2670
|
+
const [sessionHandle, sessionOptions] = authoritySessions[i];
|
|
2671
|
+
if (!sessionHandle.destroyed && !sessionHandle.closed && util.isDeepStrictEqual(sessionOptions, options)) {
|
|
2672
|
+
return sessionHandle;
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
const session = http2.connect(authority, options);
|
|
2677
|
+
let removed;
|
|
2678
|
+
let timer;
|
|
2679
|
+
const removeSession = () => {
|
|
2680
|
+
if (removed) {
|
|
2681
|
+
return;
|
|
2682
|
+
}
|
|
2683
|
+
removed = true;
|
|
2684
|
+
if (timer) {
|
|
2685
|
+
clearTimeout(timer);
|
|
2686
|
+
timer = null;
|
|
2687
|
+
}
|
|
2688
|
+
let entries = authoritySessions,
|
|
2689
|
+
len = entries.length,
|
|
2690
|
+
i = len;
|
|
2691
|
+
while (i--) {
|
|
2692
|
+
if (entries[i][0] === session) {
|
|
2693
|
+
if (len === 1) {
|
|
2694
|
+
delete this.sessions[authority];
|
|
2695
|
+
} else {
|
|
2696
|
+
entries.splice(i, 1);
|
|
2697
|
+
}
|
|
2698
|
+
if (!session.closed) {
|
|
2699
|
+
session.close();
|
|
2700
|
+
}
|
|
2701
|
+
return;
|
|
2702
|
+
}
|
|
2703
|
+
}
|
|
2704
|
+
};
|
|
2705
|
+
const originalRequestFn = session.request;
|
|
2706
|
+
const {
|
|
2707
|
+
sessionTimeout
|
|
2708
|
+
} = options;
|
|
2709
|
+
if (sessionTimeout != null) {
|
|
2710
|
+
let streamsCount = 0;
|
|
2711
|
+
session.request = function () {
|
|
2712
|
+
const stream = originalRequestFn.apply(this, arguments);
|
|
2713
|
+
streamsCount++;
|
|
2714
|
+
if (timer) {
|
|
2715
|
+
clearTimeout(timer);
|
|
2716
|
+
timer = null;
|
|
2717
|
+
}
|
|
2718
|
+
stream.once('close', () => {
|
|
2719
|
+
if (! --streamsCount) {
|
|
2720
|
+
timer = setTimeout(() => {
|
|
2721
|
+
timer = null;
|
|
2722
|
+
removeSession();
|
|
2723
|
+
}, sessionTimeout);
|
|
2724
|
+
}
|
|
2725
|
+
});
|
|
2726
|
+
return stream;
|
|
2727
|
+
};
|
|
2728
|
+
}
|
|
2729
|
+
session.once('close', removeSession);
|
|
2730
|
+
let entry = [session, options];
|
|
2731
|
+
authoritySessions ? authoritySessions.push(entry) : authoritySessions = this.sessions[authority] = [entry];
|
|
2732
|
+
return session;
|
|
2733
|
+
}
|
|
2734
|
+
}
|
|
2735
|
+
|
|
2508
2736
|
const callbackify = (fn, reducer) => {
|
|
2509
2737
|
return utils$1.isAsyncFn(fn) ? function (...args) {
|
|
2510
2738
|
const cb = args.pop();
|
|
@@ -2518,13 +2746,34 @@ const callbackify = (fn, reducer) => {
|
|
|
2518
2746
|
} : fn;
|
|
2519
2747
|
};
|
|
2520
2748
|
|
|
2521
|
-
const LOOPBACK_HOSTNAMES = new Set(['localhost']);
|
|
2749
|
+
const LOOPBACK_HOSTNAMES = new Set(['localhost', '0.0.0.0']);
|
|
2522
2750
|
const isIPv4Loopback = host => {
|
|
2523
2751
|
const parts = host.split('.');
|
|
2524
2752
|
if (parts.length !== 4) return false;
|
|
2525
2753
|
if (parts[0] !== '127') return false;
|
|
2526
2754
|
return parts.every(p => /^\d+$/.test(p) && Number(p) >= 0 && Number(p) <= 255);
|
|
2527
2755
|
};
|
|
2756
|
+
const isIPv6ZeroGroup = group => /^0{1,4}$/.test(group);
|
|
2757
|
+
|
|
2758
|
+
// The unspecified address (IPv4 0.0.0.0 / IPv6 ::) resolves to the local host
|
|
2759
|
+
// for outbound connections, so treat it as loopback-equivalent for NO_PROXY
|
|
2760
|
+
// matching. 0.0.0.0 is covered by LOOPBACK_HOSTNAMES; this handles compressed
|
|
2761
|
+
// and full IPv6 all-zero forms so both families bypass symmetrically.
|
|
2762
|
+
const isIPv6Unspecified = host => {
|
|
2763
|
+
if (host === '::') return true;
|
|
2764
|
+
const compressionIndex = host.indexOf('::');
|
|
2765
|
+
if (compressionIndex !== -1) {
|
|
2766
|
+
if (compressionIndex !== host.lastIndexOf('::')) return false;
|
|
2767
|
+
const left = host.slice(0, compressionIndex);
|
|
2768
|
+
const right = host.slice(compressionIndex + 2);
|
|
2769
|
+
const leftGroups = left ? left.split(':') : [];
|
|
2770
|
+
const rightGroups = right ? right.split(':') : [];
|
|
2771
|
+
const explicitGroups = leftGroups.length + rightGroups.length;
|
|
2772
|
+
return explicitGroups < 8 && leftGroups.every(isIPv6ZeroGroup) && rightGroups.every(isIPv6ZeroGroup);
|
|
2773
|
+
}
|
|
2774
|
+
const groups = host.split(':');
|
|
2775
|
+
return groups.length === 8 && groups.every(isIPv6ZeroGroup);
|
|
2776
|
+
};
|
|
2528
2777
|
const isIPv6Loopback = host => {
|
|
2529
2778
|
// Collapse all-zero groups: any form of ::1 / 0:0:...:0:1
|
|
2530
2779
|
// First, strip any leading "::" by normalising with Set lookup of common forms,
|
|
@@ -2557,6 +2806,7 @@ const isLoopback = host => {
|
|
|
2557
2806
|
if (!host) return false;
|
|
2558
2807
|
if (LOOPBACK_HOSTNAMES.has(host)) return true;
|
|
2559
2808
|
if (isIPv4Loopback(host)) return true;
|
|
2809
|
+
if (isIPv6Unspecified(host)) return true;
|
|
2560
2810
|
return isIPv6Loopback(host);
|
|
2561
2811
|
};
|
|
2562
2812
|
const DEFAULT_PORTS = {
|
|
@@ -2776,11 +3026,13 @@ const asyncDecorator = fn => (...args) => utils$1.asap(() => fn(...args));
|
|
|
2776
3026
|
* Estimate decoded byte length of a data:// URL *without* allocating large buffers.
|
|
2777
3027
|
* - For base64: compute exact decoded size using length and padding;
|
|
2778
3028
|
* handle %XX at the character-count level (no string allocation).
|
|
2779
|
-
* - For non-base64:
|
|
3029
|
+
* - For non-base64: compute the exact percent-decoded UTF-8 byte length.
|
|
2780
3030
|
*
|
|
2781
3031
|
* @param {string} url
|
|
2782
3032
|
* @returns {number}
|
|
2783
3033
|
*/
|
|
3034
|
+
const isHexDigit = charCode => charCode >= 48 && charCode <= 57 || charCode >= 65 && charCode <= 70 || charCode >= 97 && charCode <= 102;
|
|
3035
|
+
const isPercentEncodedByte = (str, i, len) => i + 2 < len && isHexDigit(str.charCodeAt(i + 1)) && isHexDigit(str.charCodeAt(i + 2));
|
|
2784
3036
|
function estimateDataURLDecodedBytes(url) {
|
|
2785
3037
|
if (!url || typeof url !== 'string') return 0;
|
|
2786
3038
|
if (!url.startsWith('data:')) return 0;
|
|
@@ -2797,7 +3049,7 @@ function estimateDataURLDecodedBytes(url) {
|
|
|
2797
3049
|
if (body.charCodeAt(i) === 37 /* '%' */ && i + 2 < len) {
|
|
2798
3050
|
const a = body.charCodeAt(i + 1);
|
|
2799
3051
|
const b = body.charCodeAt(i + 2);
|
|
2800
|
-
const isHex = (a
|
|
3052
|
+
const isHex = isHexDigit(a) && isHexDigit(b);
|
|
2801
3053
|
if (isHex) {
|
|
2802
3054
|
effectiveLen -= 2;
|
|
2803
3055
|
i += 2;
|
|
@@ -2832,18 +3084,18 @@ function estimateDataURLDecodedBytes(url) {
|
|
|
2832
3084
|
const bytes = groups * 3 - (pad || 0);
|
|
2833
3085
|
return bytes > 0 ? bytes : 0;
|
|
2834
3086
|
}
|
|
2835
|
-
if (typeof Buffer !== 'undefined' && typeof Buffer.byteLength === 'function') {
|
|
2836
|
-
return Buffer.byteLength(body, 'utf8');
|
|
2837
|
-
}
|
|
2838
3087
|
|
|
2839
3088
|
// Compute UTF-8 byte length directly from UTF-16 code units without allocating
|
|
2840
3089
|
// a byte buffer (TextEncoder.encode would defeat the DoS guard on large bodies).
|
|
2841
|
-
//
|
|
2842
|
-
//
|
|
3090
|
+
// Valid %XX triplets count as one decoded byte; this matches the bytes that
|
|
3091
|
+
// decodeURIComponent(body) would produce before Buffer re-encodes the string.
|
|
2843
3092
|
let bytes = 0;
|
|
2844
3093
|
for (let i = 0, len = body.length; i < len; i++) {
|
|
2845
3094
|
const c = body.charCodeAt(i);
|
|
2846
|
-
if (c
|
|
3095
|
+
if (c === 37 /* '%' */ && isPercentEncodedByte(body, i, len)) {
|
|
3096
|
+
bytes += 1;
|
|
3097
|
+
i += 2;
|
|
3098
|
+
} else if (c < 0x80) {
|
|
2847
3099
|
bytes += 1;
|
|
2848
3100
|
} else if (c < 0x800) {
|
|
2849
3101
|
bytes += 2;
|
|
@@ -2870,7 +3122,14 @@ const brotliOptions = {
|
|
|
2870
3122
|
flush: zlib.constants.BROTLI_OPERATION_FLUSH,
|
|
2871
3123
|
finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH
|
|
2872
3124
|
};
|
|
3125
|
+
const zstdOptions = {
|
|
3126
|
+
flush: zlib.constants.ZSTD_e_flush,
|
|
3127
|
+
finishFlush: zlib.constants.ZSTD_e_flush
|
|
3128
|
+
};
|
|
2873
3129
|
const isBrotliSupported = utils$1.isFunction(zlib.createBrotliDecompress);
|
|
3130
|
+
const isZstdSupported = utils$1.isFunction(zlib.createZstdDecompress);
|
|
3131
|
+
const ACCEPT_ENCODING = 'gzip, compress, deflate' + (isBrotliSupported ? ', br' : '');
|
|
3132
|
+
const ACCEPT_ENCODING_WITH_ZSTD = ACCEPT_ENCODING + (isZstdSupported ? ', zstd' : '');
|
|
2874
3133
|
const {
|
|
2875
3134
|
http: httpFollow,
|
|
2876
3135
|
https: httpsFollow
|
|
@@ -2918,6 +3177,19 @@ function getTunnelingAgent(agentOptions, userHttpsAgent) {
|
|
|
2918
3177
|
...agentOptions
|
|
2919
3178
|
} : agentOptions;
|
|
2920
3179
|
agent = new HttpsProxyAgent(merged);
|
|
3180
|
+
if (userHttpsAgent && userHttpsAgent.options) {
|
|
3181
|
+
const originTLSOptions = {
|
|
3182
|
+
...userHttpsAgent.options
|
|
3183
|
+
};
|
|
3184
|
+
const callback = agent.callback;
|
|
3185
|
+
agent.callback = function axiosTunnelingAgentCallback(req, opts) {
|
|
3186
|
+
// HttpsProxyAgent v5 reads callback opts for the post-CONNECT origin TLS upgrade.
|
|
3187
|
+
return callback.call(this, req, {
|
|
3188
|
+
...originTLSOptions,
|
|
3189
|
+
...opts
|
|
3190
|
+
});
|
|
3191
|
+
};
|
|
3192
|
+
}
|
|
2921
3193
|
agent[kAxiosInstalledTunnel] = true;
|
|
2922
3194
|
cache.set(key, agent);
|
|
2923
3195
|
return agent;
|
|
@@ -2930,7 +3202,7 @@ const supportedProtocols = platform.protocols.map(protocol => {
|
|
|
2930
3202
|
// Decode before composing the `auth` option so credentials such as
|
|
2931
3203
|
// `my%40email.com:pass` are sent as `my@email.com:pass`. Falls back to the
|
|
2932
3204
|
// original value for malformed input so a bad encoding never throws.
|
|
2933
|
-
const decodeURIComponentSafe = value => {
|
|
3205
|
+
const decodeURIComponentSafe$1 = value => {
|
|
2934
3206
|
if (!utils$1.isString(value)) {
|
|
2935
3207
|
return value;
|
|
2936
3208
|
}
|
|
@@ -2944,84 +3216,11 @@ const flushOnFinish = (stream, [throttled, flush]) => {
|
|
|
2944
3216
|
stream.on('end', flush).on('error', flush);
|
|
2945
3217
|
return throttled;
|
|
2946
3218
|
};
|
|
2947
|
-
class Http2Sessions {
|
|
2948
|
-
constructor() {
|
|
2949
|
-
this.sessions = Object.create(null);
|
|
2950
|
-
}
|
|
2951
|
-
getSession(authority, options) {
|
|
2952
|
-
options = Object.assign({
|
|
2953
|
-
sessionTimeout: 1000
|
|
2954
|
-
}, options);
|
|
2955
|
-
let authoritySessions = this.sessions[authority];
|
|
2956
|
-
if (authoritySessions) {
|
|
2957
|
-
let len = authoritySessions.length;
|
|
2958
|
-
for (let i = 0; i < len; i++) {
|
|
2959
|
-
const [sessionHandle, sessionOptions] = authoritySessions[i];
|
|
2960
|
-
if (!sessionHandle.destroyed && !sessionHandle.closed && util.isDeepStrictEqual(sessionOptions, options)) {
|
|
2961
|
-
return sessionHandle;
|
|
2962
|
-
}
|
|
2963
|
-
}
|
|
2964
|
-
}
|
|
2965
|
-
const session = http2.connect(authority, options);
|
|
2966
|
-
let removed;
|
|
2967
|
-
const removeSession = () => {
|
|
2968
|
-
if (removed) {
|
|
2969
|
-
return;
|
|
2970
|
-
}
|
|
2971
|
-
removed = true;
|
|
2972
|
-
let entries = authoritySessions,
|
|
2973
|
-
len = entries.length,
|
|
2974
|
-
i = len;
|
|
2975
|
-
while (i--) {
|
|
2976
|
-
if (entries[i][0] === session) {
|
|
2977
|
-
if (len === 1) {
|
|
2978
|
-
delete this.sessions[authority];
|
|
2979
|
-
} else {
|
|
2980
|
-
entries.splice(i, 1);
|
|
2981
|
-
}
|
|
2982
|
-
if (!session.closed) {
|
|
2983
|
-
session.close();
|
|
2984
|
-
}
|
|
2985
|
-
return;
|
|
2986
|
-
}
|
|
2987
|
-
}
|
|
2988
|
-
};
|
|
2989
|
-
const originalRequestFn = session.request;
|
|
2990
|
-
const {
|
|
2991
|
-
sessionTimeout
|
|
2992
|
-
} = options;
|
|
2993
|
-
if (sessionTimeout != null) {
|
|
2994
|
-
let timer;
|
|
2995
|
-
let streamsCount = 0;
|
|
2996
|
-
session.request = function () {
|
|
2997
|
-
const stream = originalRequestFn.apply(this, arguments);
|
|
2998
|
-
streamsCount++;
|
|
2999
|
-
if (timer) {
|
|
3000
|
-
clearTimeout(timer);
|
|
3001
|
-
timer = null;
|
|
3002
|
-
}
|
|
3003
|
-
stream.once('close', () => {
|
|
3004
|
-
if (! --streamsCount) {
|
|
3005
|
-
timer = setTimeout(() => {
|
|
3006
|
-
timer = null;
|
|
3007
|
-
removeSession();
|
|
3008
|
-
}, sessionTimeout);
|
|
3009
|
-
}
|
|
3010
|
-
});
|
|
3011
|
-
return stream;
|
|
3012
|
-
};
|
|
3013
|
-
}
|
|
3014
|
-
session.once('close', removeSession);
|
|
3015
|
-
let entry = [session, options];
|
|
3016
|
-
authoritySessions ? authoritySessions.push(entry) : authoritySessions = this.sessions[authority] = [entry];
|
|
3017
|
-
return session;
|
|
3018
|
-
}
|
|
3019
|
-
}
|
|
3020
3219
|
const http2Sessions = new Http2Sessions();
|
|
3021
3220
|
|
|
3022
3221
|
/**
|
|
3023
|
-
* If the proxy or config beforeRedirects functions are defined,
|
|
3024
|
-
* object.
|
|
3222
|
+
* If the proxy, auth, sensitive header, or config beforeRedirects functions are defined,
|
|
3223
|
+
* call them with the options object.
|
|
3025
3224
|
*
|
|
3026
3225
|
* @param {Object<string, any>} options - The options object that was passed to the request.
|
|
3027
3226
|
*
|
|
@@ -3031,10 +3230,37 @@ function dispatchBeforeRedirect(options, responseDetails, requestDetails) {
|
|
|
3031
3230
|
if (options.beforeRedirects.proxy) {
|
|
3032
3231
|
options.beforeRedirects.proxy(options);
|
|
3033
3232
|
}
|
|
3233
|
+
if (options.beforeRedirects.auth) {
|
|
3234
|
+
options.beforeRedirects.auth(options);
|
|
3235
|
+
}
|
|
3236
|
+
if (options.beforeRedirects.sensitiveHeaders) {
|
|
3237
|
+
options.beforeRedirects.sensitiveHeaders(options, requestDetails);
|
|
3238
|
+
}
|
|
3034
3239
|
if (options.beforeRedirects.config) {
|
|
3035
3240
|
options.beforeRedirects.config(options, responseDetails, requestDetails);
|
|
3036
3241
|
}
|
|
3037
3242
|
}
|
|
3243
|
+
function stripMatchingHeaders(headers, sensitiveSet) {
|
|
3244
|
+
if (!headers) {
|
|
3245
|
+
return;
|
|
3246
|
+
}
|
|
3247
|
+
Object.keys(headers).forEach(header => {
|
|
3248
|
+
if (sensitiveSet.has(header.toLowerCase())) {
|
|
3249
|
+
delete headers[header];
|
|
3250
|
+
}
|
|
3251
|
+
});
|
|
3252
|
+
}
|
|
3253
|
+
function isSameOriginRedirect(redirectOptions, requestDetails) {
|
|
3254
|
+
if (!requestDetails) {
|
|
3255
|
+
return false;
|
|
3256
|
+
}
|
|
3257
|
+
try {
|
|
3258
|
+
return new URL(requestDetails.url).origin === new URL(redirectOptions.href).origin;
|
|
3259
|
+
} catch (e) {
|
|
3260
|
+
// If origin comparison fails, treat the redirect as unsafe.
|
|
3261
|
+
return false;
|
|
3262
|
+
}
|
|
3263
|
+
}
|
|
3038
3264
|
|
|
3039
3265
|
/**
|
|
3040
3266
|
* If the proxy or config afterRedirects functions are defined, call them with the options
|
|
@@ -3138,7 +3364,7 @@ function setProxy(options, configProxy, location, isRedirect, configHttpsAgent)
|
|
|
3138
3364
|
}
|
|
3139
3365
|
const tunnelingAgent = getTunnelingAgent(agentOptions, configHttpsAgent);
|
|
3140
3366
|
// Set both: `options.agent` is consumed by the native https.request path
|
|
3141
|
-
// (
|
|
3367
|
+
// (maxRedirects === 0); `options.agents.https` is consumed by
|
|
3142
3368
|
// follow-redirects, which ignores `options.agent` when `options.agents`
|
|
3143
3369
|
// is present.
|
|
3144
3370
|
options.agent = tunnelingAgent;
|
|
@@ -3265,7 +3491,13 @@ const http2Transport = {
|
|
|
3265
3491
|
/*eslint consistent-return:0*/
|
|
3266
3492
|
var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
3267
3493
|
return wrapAsync(async function dispatchHttpRequest(resolve, reject, onDone) {
|
|
3268
|
-
|
|
3494
|
+
// Read config pollution-safely: own properties and members inherited from
|
|
3495
|
+
// a non-Object.prototype source (e.g. an Object.create(defaults) template)
|
|
3496
|
+
// are honored, but values injected onto a polluted Object.prototype are
|
|
3497
|
+
// ignored. All behavior-affecting reads in this adapter go through own()
|
|
3498
|
+
// so the protection boundary stays consistent.
|
|
3499
|
+
const own = key => utils$1.getSafeProp(config, key);
|
|
3500
|
+
const transitional = own('transitional') || transitionalDefaults;
|
|
3269
3501
|
let data = own('data');
|
|
3270
3502
|
let lookup = own('lookup');
|
|
3271
3503
|
let family = own('family');
|
|
@@ -3274,7 +3506,13 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3274
3506
|
let http2Options = own('http2Options');
|
|
3275
3507
|
const responseType = own('responseType');
|
|
3276
3508
|
const responseEncoding = own('responseEncoding');
|
|
3277
|
-
const
|
|
3509
|
+
const httpAgent = own('httpAgent');
|
|
3510
|
+
const httpsAgent = own('httpsAgent');
|
|
3511
|
+
const method = own('method').toUpperCase();
|
|
3512
|
+
const maxRedirects = own('maxRedirects');
|
|
3513
|
+
const maxBodyLength = own('maxBodyLength');
|
|
3514
|
+
const maxContentLength = own('maxContentLength');
|
|
3515
|
+
const decompress = own('decompress');
|
|
3278
3516
|
let isDone;
|
|
3279
3517
|
let rejected = false;
|
|
3280
3518
|
let req;
|
|
@@ -3305,7 +3543,7 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3305
3543
|
try {
|
|
3306
3544
|
abortEmitter.emit('abort', !reason || reason.type ? new CanceledError(null, config, req) : reason);
|
|
3307
3545
|
} catch (err) {
|
|
3308
|
-
|
|
3546
|
+
// ignore emit errors
|
|
3309
3547
|
}
|
|
3310
3548
|
}
|
|
3311
3549
|
function clearConnectPhaseTimer() {
|
|
@@ -3315,10 +3553,11 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3315
3553
|
}
|
|
3316
3554
|
}
|
|
3317
3555
|
function createTimeoutError() {
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3556
|
+
const configTimeout = own('timeout');
|
|
3557
|
+
let timeoutErrorMessage = configTimeout ? 'timeout of ' + configTimeout + 'ms exceeded' : 'timeout exceeded';
|
|
3558
|
+
const configTimeoutErrorMessage = own('timeoutErrorMessage');
|
|
3559
|
+
if (configTimeoutErrorMessage) {
|
|
3560
|
+
timeoutErrorMessage = configTimeoutErrorMessage;
|
|
3322
3561
|
}
|
|
3323
3562
|
return new AxiosError(timeoutErrorMessage, transitional.clarifyTimeoutError ? AxiosError.ETIMEDOUT : AxiosError.ECONNABORTED, config, req);
|
|
3324
3563
|
}
|
|
@@ -3361,17 +3600,17 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3361
3600
|
});
|
|
3362
3601
|
|
|
3363
3602
|
// Parse url
|
|
3364
|
-
const fullPath = buildFullPath(
|
|
3603
|
+
const fullPath = buildFullPath(own('baseURL'), own('url'), own('allowAbsoluteUrls'), config);
|
|
3365
3604
|
const parsed = new URL(fullPath, platform.hasBrowserEnv ? platform.origin : undefined);
|
|
3366
3605
|
const protocol = parsed.protocol || supportedProtocols[0];
|
|
3367
3606
|
if (protocol === 'data:') {
|
|
3368
3607
|
// Apply the same semantics as HTTP: only enforce if a finite, non-negative cap is set.
|
|
3369
|
-
if (
|
|
3370
|
-
// Use the exact string passed to fromDataURI (
|
|
3371
|
-
const dataUrl = String(
|
|
3608
|
+
if (maxContentLength > -1) {
|
|
3609
|
+
// Use the exact string passed to fromDataURI (the configured url); fall back to fullPath if needed.
|
|
3610
|
+
const dataUrl = String(own('url') || fullPath || '');
|
|
3372
3611
|
const estimated = estimateDataURLDecodedBytes(dataUrl);
|
|
3373
|
-
if (estimated >
|
|
3374
|
-
return reject(new AxiosError('maxContentLength size of ' +
|
|
3612
|
+
if (estimated > maxContentLength) {
|
|
3613
|
+
return reject(new AxiosError('maxContentLength size of ' + maxContentLength + ' exceeded', AxiosError.ERR_BAD_RESPONSE, config));
|
|
3375
3614
|
}
|
|
3376
3615
|
}
|
|
3377
3616
|
let convertedData;
|
|
@@ -3384,7 +3623,7 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3384
3623
|
});
|
|
3385
3624
|
}
|
|
3386
3625
|
try {
|
|
3387
|
-
convertedData = fromDataURI(
|
|
3626
|
+
convertedData = fromDataURI(own('url'), responseType === 'blob', {
|
|
3388
3627
|
Blob: config.env && config.env.Blob
|
|
3389
3628
|
});
|
|
3390
3629
|
} catch (err) {
|
|
@@ -3458,7 +3697,7 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3458
3697
|
|
|
3459
3698
|
// Add Content-Length header if data exists
|
|
3460
3699
|
headers.setContentLength(data.length, false);
|
|
3461
|
-
if (
|
|
3700
|
+
if (maxBodyLength > -1 && data.length > maxBodyLength) {
|
|
3462
3701
|
return reject(new AxiosError('Request body larger than maxBodyLength limit', AxiosError.ERR_BAD_REQUEST, config));
|
|
3463
3702
|
}
|
|
3464
3703
|
}
|
|
@@ -3485,27 +3724,27 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3485
3724
|
let auth = undefined;
|
|
3486
3725
|
const configAuth = own('auth');
|
|
3487
3726
|
if (configAuth) {
|
|
3488
|
-
const username = configAuth
|
|
3489
|
-
const password = configAuth
|
|
3727
|
+
const username = utils$1.getSafeProp(configAuth, 'username') || '';
|
|
3728
|
+
const password = utils$1.getSafeProp(configAuth, 'password') || '';
|
|
3490
3729
|
auth = username + ':' + password;
|
|
3491
3730
|
}
|
|
3492
|
-
if (!auth && parsed.username) {
|
|
3493
|
-
const urlUsername = decodeURIComponentSafe(parsed.username);
|
|
3494
|
-
const urlPassword = decodeURIComponentSafe(parsed.password);
|
|
3731
|
+
if (!auth && (parsed.username || parsed.password)) {
|
|
3732
|
+
const urlUsername = decodeURIComponentSafe$1(parsed.username);
|
|
3733
|
+
const urlPassword = decodeURIComponentSafe$1(parsed.password);
|
|
3495
3734
|
auth = urlUsername + ':' + urlPassword;
|
|
3496
3735
|
}
|
|
3497
3736
|
auth && headers.delete('authorization');
|
|
3498
3737
|
let path$1;
|
|
3499
3738
|
try {
|
|
3500
|
-
path$1 = buildURL(parsed.pathname + parsed.search,
|
|
3739
|
+
path$1 = buildURL(parsed.pathname + parsed.search, own('params'), own('paramsSerializer')).replace(/^\?/, '');
|
|
3501
3740
|
} catch (err) {
|
|
3502
3741
|
const customErr = new Error(err.message);
|
|
3503
3742
|
customErr.config = config;
|
|
3504
|
-
customErr.url =
|
|
3743
|
+
customErr.url = own('url');
|
|
3505
3744
|
customErr.exists = true;
|
|
3506
3745
|
return reject(customErr);
|
|
3507
3746
|
}
|
|
3508
|
-
headers.set('Accept-Encoding',
|
|
3747
|
+
headers.set('Accept-Encoding', utils$1.hasOwnProp(transitional, 'advertiseZstdAcceptEncoding') && transitional.advertiseZstdAcceptEncoding === true ? ACCEPT_ENCODING_WITH_ZSTD : ACCEPT_ENCODING, false);
|
|
3509
3748
|
|
|
3510
3749
|
// Null-prototype to block prototype pollution gadgets on properties read
|
|
3511
3750
|
// directly by Node's http.request (e.g. insecureHTTPParser, lookup).
|
|
@@ -3514,8 +3753,8 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3514
3753
|
method: method,
|
|
3515
3754
|
headers: toByteStringHeaderObject(headers),
|
|
3516
3755
|
agents: {
|
|
3517
|
-
http:
|
|
3518
|
-
https:
|
|
3756
|
+
http: httpAgent,
|
|
3757
|
+
https: httpsAgent
|
|
3519
3758
|
},
|
|
3520
3759
|
auth,
|
|
3521
3760
|
protocol,
|
|
@@ -3527,31 +3766,38 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3527
3766
|
|
|
3528
3767
|
// cacheable-lookup integration hotfix
|
|
3529
3768
|
!utils$1.isUndefined(lookup) && (options.lookup = lookup);
|
|
3530
|
-
|
|
3531
|
-
|
|
3769
|
+
const socketPath = own('socketPath');
|
|
3770
|
+
if (socketPath) {
|
|
3771
|
+
if (typeof socketPath !== 'string') {
|
|
3532
3772
|
return reject(new AxiosError('socketPath must be a string', AxiosError.ERR_BAD_OPTION_VALUE, config));
|
|
3533
3773
|
}
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
const
|
|
3774
|
+
const allowedSocketPaths = own('allowedSocketPaths');
|
|
3775
|
+
if (allowedSocketPaths != null) {
|
|
3776
|
+
const allowed = Array.isArray(allowedSocketPaths) ? allowedSocketPaths : [allowedSocketPaths];
|
|
3777
|
+
const resolvedSocket = path.resolve(socketPath);
|
|
3537
3778
|
const isAllowed = allowed.some(entry => typeof entry === 'string' && path.resolve(entry) === resolvedSocket);
|
|
3538
3779
|
if (!isAllowed) {
|
|
3539
|
-
return reject(new AxiosError(`socketPath "${
|
|
3780
|
+
return reject(new AxiosError(`socketPath "${socketPath}" is not permitted by allowedSocketPaths`, AxiosError.ERR_BAD_OPTION_VALUE, config));
|
|
3540
3781
|
}
|
|
3541
3782
|
}
|
|
3542
|
-
options.socketPath =
|
|
3783
|
+
options.socketPath = socketPath;
|
|
3543
3784
|
} else {
|
|
3544
3785
|
options.hostname = parsed.hostname.startsWith('[') ? parsed.hostname.slice(1, -1) : parsed.hostname;
|
|
3545
3786
|
options.port = parsed.port;
|
|
3546
|
-
setProxy(options,
|
|
3787
|
+
setProxy(options, own('proxy'), protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path, false, httpsAgent);
|
|
3547
3788
|
}
|
|
3548
3789
|
let transport;
|
|
3549
3790
|
let isNativeTransport = false;
|
|
3791
|
+
// True only for the follow-redirects transport, which applies
|
|
3792
|
+
// options.maxBodyLength itself. Every other transport (http2, native
|
|
3793
|
+
// http/https, a user-supplied custom transport) needs the explicit
|
|
3794
|
+
// byte-counting pipeline below to enforce maxBodyLength on streamed uploads.
|
|
3795
|
+
let transportEnforcesMaxBodyLength = false;
|
|
3550
3796
|
const isHttpsRequest = isHttps.test(options.protocol);
|
|
3551
3797
|
// Don't clobber a CONNECT-tunneling agent installed by setProxy() for an
|
|
3552
3798
|
// HTTPS target.
|
|
3553
3799
|
if (options.agent == null) {
|
|
3554
|
-
options.agent = isHttpsRequest ?
|
|
3800
|
+
options.agent = isHttpsRequest ? httpsAgent : httpAgent;
|
|
3555
3801
|
}
|
|
3556
3802
|
if (isHttp2) {
|
|
3557
3803
|
transport = http2Transport;
|
|
@@ -3559,22 +3805,62 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3559
3805
|
const configTransport = own('transport');
|
|
3560
3806
|
if (configTransport) {
|
|
3561
3807
|
transport = configTransport;
|
|
3562
|
-
} else if (
|
|
3808
|
+
} else if (maxRedirects === 0) {
|
|
3563
3809
|
transport = isHttpsRequest ? https : http;
|
|
3564
3810
|
isNativeTransport = true;
|
|
3565
3811
|
} else {
|
|
3566
|
-
|
|
3567
|
-
|
|
3812
|
+
transportEnforcesMaxBodyLength = true;
|
|
3813
|
+
options.sensitiveHeaders = [];
|
|
3814
|
+
if (maxRedirects) {
|
|
3815
|
+
options.maxRedirects = maxRedirects;
|
|
3568
3816
|
}
|
|
3569
3817
|
const configBeforeRedirect = own('beforeRedirect');
|
|
3570
3818
|
if (configBeforeRedirect) {
|
|
3571
3819
|
options.beforeRedirects.config = configBeforeRedirect;
|
|
3572
3820
|
}
|
|
3821
|
+
if (auth) {
|
|
3822
|
+
// Restore HTTP Basic credentials on same-origin redirects only.
|
|
3823
|
+
// follow-redirects >= 1.15.8 strips Authorization on every redirect (see #6929);
|
|
3824
|
+
// cross-origin stripping is the documented mitigation for T-R2 in THREATMODEL.md
|
|
3825
|
+
// and is preserved by deliberately not restoring on origin change.
|
|
3826
|
+
const requestOrigin = parsed.origin;
|
|
3827
|
+
const authToRestore = auth;
|
|
3828
|
+
options.beforeRedirects.auth = function beforeRedirectAuth(redirectOptions) {
|
|
3829
|
+
try {
|
|
3830
|
+
if (new URL(redirectOptions.href).origin === requestOrigin) {
|
|
3831
|
+
redirectOptions.auth = authToRestore;
|
|
3832
|
+
}
|
|
3833
|
+
} catch (e) {
|
|
3834
|
+
// ignore malformed URL: leaving auth stripped is fail-safe
|
|
3835
|
+
}
|
|
3836
|
+
};
|
|
3837
|
+
}
|
|
3838
|
+
const sensitiveHeaders = own('sensitiveHeaders');
|
|
3839
|
+
if (sensitiveHeaders != null) {
|
|
3840
|
+
if (!utils$1.isArray(sensitiveHeaders)) {
|
|
3841
|
+
return reject(new AxiosError('sensitiveHeaders must be an array of strings', AxiosError.ERR_BAD_OPTION_VALUE, config));
|
|
3842
|
+
}
|
|
3843
|
+
const sensitiveSet = new Set();
|
|
3844
|
+
for (const header of sensitiveHeaders) {
|
|
3845
|
+
if (!utils$1.isString(header)) {
|
|
3846
|
+
return reject(new AxiosError('sensitiveHeaders must be an array of strings', AxiosError.ERR_BAD_OPTION_VALUE, config));
|
|
3847
|
+
}
|
|
3848
|
+
sensitiveSet.add(header.toLowerCase());
|
|
3849
|
+
}
|
|
3850
|
+
if (sensitiveSet.size) {
|
|
3851
|
+
options.sensitiveHeaders = Array.from(sensitiveSet);
|
|
3852
|
+
options.beforeRedirects.sensitiveHeaders = function beforeRedirectSensitiveHeaders(redirectOptions, requestDetails) {
|
|
3853
|
+
if (!isSameOriginRedirect(redirectOptions, requestDetails)) {
|
|
3854
|
+
stripMatchingHeaders(redirectOptions.headers, sensitiveSet);
|
|
3855
|
+
}
|
|
3856
|
+
};
|
|
3857
|
+
}
|
|
3858
|
+
}
|
|
3573
3859
|
transport = isHttpsRequest ? httpsFollow : httpFollow;
|
|
3574
3860
|
}
|
|
3575
3861
|
}
|
|
3576
|
-
if (
|
|
3577
|
-
options.maxBodyLength =
|
|
3862
|
+
if (maxBodyLength > -1) {
|
|
3863
|
+
options.maxBodyLength = maxBodyLength;
|
|
3578
3864
|
} else {
|
|
3579
3865
|
// follow-redirects does not skip comparison, so it should always succeed for axios -1 unlimited
|
|
3580
3866
|
options.maxBodyLength = Infinity;
|
|
@@ -3606,7 +3892,7 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3606
3892
|
const lastRequest = res.req || req;
|
|
3607
3893
|
|
|
3608
3894
|
// if decompress disabled we should not decompress
|
|
3609
|
-
if (
|
|
3895
|
+
if (decompress !== false && res.headers['content-encoding']) {
|
|
3610
3896
|
// if no content, but headers still say that it is encoded,
|
|
3611
3897
|
// remove the header not confuse downstream operations
|
|
3612
3898
|
if (method === 'HEAD' || res.statusCode === 204) {
|
|
@@ -3638,6 +3924,13 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3638
3924
|
streams.push(zlib.createBrotliDecompress(brotliOptions));
|
|
3639
3925
|
delete res.headers['content-encoding'];
|
|
3640
3926
|
}
|
|
3927
|
+
break;
|
|
3928
|
+
case 'zstd':
|
|
3929
|
+
if (isZstdSupported) {
|
|
3930
|
+
streams.push(zlib.createZstdDecompress(zstdOptions));
|
|
3931
|
+
delete res.headers['content-encoding'];
|
|
3932
|
+
}
|
|
3933
|
+
break;
|
|
3641
3934
|
}
|
|
3642
3935
|
}
|
|
3643
3936
|
responseStream = streams.length > 1 ? stream.pipeline(streams, utils$1.noop) : streams[0];
|
|
@@ -3651,8 +3944,8 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3651
3944
|
if (responseType === 'stream') {
|
|
3652
3945
|
// Enforce maxContentLength on streamed responses; previously this
|
|
3653
3946
|
// was applied only to buffered responses.
|
|
3654
|
-
if (
|
|
3655
|
-
const limit =
|
|
3947
|
+
if (maxContentLength > -1) {
|
|
3948
|
+
const limit = maxContentLength;
|
|
3656
3949
|
const source = responseStream;
|
|
3657
3950
|
async function* enforceMaxContentLength() {
|
|
3658
3951
|
let totalResponseBytes = 0;
|
|
@@ -3678,11 +3971,11 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3678
3971
|
totalResponseBytes += chunk.length;
|
|
3679
3972
|
|
|
3680
3973
|
// make sure the content length is not over the maxContentLength if specified
|
|
3681
|
-
if (
|
|
3974
|
+
if (maxContentLength > -1 && totalResponseBytes > maxContentLength) {
|
|
3682
3975
|
// stream.destroy() emit aborted event before calling reject() on Node.js v16
|
|
3683
3976
|
rejected = true;
|
|
3684
3977
|
responseStream.destroy();
|
|
3685
|
-
abort(new AxiosError('maxContentLength size of ' +
|
|
3978
|
+
abort(new AxiosError('maxContentLength size of ' + maxContentLength + ' exceeded', AxiosError.ERR_BAD_RESPONSE, config, lastRequest));
|
|
3686
3979
|
}
|
|
3687
3980
|
});
|
|
3688
3981
|
responseStream.on('aborted', function handlerStreamAborted() {
|
|
@@ -3775,9 +4068,9 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3775
4068
|
});
|
|
3776
4069
|
|
|
3777
4070
|
// Handle request timeout
|
|
3778
|
-
if (
|
|
4071
|
+
if (own('timeout')) {
|
|
3779
4072
|
// This is forcing a int timeout to avoid problems if the `req` interface doesn't handle other types.
|
|
3780
|
-
const timeout = parseInt(
|
|
4073
|
+
const timeout = parseInt(own('timeout'), 10);
|
|
3781
4074
|
if (Number.isNaN(timeout)) {
|
|
3782
4075
|
abort(new AxiosError('error trying to parse `config.timeout` to int', AxiosError.ERR_BAD_OPTION_VALUE, config, req));
|
|
3783
4076
|
return;
|
|
@@ -3821,12 +4114,13 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3821
4114
|
}
|
|
3822
4115
|
});
|
|
3823
4116
|
|
|
3824
|
-
// Enforce maxBodyLength for streamed uploads on
|
|
3825
|
-
//
|
|
3826
|
-
//
|
|
4117
|
+
// Enforce maxBodyLength for streamed uploads on every transport that
|
|
4118
|
+
// does not apply options.maxBodyLength itself (native http/https, http2,
|
|
4119
|
+
// and user-supplied custom transports). The follow-redirects transport
|
|
4120
|
+
// enforces it on the redirected HTTP/1 path.
|
|
3827
4121
|
let uploadStream = data;
|
|
3828
|
-
if (
|
|
3829
|
-
const limit =
|
|
4122
|
+
if (maxBodyLength > -1 && !transportEnforcesMaxBodyLength) {
|
|
4123
|
+
const limit = maxBodyLength;
|
|
3830
4124
|
let bytesSent = 0;
|
|
3831
4125
|
uploadStream = stream.pipeline([data, new stream.Transform({
|
|
3832
4126
|
transform(chunk, _enc, cb) {
|
|
@@ -3973,6 +4267,23 @@ function mergeConfig(config1, config2) {
|
|
|
3973
4267
|
return getMergedValue(undefined, a);
|
|
3974
4268
|
}
|
|
3975
4269
|
}
|
|
4270
|
+
function getMergedTransitionalOption(prop) {
|
|
4271
|
+
const transitional2 = utils$1.hasOwnProp(config2, 'transitional') ? config2.transitional : undefined;
|
|
4272
|
+
if (!utils$1.isUndefined(transitional2)) {
|
|
4273
|
+
if (utils$1.isPlainObject(transitional2)) {
|
|
4274
|
+
if (utils$1.hasOwnProp(transitional2, prop)) {
|
|
4275
|
+
return transitional2[prop];
|
|
4276
|
+
}
|
|
4277
|
+
} else {
|
|
4278
|
+
return undefined;
|
|
4279
|
+
}
|
|
4280
|
+
}
|
|
4281
|
+
const transitional1 = utils$1.hasOwnProp(config1, 'transitional') ? config1.transitional : undefined;
|
|
4282
|
+
if (utils$1.isPlainObject(transitional1) && utils$1.hasOwnProp(transitional1, prop)) {
|
|
4283
|
+
return transitional1[prop];
|
|
4284
|
+
}
|
|
4285
|
+
return undefined;
|
|
4286
|
+
}
|
|
3976
4287
|
|
|
3977
4288
|
// eslint-disable-next-line consistent-return
|
|
3978
4289
|
function mergeDirectKeys(a, b, prop) {
|
|
@@ -4025,6 +4336,13 @@ function mergeConfig(config1, config2) {
|
|
|
4025
4336
|
const configValue = merge(a, b, prop);
|
|
4026
4337
|
utils$1.isUndefined(configValue) && merge !== mergeDirectKeys || (config[prop] = configValue);
|
|
4027
4338
|
});
|
|
4339
|
+
if (utils$1.hasOwnProp(config2, 'validateStatus') && utils$1.isUndefined(config2.validateStatus) && getMergedTransitionalOption('validateStatusUndefinedResolves') === false) {
|
|
4340
|
+
if (utils$1.hasOwnProp(config1, 'validateStatus')) {
|
|
4341
|
+
config.validateStatus = getMergedValue(undefined, config1.validateStatus);
|
|
4342
|
+
} else {
|
|
4343
|
+
delete config.validateStatus;
|
|
4344
|
+
}
|
|
4345
|
+
}
|
|
4028
4346
|
return config;
|
|
4029
4347
|
}
|
|
4030
4348
|
|
|
@@ -4049,8 +4367,8 @@ function setFormDataHeaders(headers, formHeaders, policy) {
|
|
|
4049
4367
|
*
|
|
4050
4368
|
* @returns {string} UTF-8 bytes as a Latin-1 string
|
|
4051
4369
|
*/
|
|
4052
|
-
const encodeUTF8 = str => encodeURIComponent(str).replace(/%([0-9A-F]{2})/gi, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
|
|
4053
|
-
|
|
4370
|
+
const encodeUTF8$1 = str => encodeURIComponent(str).replace(/%([0-9A-F]{2})/gi, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
|
|
4371
|
+
function resolveConfig(config) {
|
|
4054
4372
|
const newConfig = mergeConfig({}, config);
|
|
4055
4373
|
|
|
4056
4374
|
// Read only own properties to prevent prototype pollution gadgets
|
|
@@ -4066,15 +4384,17 @@ var resolveConfig = config => {
|
|
|
4066
4384
|
const allowAbsoluteUrls = own('allowAbsoluteUrls');
|
|
4067
4385
|
const url = own('url');
|
|
4068
4386
|
newConfig.headers = headers = AxiosHeaders.from(headers);
|
|
4069
|
-
newConfig.url = buildURL(buildFullPath(baseURL, url, allowAbsoluteUrls),
|
|
4387
|
+
newConfig.url = buildURL(buildFullPath(baseURL, url, allowAbsoluteUrls, newConfig), own('params'), own('paramsSerializer'));
|
|
4070
4388
|
|
|
4071
4389
|
// HTTP basic authentication
|
|
4072
4390
|
if (auth) {
|
|
4073
|
-
|
|
4391
|
+
const username = utils$1.getSafeProp(auth, 'username') || '';
|
|
4392
|
+
const password = utils$1.getSafeProp(auth, 'password') || '';
|
|
4393
|
+
headers.set('Authorization', 'Basic ' + btoa(username + ':' + (password ? encodeUTF8$1(password) : '')));
|
|
4074
4394
|
}
|
|
4075
4395
|
if (utils$1.isFormData(data)) {
|
|
4076
|
-
if (platform.hasStandardBrowserEnv || platform.hasStandardBrowserWebWorkerEnv) {
|
|
4077
|
-
headers.setContentType(undefined); // browser handles it
|
|
4396
|
+
if (platform.hasStandardBrowserEnv || platform.hasStandardBrowserWebWorkerEnv || utils$1.isReactNative(data)) {
|
|
4397
|
+
headers.setContentType(undefined); // browser/web worker/RN handles it
|
|
4078
4398
|
} else if (utils$1.isFunction(data.getHeaders)) {
|
|
4079
4399
|
// Node.js FormData (like form-data package)
|
|
4080
4400
|
setFormDataHeaders(headers, data.getHeaders(), own('formDataHeaderPolicy'));
|
|
@@ -4102,7 +4422,7 @@ var resolveConfig = config => {
|
|
|
4102
4422
|
}
|
|
4103
4423
|
}
|
|
4104
4424
|
return newConfig;
|
|
4105
|
-
}
|
|
4425
|
+
}
|
|
4106
4426
|
|
|
4107
4427
|
const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';
|
|
4108
4428
|
var xhrAdapter = isXHRAdapterSupported && function (config) {
|
|
@@ -4403,6 +4723,31 @@ const DEFAULT_CHUNK_SIZE = 64 * 1024;
|
|
|
4403
4723
|
const {
|
|
4404
4724
|
isFunction
|
|
4405
4725
|
} = utils$1;
|
|
4726
|
+
|
|
4727
|
+
/**
|
|
4728
|
+
* Encode a UTF-8 string to a Latin-1 byte string for use with btoa().
|
|
4729
|
+
* This is a modern replacement for the deprecated unescape(encodeURIComponent(str)) pattern.
|
|
4730
|
+
*
|
|
4731
|
+
* @param {string} str The string to encode
|
|
4732
|
+
*
|
|
4733
|
+
* @returns {string} UTF-8 bytes as a Latin-1 string
|
|
4734
|
+
*/
|
|
4735
|
+
const encodeUTF8 = str => encodeURIComponent(str).replace(/%([0-9A-F]{2})/gi, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
|
|
4736
|
+
|
|
4737
|
+
// Node's WHATWG URL parser returns `username` and `password` percent-encoded.
|
|
4738
|
+
// Decode before composing the `auth` option so credentials such as
|
|
4739
|
+
// `my%40email.com:pass` are sent as `my@email.com:pass`. Falls back to the
|
|
4740
|
+
// original value for malformed input so a bad encoding never throws.
|
|
4741
|
+
const decodeURIComponentSafe = value => {
|
|
4742
|
+
if (!utils$1.isString(value)) {
|
|
4743
|
+
return value;
|
|
4744
|
+
}
|
|
4745
|
+
try {
|
|
4746
|
+
return decodeURIComponent(value);
|
|
4747
|
+
} catch (error) {
|
|
4748
|
+
return value;
|
|
4749
|
+
}
|
|
4750
|
+
};
|
|
4406
4751
|
const test = (fn, ...args) => {
|
|
4407
4752
|
try {
|
|
4408
4753
|
return !!fn(...args);
|
|
@@ -4410,6 +4755,14 @@ const test = (fn, ...args) => {
|
|
|
4410
4755
|
return false;
|
|
4411
4756
|
}
|
|
4412
4757
|
};
|
|
4758
|
+
const maybeWithAuthCredentials = url => {
|
|
4759
|
+
const protocolIndex = url.indexOf('://');
|
|
4760
|
+
let urlToCheck = url;
|
|
4761
|
+
if (protocolIndex !== -1) {
|
|
4762
|
+
urlToCheck = urlToCheck.slice(protocolIndex + 3);
|
|
4763
|
+
}
|
|
4764
|
+
return urlToCheck.includes('@') || urlToCheck.includes(':');
|
|
4765
|
+
};
|
|
4413
4766
|
const factory = env => {
|
|
4414
4767
|
const globalObject = utils$1.global !== undefined && utils$1.global !== null ? utils$1.global : globalThis;
|
|
4415
4768
|
const {
|
|
@@ -4513,6 +4866,7 @@ const factory = env => {
|
|
|
4513
4866
|
} = resolveConfig(config);
|
|
4514
4867
|
const hasMaxContentLength = utils$1.isNumber(maxContentLength) && maxContentLength > -1;
|
|
4515
4868
|
const hasMaxBodyLength = utils$1.isNumber(maxBodyLength) && maxBodyLength > -1;
|
|
4869
|
+
const own = key => utils$1.hasOwnProp(config, key) ? config[key] : undefined;
|
|
4516
4870
|
let _fetch = envFetch || fetch;
|
|
4517
4871
|
responseType = responseType ? (responseType + '').toLowerCase() : 'text';
|
|
4518
4872
|
let composedSignal = composeSignals([signal, cancelToken && cancelToken.toAbortSignal()], timeout);
|
|
@@ -4521,7 +4875,46 @@ const factory = env => {
|
|
|
4521
4875
|
composedSignal.unsubscribe();
|
|
4522
4876
|
});
|
|
4523
4877
|
let requestContentLength;
|
|
4878
|
+
|
|
4879
|
+
// AxiosError we raise while the request body is being streamed. Captured
|
|
4880
|
+
// by identity so the catch block can surface it directly, regardless of
|
|
4881
|
+
// how the runtime wraps the resulting fetch rejection (undici exposes it
|
|
4882
|
+
// as `err.cause`; some browsers drop the original error entirely).
|
|
4883
|
+
let pendingBodyError = null;
|
|
4884
|
+
const maxBodyLengthError = () => new AxiosError('Request body larger than maxBodyLength limit', AxiosError.ERR_BAD_REQUEST, config, request);
|
|
4524
4885
|
try {
|
|
4886
|
+
// HTTP basic authentication
|
|
4887
|
+
let auth = undefined;
|
|
4888
|
+
const configAuth = own('auth');
|
|
4889
|
+
if (configAuth) {
|
|
4890
|
+
const username = utils$1.getSafeProp(configAuth, 'username') || '';
|
|
4891
|
+
const password = utils$1.getSafeProp(configAuth, 'password') || '';
|
|
4892
|
+
auth = {
|
|
4893
|
+
username,
|
|
4894
|
+
password
|
|
4895
|
+
};
|
|
4896
|
+
}
|
|
4897
|
+
if (maybeWithAuthCredentials(url)) {
|
|
4898
|
+
const parsedURL = new URL(url, platform.origin);
|
|
4899
|
+
if (!auth && (parsedURL.username || parsedURL.password)) {
|
|
4900
|
+
const urlUsername = decodeURIComponentSafe(parsedURL.username);
|
|
4901
|
+
const urlPassword = decodeURIComponentSafe(parsedURL.password);
|
|
4902
|
+
auth = {
|
|
4903
|
+
username: urlUsername,
|
|
4904
|
+
password: urlPassword
|
|
4905
|
+
};
|
|
4906
|
+
}
|
|
4907
|
+
if (parsedURL.username || parsedURL.password) {
|
|
4908
|
+
parsedURL.username = '';
|
|
4909
|
+
parsedURL.password = '';
|
|
4910
|
+
url = parsedURL.href;
|
|
4911
|
+
}
|
|
4912
|
+
}
|
|
4913
|
+
if (auth) {
|
|
4914
|
+
headers.delete('authorization');
|
|
4915
|
+
headers.set('Authorization', 'Basic ' + btoa(encodeUTF8((auth.username || '') + ':' + (auth.password || ''))));
|
|
4916
|
+
}
|
|
4917
|
+
|
|
4525
4918
|
// Enforce maxContentLength for data: URLs up-front so we never materialize
|
|
4526
4919
|
// an oversized payload. The HTTP adapter applies the same check (see http.js
|
|
4527
4920
|
// "if (protocol === 'data:')" branch).
|
|
@@ -4532,30 +4925,54 @@ const factory = env => {
|
|
|
4532
4925
|
}
|
|
4533
4926
|
}
|
|
4534
4927
|
|
|
4535
|
-
// Enforce maxBodyLength against
|
|
4536
|
-
//
|
|
4537
|
-
//
|
|
4538
|
-
//
|
|
4928
|
+
// Enforce maxBodyLength against known-size bodies before dispatch using
|
|
4929
|
+
// the body's *actual* size — never a caller-declared Content-Length,
|
|
4930
|
+
// which could under-report to slip an oversized body past the check.
|
|
4931
|
+
// Unknown-size streams return undefined here and are counted per-chunk
|
|
4932
|
+
// below as fetch consumes them.
|
|
4539
4933
|
if (hasMaxBodyLength && method !== 'get' && method !== 'head') {
|
|
4540
|
-
const outboundLength = await
|
|
4541
|
-
if (typeof outboundLength === 'number' && isFinite(outboundLength)
|
|
4542
|
-
|
|
4934
|
+
const outboundLength = await getBodyLength(data);
|
|
4935
|
+
if (typeof outboundLength === 'number' && isFinite(outboundLength)) {
|
|
4936
|
+
requestContentLength = outboundLength;
|
|
4937
|
+
if (outboundLength > maxBodyLength) {
|
|
4938
|
+
throw maxBodyLengthError();
|
|
4939
|
+
}
|
|
4543
4940
|
}
|
|
4544
4941
|
}
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
if (utils$1.isFormData(data) && (contentTypeHeader = _request.headers.get('content-type'))) {
|
|
4553
|
-
headers.setContentType(contentTypeHeader);
|
|
4942
|
+
|
|
4943
|
+
// A streamed body under maxBodyLength must be counted as fetch consumes
|
|
4944
|
+
// it; its size is never trusted from a caller-declared Content-Length.
|
|
4945
|
+
const mustEnforceStreamBody = hasMaxBodyLength && (utils$1.isReadableStream(data) || utils$1.isStream(data));
|
|
4946
|
+
const trackRequestStream = (stream, onProgress, flush) => trackStream(stream, DEFAULT_CHUNK_SIZE, loadedBytes => {
|
|
4947
|
+
if (hasMaxBodyLength && loadedBytes > maxBodyLength) {
|
|
4948
|
+
throw pendingBodyError = maxBodyLengthError();
|
|
4554
4949
|
}
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4950
|
+
onProgress && onProgress(loadedBytes);
|
|
4951
|
+
}, flush);
|
|
4952
|
+
if (supportsRequestStream && method !== 'get' && method !== 'head' && (onUploadProgress || mustEnforceStreamBody)) {
|
|
4953
|
+
requestContentLength = requestContentLength == null ? await resolveBodyLength(headers, data) : requestContentLength;
|
|
4954
|
+
|
|
4955
|
+
// A declared length of 0 is only trusted to skip the wrap when we are
|
|
4956
|
+
// not enforcing a stream limit (which must not rely on that header).
|
|
4957
|
+
if (requestContentLength !== 0 || mustEnforceStreamBody) {
|
|
4958
|
+
let _request = new Request(url, {
|
|
4959
|
+
method: 'POST',
|
|
4960
|
+
body: data,
|
|
4961
|
+
duplex: 'half'
|
|
4962
|
+
});
|
|
4963
|
+
let contentTypeHeader;
|
|
4964
|
+
if (utils$1.isFormData(data) && (contentTypeHeader = _request.headers.get('content-type'))) {
|
|
4965
|
+
headers.setContentType(contentTypeHeader);
|
|
4966
|
+
}
|
|
4967
|
+
if (_request.body) {
|
|
4968
|
+
const [onProgress, flush] = onUploadProgress && progressEventDecorator(requestContentLength, progressEventReducer(asyncDecorator(onUploadProgress))) || [];
|
|
4969
|
+
data = trackRequestStream(_request.body, onProgress, flush);
|
|
4970
|
+
}
|
|
4558
4971
|
}
|
|
4972
|
+
} else if (mustEnforceStreamBody && !isRequestSupported && isReadableStreamSupported && method !== 'get' && method !== 'head') {
|
|
4973
|
+
data = trackRequestStream(data);
|
|
4974
|
+
} else if (mustEnforceStreamBody && isRequestSupported && !supportsRequestStream && method !== 'get' && method !== 'head') {
|
|
4975
|
+
throw new AxiosError('Stream request bodies are not supported by the current fetch implementation', AxiosError.ERR_NOT_SUPPORT, config, request);
|
|
4559
4976
|
}
|
|
4560
4977
|
if (!utils$1.isString(withCredentials)) {
|
|
4561
4978
|
withCredentials = withCredentials ? 'include' : 'omit';
|
|
@@ -4587,11 +5004,12 @@ const factory = env => {
|
|
|
4587
5004
|
};
|
|
4588
5005
|
request = isRequestSupported && new Request(url, resolvedOptions);
|
|
4589
5006
|
let response = await (isRequestSupported ? _fetch(request, fetchOptions) : _fetch(url, resolvedOptions));
|
|
5007
|
+
const responseHeaders = AxiosHeaders.from(response.headers);
|
|
4590
5008
|
|
|
4591
5009
|
// Cheap pre-check: if the server honestly declares a content-length that
|
|
4592
5010
|
// already exceeds the cap, reject before we start streaming.
|
|
4593
5011
|
if (hasMaxContentLength) {
|
|
4594
|
-
const declaredLength = utils$1.toFiniteNumber(
|
|
5012
|
+
const declaredLength = utils$1.toFiniteNumber(responseHeaders.getContentLength());
|
|
4595
5013
|
if (declaredLength != null && declaredLength > maxContentLength) {
|
|
4596
5014
|
throw new AxiosError('maxContentLength size of ' + maxContentLength + ' exceeded', AxiosError.ERR_BAD_RESPONSE, config, request);
|
|
4597
5015
|
}
|
|
@@ -4602,7 +5020,7 @@ const factory = env => {
|
|
|
4602
5020
|
['status', 'statusText', 'headers'].forEach(prop => {
|
|
4603
5021
|
options[prop] = response[prop];
|
|
4604
5022
|
});
|
|
4605
|
-
const responseContentLength = utils$1.toFiniteNumber(
|
|
5023
|
+
const responseContentLength = utils$1.toFiniteNumber(responseHeaders.getContentLength());
|
|
4606
5024
|
const [onProgress, flush] = onDownloadProgress && progressEventDecorator(responseContentLength, progressEventReducer(asyncDecorator(onDownloadProgress), true)) || [];
|
|
4607
5025
|
let bytesRead = 0;
|
|
4608
5026
|
const onChunkProgress = loadedBytes => {
|
|
@@ -4664,6 +5082,23 @@ const factory = env => {
|
|
|
4664
5082
|
err !== canceledError && (canceledError.cause = err);
|
|
4665
5083
|
throw canceledError;
|
|
4666
5084
|
}
|
|
5085
|
+
|
|
5086
|
+
// Surface a maxBodyLength violation we raised while the request body was
|
|
5087
|
+
// being streamed. Matching by identity (rather than reading
|
|
5088
|
+
// `err.cause.isAxiosError`) keeps the error deterministic across runtimes
|
|
5089
|
+
// and avoids both prototype-pollution reads and mis-attributing a foreign
|
|
5090
|
+
// AxiosError that merely happened to land in `err.cause`.
|
|
5091
|
+
if (pendingBodyError) {
|
|
5092
|
+
request && !pendingBodyError.request && (pendingBodyError.request = request);
|
|
5093
|
+
throw pendingBodyError;
|
|
5094
|
+
}
|
|
5095
|
+
|
|
5096
|
+
// Re-throw AxiosErrors we raised synchronously (data: URL / content-length
|
|
5097
|
+
// pre-checks, response size enforcement) without re-wrapping them.
|
|
5098
|
+
if (err instanceof AxiosError) {
|
|
5099
|
+
request && !err.request && (err.request = request);
|
|
5100
|
+
throw err;
|
|
5101
|
+
}
|
|
4667
5102
|
if (err && err.name === 'TypeError' && /Load failed|fetch/i.test(err.message)) {
|
|
4668
5103
|
throw Object.assign(new AxiosError('Network Error', AxiosError.ERR_NETWORK, config, request, err && err.response), {
|
|
4669
5104
|
cause: err.cause || err
|
|
@@ -5038,7 +5473,9 @@ class Axios {
|
|
|
5038
5473
|
silentJSONParsing: validators.transitional(validators.boolean),
|
|
5039
5474
|
forcedJSONParsing: validators.transitional(validators.boolean),
|
|
5040
5475
|
clarifyTimeoutError: validators.transitional(validators.boolean),
|
|
5041
|
-
legacyInterceptorReqResOrdering: validators.transitional(validators.boolean)
|
|
5476
|
+
legacyInterceptorReqResOrdering: validators.transitional(validators.boolean),
|
|
5477
|
+
advertiseZstdAcceptEncoding: validators.transitional(validators.boolean),
|
|
5478
|
+
validateStatusUndefinedResolves: validators.transitional(validators.boolean)
|
|
5042
5479
|
}, false);
|
|
5043
5480
|
}
|
|
5044
5481
|
if (paramsSerializer != null) {
|
|
@@ -5135,7 +5572,7 @@ class Axios {
|
|
|
5135
5572
|
}
|
|
5136
5573
|
getUri(config) {
|
|
5137
5574
|
config = mergeConfig(this.defaults, config);
|
|
5138
|
-
const fullPath = buildFullPath(config.baseURL, config.url, config.allowAbsoluteUrls);
|
|
5575
|
+
const fullPath = buildFullPath(config.baseURL, config.url, config.allowAbsoluteUrls, config);
|
|
5139
5576
|
return buildURL(fullPath, config.params, config.paramsSerializer);
|
|
5140
5577
|
}
|
|
5141
5578
|
}
|
|
@@ -5147,7 +5584,7 @@ utils$1.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoDa
|
|
|
5147
5584
|
return this.request(mergeConfig(config || {}, {
|
|
5148
5585
|
method,
|
|
5149
5586
|
url,
|
|
5150
|
-
data: (config
|
|
5587
|
+
data: config && utils$1.hasOwnProp(config, 'data') ? config.data : undefined
|
|
5151
5588
|
}));
|
|
5152
5589
|
};
|
|
5153
5590
|
});
|