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.
@@ -1,4 +1,4 @@
1
- /*! Axios v1.16.1 Copyright (c) 2026 Matt Zabriskie and contributors */
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 (kindOf(val) !== 'object') {
207
+ if (!isObject(val)) {
162
208
  return false;
163
209
  }
164
210
  const prototype = getPrototypeOf(val);
165
- return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(toStringTag in val) && !(iterator in val);
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
- const targetKey = caseless && findKey(result, key) || key;
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
- objs[i] && forEach(objs[i], assignValue);
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
- /* Creating a function that will check if an object has a property. */
650
- const hasOwnProperty = (({
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
- throw new Error('header name must be a non-empty string');
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.isIterable(header)) {
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 ? 100 : options.maxDepth;
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 = JSON.stringify(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
- if (depth > maxDepth) {
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
- const serializeFn = _options && _options.serialize;
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
- return utils$1.matchAll(/\w+|\[(\w*)]/g, name).map(match => {
1829
- return match[0] === '[]' ? '' : match[1] || match[0];
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.16.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: use UTF-8 byteLength of the encoded body as a safe upper bound.
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 >= 48 && a <= 57 || a >= 65 && a <= 70 || a >= 97 && a <= 102) && (b >= 48 && b <= 57 || b >= 65 && b <= 70 || b >= 97 && b <= 102);
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
- // Using body.length here would undercount non-ASCII (e.g. '€' is 1 code unit
2842
- // but 3 UTF-8 bytes).
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 < 0x80) {
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, call them with the options
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
- // (config.maxRedirects === 0); `options.agents.https` is consumed by
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
- const own = key => utils$1.hasOwnProp(config, key) ? config[key] : undefined;
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 method = config.method.toUpperCase();
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
- console.warn('emit error', err);
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
- let timeoutErrorMessage = config.timeout ? 'timeout of ' + config.timeout + 'ms exceeded' : 'timeout exceeded';
3319
- const transitional = config.transitional || transitionalDefaults;
3320
- if (config.timeoutErrorMessage) {
3321
- timeoutErrorMessage = config.timeoutErrorMessage;
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(config.baseURL, config.url, config.allowAbsoluteUrls);
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 (config.maxContentLength > -1) {
3370
- // Use the exact string passed to fromDataURI (config.url); fall back to fullPath if needed.
3371
- const dataUrl = String(config.url || fullPath || '');
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 > config.maxContentLength) {
3374
- return reject(new AxiosError('maxContentLength size of ' + config.maxContentLength + ' exceeded', AxiosError.ERR_BAD_RESPONSE, config));
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(config.url, responseType === 'blob', {
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 (config.maxBodyLength > -1 && data.length > config.maxBodyLength) {
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.username || '';
3489
- const password = configAuth.password || '';
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, config.params, config.paramsSerializer).replace(/^\?/, '');
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 = config.url;
3743
+ customErr.url = own('url');
3505
3744
  customErr.exists = true;
3506
3745
  return reject(customErr);
3507
3746
  }
3508
- headers.set('Accept-Encoding', 'gzip, compress, deflate' + (isBrotliSupported ? ', br' : ''), false);
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: config.httpAgent,
3518
- https: config.httpsAgent
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
- if (config.socketPath) {
3531
- if (typeof config.socketPath !== 'string') {
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
- if (config.allowedSocketPaths != null) {
3535
- const allowed = Array.isArray(config.allowedSocketPaths) ? config.allowedSocketPaths : [config.allowedSocketPaths];
3536
- const resolvedSocket = path.resolve(config.socketPath);
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 "${config.socketPath}" is not permitted by allowedSocketPaths`, AxiosError.ERR_BAD_OPTION_VALUE, config));
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 = config.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, config.proxy, protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path, false, config.httpsAgent);
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 ? config.httpsAgent : config.httpAgent;
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 (config.maxRedirects === 0) {
3808
+ } else if (maxRedirects === 0) {
3563
3809
  transport = isHttpsRequest ? https : http;
3564
3810
  isNativeTransport = true;
3565
3811
  } else {
3566
- if (config.maxRedirects) {
3567
- options.maxRedirects = config.maxRedirects;
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 (config.maxBodyLength > -1) {
3577
- options.maxBodyLength = config.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 (config.decompress !== false && res.headers['content-encoding']) {
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 (config.maxContentLength > -1) {
3655
- const limit = config.maxContentLength;
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 (config.maxContentLength > -1 && totalResponseBytes > config.maxContentLength) {
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 ' + config.maxContentLength + ' exceeded', AxiosError.ERR_BAD_RESPONSE, config, lastRequest));
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 (config.timeout) {
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(config.timeout, 10);
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 the native http/https
3825
- // transport (maxRedirects === 0); follow-redirects enforces it on the
3826
- // other path.
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 (config.maxBodyLength > -1 && config.maxRedirects === 0) {
3829
- const limit = config.maxBodyLength;
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
- var resolveConfig = config => {
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), config.params, config.paramsSerializer);
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
- headers.set('Authorization', 'Basic ' + btoa((auth.username || '') + ':' + (auth.password ? encodeUTF8(auth.password) : '')));
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 the outbound request body before dispatch.
4536
- // Mirrors http.js behavior (ERR_BAD_REQUEST / 'Request body larger than
4537
- // maxBodyLength limit'). Skip when the body length cannot be determined
4538
- // (e.g. a live ReadableStream supplied by the caller).
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 resolveBodyLength(headers, data);
4541
- if (typeof outboundLength === 'number' && isFinite(outboundLength) && outboundLength > maxBodyLength) {
4542
- throw new AxiosError('Request body larger than maxBodyLength limit', AxiosError.ERR_BAD_REQUEST, config, request);
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
- if (onUploadProgress && supportsRequestStream && method !== 'get' && method !== 'head' && (requestContentLength = await resolveBodyLength(headers, data)) !== 0) {
4546
- let _request = new Request(url, {
4547
- method: 'POST',
4548
- body: data,
4549
- duplex: 'half'
4550
- });
4551
- let contentTypeHeader;
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
- if (_request.body) {
4556
- const [onProgress, flush] = progressEventDecorator(requestContentLength, progressEventReducer(asyncDecorator(onUploadProgress)));
4557
- data = trackStream(_request.body, DEFAULT_CHUNK_SIZE, onProgress, flush);
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(response.headers.get('content-length'));
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(response.headers.get('content-length'));
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 || {}).data
5587
+ data: config && utils$1.hasOwnProp(config, 'data') ? config.data : undefined
5151
5588
  }));
5152
5589
  };
5153
5590
  });