axios 1.16.0 → 1.17.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 +113 -0
- package/README.md +280 -245
- package/dist/axios.js +192 -72
- package/dist/axios.min.js +2 -2
- package/dist/axios.min.js.map +1 -1
- package/dist/browser/axios.cjs +215 -77
- package/dist/esm/axios.js +215 -77
- package/dist/esm/axios.min.js +2 -2
- package/dist/esm/axios.min.js.map +1 -1
- package/dist/node/axios.cjs +453 -190
- package/index.d.cts +9 -4
- package/index.d.ts +5 -2
- package/lib/adapters/fetch.js +85 -2
- package/lib/adapters/http.js +201 -147
- package/lib/adapters/xhr.js +2 -1
- package/lib/core/Axios.js +1 -0
- package/lib/core/AxiosHeaders.js +3 -35
- package/lib/defaults/transitional.js +1 -0
- package/lib/env/data.js +1 -1
- package/lib/helpers/Http2Sessions.js +119 -0
- package/lib/helpers/buildURL.js +1 -1
- package/lib/helpers/composeSignals.js +48 -47
- package/lib/helpers/formDataToJSON.js +1 -1
- package/lib/helpers/formDataToStream.js +2 -2
- package/lib/helpers/fromDataURI.js +18 -5
- package/lib/helpers/progressEventReducer.js +3 -0
- package/lib/helpers/resolveConfig.js +12 -6
- package/lib/helpers/sanitizeHeaderValue.js +60 -0
- package/lib/helpers/toFormData.js +1 -1
- package/lib/utils.js +31 -9
- package/package.json +31 -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,9 +1,10 @@
|
|
|
1
|
-
/*! Axios v1.
|
|
1
|
+
/*! Axios v1.17.0 Copyright (c) 2026 Matt Zabriskie and contributors */
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var FormData$1 = require('form-data');
|
|
5
5
|
var crypto = require('crypto');
|
|
6
6
|
var url = require('url');
|
|
7
|
+
var HttpsProxyAgent = require('https-proxy-agent');
|
|
7
8
|
var http = require('http');
|
|
8
9
|
var https = require('https');
|
|
9
10
|
var http2 = require('http2');
|
|
@@ -416,7 +417,10 @@ function merge(...objs) {
|
|
|
416
417
|
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
|
|
417
418
|
return;
|
|
418
419
|
}
|
|
419
|
-
|
|
420
|
+
|
|
421
|
+
// findKey lowercases the key, so caseless lookup only applies to strings —
|
|
422
|
+
// symbol keys are identity-matched.
|
|
423
|
+
const targetKey = caseless && typeof key === 'string' && findKey(result, key) || key;
|
|
420
424
|
// Read via own-prop only — a bare `result[targetKey]` walks the prototype
|
|
421
425
|
// chain, so a polluted Object.prototype value could surface here and get
|
|
422
426
|
// copied into the merged result.
|
|
@@ -432,7 +436,21 @@ function merge(...objs) {
|
|
|
432
436
|
}
|
|
433
437
|
};
|
|
434
438
|
for (let i = 0, l = objs.length; i < l; i++) {
|
|
435
|
-
|
|
439
|
+
const source = objs[i];
|
|
440
|
+
if (!source || isBuffer(source)) {
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
forEach(source, assignValue);
|
|
444
|
+
if (typeof source !== 'object' || isArray(source)) {
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
const symbols = Object.getOwnPropertySymbols(source);
|
|
448
|
+
for (let j = 0; j < symbols.length; j++) {
|
|
449
|
+
const symbol = symbols[j];
|
|
450
|
+
if (propertyIsEnumerable.call(source, symbol)) {
|
|
451
|
+
assignValue(source[symbol], symbol);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
436
454
|
}
|
|
437
455
|
return result;
|
|
438
456
|
}
|
|
@@ -649,6 +667,9 @@ const toCamelCase = str => {
|
|
|
649
667
|
const hasOwnProperty = (({
|
|
650
668
|
hasOwnProperty
|
|
651
669
|
}) => (obj, prop) => hasOwnProperty.call(obj, prop))(Object.prototype);
|
|
670
|
+
const {
|
|
671
|
+
propertyIsEnumerable
|
|
672
|
+
} = Object.prototype;
|
|
652
673
|
|
|
653
674
|
/**
|
|
654
675
|
* Determine if a value is a RegExp object
|
|
@@ -737,10 +758,10 @@ function isSpecCompliantForm(thing) {
|
|
|
737
758
|
* @returns {Object} The JSON-compatible object.
|
|
738
759
|
*/
|
|
739
760
|
const toJSONObject = obj => {
|
|
740
|
-
const
|
|
741
|
-
const visit =
|
|
761
|
+
const visited = new WeakSet();
|
|
762
|
+
const visit = source => {
|
|
742
763
|
if (isObject(source)) {
|
|
743
|
-
if (
|
|
764
|
+
if (visited.has(source)) {
|
|
744
765
|
return;
|
|
745
766
|
}
|
|
746
767
|
|
|
@@ -749,19 +770,20 @@ const toJSONObject = obj => {
|
|
|
749
770
|
return source;
|
|
750
771
|
}
|
|
751
772
|
if (!('toJSON' in source)) {
|
|
752
|
-
|
|
773
|
+
// add-on descent / delete-on-ascent: preserves path semantics, so DAG nodes serialise at every occurrence (see #7230).
|
|
774
|
+
visited.add(source);
|
|
753
775
|
const target = isArray(source) ? [] : {};
|
|
754
776
|
forEach(source, (value, key) => {
|
|
755
|
-
const reducedValue = visit(value
|
|
777
|
+
const reducedValue = visit(value);
|
|
756
778
|
!isUndefined(reducedValue) && (target[key] = reducedValue);
|
|
757
779
|
});
|
|
758
|
-
|
|
780
|
+
visited.delete(source);
|
|
759
781
|
return target;
|
|
760
782
|
}
|
|
761
783
|
}
|
|
762
784
|
return source;
|
|
763
785
|
};
|
|
764
|
-
return visit(obj
|
|
786
|
+
return visit(obj);
|
|
765
787
|
};
|
|
766
788
|
|
|
767
789
|
/**
|
|
@@ -928,8 +950,6 @@ var parseHeaders = rawHeaders => {
|
|
|
928
950
|
return parsed;
|
|
929
951
|
};
|
|
930
952
|
|
|
931
|
-
const $internals = Symbol('internals');
|
|
932
|
-
const INVALID_HEADER_VALUE_CHARS_RE = /[^\x09\x20-\x7E\x80-\xFF]/g;
|
|
933
953
|
function trimSPorHTAB(str) {
|
|
934
954
|
let start = 0;
|
|
935
955
|
let end = str.length;
|
|
@@ -949,12 +969,32 @@ function trimSPorHTAB(str) {
|
|
|
949
969
|
}
|
|
950
970
|
return start === 0 && end === str.length ? str : str.slice(start, end);
|
|
951
971
|
}
|
|
972
|
+
|
|
973
|
+
// The control-code ranges are intentional: header sanitization strips C0/DEL bytes.
|
|
974
|
+
// eslint-disable-next-line no-control-regex
|
|
975
|
+
const INVALID_UNICODE_HEADER_VALUE_CHARS = new RegExp('[\\u0000-\\u0008\\u000a-\\u001f\\u007f]+', 'g');
|
|
976
|
+
// eslint-disable-next-line no-control-regex
|
|
977
|
+
const INVALID_BYTE_STRING_HEADER_VALUE_CHARS = new RegExp('[^\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+', 'g');
|
|
978
|
+
function sanitizeValue(value, invalidChars) {
|
|
979
|
+
if (utils$1.isArray(value)) {
|
|
980
|
+
return value.map(item => sanitizeValue(item, invalidChars));
|
|
981
|
+
}
|
|
982
|
+
return trimSPorHTAB(String(value).replace(invalidChars, ''));
|
|
983
|
+
}
|
|
984
|
+
const sanitizeHeaderValue = value => sanitizeValue(value, INVALID_UNICODE_HEADER_VALUE_CHARS);
|
|
985
|
+
const sanitizeByteStringHeaderValue = value => sanitizeValue(value, INVALID_BYTE_STRING_HEADER_VALUE_CHARS);
|
|
986
|
+
function toByteStringHeaderObject(headers) {
|
|
987
|
+
const byteStringHeaders = Object.create(null);
|
|
988
|
+
utils$1.forEach(headers.toJSON(), (value, header) => {
|
|
989
|
+
byteStringHeaders[header] = sanitizeByteStringHeaderValue(value);
|
|
990
|
+
});
|
|
991
|
+
return byteStringHeaders;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
const $internals = Symbol('internals');
|
|
952
995
|
function normalizeHeader(header) {
|
|
953
996
|
return header && String(header).trim().toLowerCase();
|
|
954
997
|
}
|
|
955
|
-
function sanitizeHeaderValue(str) {
|
|
956
|
-
return trimSPorHTAB(str.replace(INVALID_HEADER_VALUE_CHARS_RE, ''));
|
|
957
|
-
}
|
|
958
998
|
function normalizeValue(value) {
|
|
959
999
|
if (value === false || value == null) {
|
|
960
1000
|
return value;
|
|
@@ -1014,7 +1054,7 @@ class AxiosHeaders {
|
|
|
1014
1054
|
function setHeader(_value, _header, _rewrite) {
|
|
1015
1055
|
const lHeader = normalizeHeader(_header);
|
|
1016
1056
|
if (!lHeader) {
|
|
1017
|
-
|
|
1057
|
+
return;
|
|
1018
1058
|
}
|
|
1019
1059
|
const key = utils$1.findKey(self, lHeader);
|
|
1020
1060
|
if (!key || self[key] === undefined || _rewrite === true || _rewrite === undefined && self[key] !== false) {
|
|
@@ -1032,7 +1072,7 @@ class AxiosHeaders {
|
|
|
1032
1072
|
key;
|
|
1033
1073
|
for (const entry of header) {
|
|
1034
1074
|
if (!utils$1.isArray(entry)) {
|
|
1035
|
-
throw TypeError('Object iterator must return a key-value pair');
|
|
1075
|
+
throw new TypeError('Object iterator must return a key-value pair');
|
|
1036
1076
|
}
|
|
1037
1077
|
obj[key = entry[0]] = (dest = obj[key]) ? utils$1.isArray(dest) ? [...dest, entry[1]] : [dest, entry[1]] : entry[1];
|
|
1038
1078
|
}
|
|
@@ -1510,7 +1550,7 @@ function toFormData(obj, formData, options) {
|
|
|
1510
1550
|
throw new AxiosError('Object is too deeply nested (' + depth + ' levels). Max depth: ' + maxDepth, AxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED);
|
|
1511
1551
|
}
|
|
1512
1552
|
if (stack.indexOf(value) !== -1) {
|
|
1513
|
-
throw Error('Circular reference detected in ' + path.join('.'));
|
|
1553
|
+
throw new Error('Circular reference detected in ' + path.join('.'));
|
|
1514
1554
|
}
|
|
1515
1555
|
stack.push(value);
|
|
1516
1556
|
utils$1.forEach(value, function each(el, key) {
|
|
@@ -1692,7 +1732,8 @@ var transitionalDefaults = {
|
|
|
1692
1732
|
silentJSONParsing: true,
|
|
1693
1733
|
forcedJSONParsing: true,
|
|
1694
1734
|
clarifyTimeoutError: false,
|
|
1695
|
-
legacyInterceptorReqResOrdering: true
|
|
1735
|
+
legacyInterceptorReqResOrdering: true,
|
|
1736
|
+
advertiseZstdAcceptEncoding: false
|
|
1696
1737
|
};
|
|
1697
1738
|
|
|
1698
1739
|
var URLSearchParams = url.URLSearchParams;
|
|
@@ -1852,7 +1893,7 @@ function formDataToJSON(formData) {
|
|
|
1852
1893
|
}
|
|
1853
1894
|
return !isNumericKey;
|
|
1854
1895
|
}
|
|
1855
|
-
if (!target
|
|
1896
|
+
if (!utils$1.hasOwnProp(target, name) || !utils$1.isObject(target[name])) {
|
|
1856
1897
|
target[name] = [];
|
|
1857
1898
|
}
|
|
1858
1899
|
const result = buildPath(path, value, target[name], index);
|
|
@@ -2193,14 +2234,16 @@ function getEnv(key) {
|
|
|
2193
2234
|
return process.env[key.toLowerCase()] || process.env[key.toUpperCase()] || '';
|
|
2194
2235
|
}
|
|
2195
2236
|
|
|
2196
|
-
const VERSION = "1.
|
|
2237
|
+
const VERSION = "1.17.0";
|
|
2197
2238
|
|
|
2198
2239
|
function parseProtocol(url) {
|
|
2199
2240
|
const match = /^([-+\w]{1,25}):(?:\/\/)?/.exec(url);
|
|
2200
2241
|
return match && match[1] || '';
|
|
2201
2242
|
}
|
|
2202
2243
|
|
|
2203
|
-
|
|
2244
|
+
// RFC 2397: data:[<mediatype>][;base64],<data>
|
|
2245
|
+
// mediatype = type/subtype followed by optional ;name=value parameters
|
|
2246
|
+
const DATA_URL_PATTERN = /^([^,;]+\/[^,;]+)?((?:;[^,;=]+=[^,;]+)*)(;base64)?,([\s\S]*)$/;
|
|
2204
2247
|
|
|
2205
2248
|
/**
|
|
2206
2249
|
* Parse data uri to a Buffer or Blob
|
|
@@ -2224,10 +2267,20 @@ function fromDataURI(uri, asBlob, options) {
|
|
|
2224
2267
|
if (!match) {
|
|
2225
2268
|
throw new AxiosError('Invalid URL', AxiosError.ERR_INVALID_URL);
|
|
2226
2269
|
}
|
|
2227
|
-
const
|
|
2228
|
-
const
|
|
2229
|
-
const
|
|
2230
|
-
const
|
|
2270
|
+
const type = match[1];
|
|
2271
|
+
const params = match[2];
|
|
2272
|
+
const encoding = match[3] ? 'base64' : 'utf8';
|
|
2273
|
+
const body = match[4];
|
|
2274
|
+
|
|
2275
|
+
// RFC 2397 section 3: default mediatype is text/plain;charset=US-ASCII
|
|
2276
|
+
// Bare `data:,` leaves mime undefined; Blob normalises that to "" per spec.
|
|
2277
|
+
let mime;
|
|
2278
|
+
if (type) {
|
|
2279
|
+
mime = params ? type + params : type;
|
|
2280
|
+
} else if (params) {
|
|
2281
|
+
mime = 'text/plain' + params;
|
|
2282
|
+
}
|
|
2283
|
+
const buffer = Buffer.from(decodeURIComponent(body), encoding);
|
|
2231
2284
|
if (asBlob) {
|
|
2232
2285
|
if (!_Blob) {
|
|
2233
2286
|
throw new AxiosError('Blob is not supported', AxiosError.ERR_NOT_SUPPORT);
|
|
@@ -2420,10 +2473,10 @@ const formDataToStream = (form, headersHandler, options) => {
|
|
|
2420
2473
|
boundary = tag + '-' + platform.generateString(size, BOUNDARY_ALPHABET)
|
|
2421
2474
|
} = options || {};
|
|
2422
2475
|
if (!utils$1.isFormData(form)) {
|
|
2423
|
-
throw TypeError('FormData instance required');
|
|
2476
|
+
throw new TypeError('FormData instance required');
|
|
2424
2477
|
}
|
|
2425
2478
|
if (boundary.length < 1 || boundary.length > 70) {
|
|
2426
|
-
throw Error('boundary must be 1-70 characters long');
|
|
2479
|
+
throw new Error('boundary must be 1-70 characters long');
|
|
2427
2480
|
}
|
|
2428
2481
|
const boundaryBytes = textEncoder.encode('--' + boundary + CRLF);
|
|
2429
2482
|
const footerBytes = textEncoder.encode('--' + boundary + '--' + CRLF);
|
|
@@ -2473,6 +2526,84 @@ class ZlibHeaderTransformStream extends stream.Transform {
|
|
|
2473
2526
|
}
|
|
2474
2527
|
}
|
|
2475
2528
|
|
|
2529
|
+
class Http2Sessions {
|
|
2530
|
+
constructor() {
|
|
2531
|
+
this.sessions = Object.create(null);
|
|
2532
|
+
}
|
|
2533
|
+
getSession(authority, options) {
|
|
2534
|
+
options = Object.assign({
|
|
2535
|
+
sessionTimeout: 1000
|
|
2536
|
+
}, options);
|
|
2537
|
+
let authoritySessions = this.sessions[authority];
|
|
2538
|
+
if (authoritySessions) {
|
|
2539
|
+
let len = authoritySessions.length;
|
|
2540
|
+
for (let i = 0; i < len; i++) {
|
|
2541
|
+
const [sessionHandle, sessionOptions] = authoritySessions[i];
|
|
2542
|
+
if (!sessionHandle.destroyed && !sessionHandle.closed && util.isDeepStrictEqual(sessionOptions, options)) {
|
|
2543
|
+
return sessionHandle;
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
}
|
|
2547
|
+
const session = http2.connect(authority, options);
|
|
2548
|
+
let removed;
|
|
2549
|
+
let timer;
|
|
2550
|
+
const removeSession = () => {
|
|
2551
|
+
if (removed) {
|
|
2552
|
+
return;
|
|
2553
|
+
}
|
|
2554
|
+
removed = true;
|
|
2555
|
+
if (timer) {
|
|
2556
|
+
clearTimeout(timer);
|
|
2557
|
+
timer = null;
|
|
2558
|
+
}
|
|
2559
|
+
let entries = authoritySessions,
|
|
2560
|
+
len = entries.length,
|
|
2561
|
+
i = len;
|
|
2562
|
+
while (i--) {
|
|
2563
|
+
if (entries[i][0] === session) {
|
|
2564
|
+
if (len === 1) {
|
|
2565
|
+
delete this.sessions[authority];
|
|
2566
|
+
} else {
|
|
2567
|
+
entries.splice(i, 1);
|
|
2568
|
+
}
|
|
2569
|
+
if (!session.closed) {
|
|
2570
|
+
session.close();
|
|
2571
|
+
}
|
|
2572
|
+
return;
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
};
|
|
2576
|
+
const originalRequestFn = session.request;
|
|
2577
|
+
const {
|
|
2578
|
+
sessionTimeout
|
|
2579
|
+
} = options;
|
|
2580
|
+
if (sessionTimeout != null) {
|
|
2581
|
+
let streamsCount = 0;
|
|
2582
|
+
session.request = function () {
|
|
2583
|
+
const stream = originalRequestFn.apply(this, arguments);
|
|
2584
|
+
streamsCount++;
|
|
2585
|
+
if (timer) {
|
|
2586
|
+
clearTimeout(timer);
|
|
2587
|
+
timer = null;
|
|
2588
|
+
}
|
|
2589
|
+
stream.once('close', () => {
|
|
2590
|
+
if (! --streamsCount) {
|
|
2591
|
+
timer = setTimeout(() => {
|
|
2592
|
+
timer = null;
|
|
2593
|
+
removeSession();
|
|
2594
|
+
}, sessionTimeout);
|
|
2595
|
+
}
|
|
2596
|
+
});
|
|
2597
|
+
return stream;
|
|
2598
|
+
};
|
|
2599
|
+
}
|
|
2600
|
+
session.once('close', removeSession);
|
|
2601
|
+
let entry = [session, options];
|
|
2602
|
+
authoritySessions ? authoritySessions.push(entry) : authoritySessions = this.sessions[authority] = [entry];
|
|
2603
|
+
return session;
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
|
|
2476
2607
|
const callbackify = (fn, reducer) => {
|
|
2477
2608
|
return utils$1.isAsyncFn(fn) ? function (...args) {
|
|
2478
2609
|
const cb = args.pop();
|
|
@@ -2707,6 +2838,9 @@ const progressEventReducer = (listener, isDownloadStream, freq = 3) => {
|
|
|
2707
2838
|
let bytesNotified = 0;
|
|
2708
2839
|
const _speedometer = speedometer(50, 250);
|
|
2709
2840
|
return throttle(e => {
|
|
2841
|
+
if (!e || typeof e.loaded !== 'number') {
|
|
2842
|
+
return;
|
|
2843
|
+
}
|
|
2710
2844
|
const rawLoaded = e.loaded;
|
|
2711
2845
|
const total = e.lengthComputable ? e.total : undefined;
|
|
2712
2846
|
const loaded = total != null ? Math.min(rawLoaded, total) : rawLoaded;
|
|
@@ -2835,7 +2969,14 @@ const brotliOptions = {
|
|
|
2835
2969
|
flush: zlib.constants.BROTLI_OPERATION_FLUSH,
|
|
2836
2970
|
finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH
|
|
2837
2971
|
};
|
|
2972
|
+
const zstdOptions = {
|
|
2973
|
+
flush: zlib.constants.ZSTD_e_flush,
|
|
2974
|
+
finishFlush: zlib.constants.ZSTD_e_flush
|
|
2975
|
+
};
|
|
2838
2976
|
const isBrotliSupported = utils$1.isFunction(zlib.createBrotliDecompress);
|
|
2977
|
+
const isZstdSupported = utils$1.isFunction(zlib.createZstdDecompress);
|
|
2978
|
+
const ACCEPT_ENCODING = 'gzip, compress, deflate' + (isBrotliSupported ? ', br' : '');
|
|
2979
|
+
const ACCEPT_ENCODING_WITH_ZSTD = ACCEPT_ENCODING + (isZstdSupported ? ', zstd' : '');
|
|
2839
2980
|
const {
|
|
2840
2981
|
http: httpFollow,
|
|
2841
2982
|
https: httpsFollow
|
|
@@ -2858,6 +2999,48 @@ function setFormDataHeaders$1(headers, formHeaders, policy) {
|
|
|
2858
2999
|
// the request currently owning that socket across keep-alive reuse (issue #10780).
|
|
2859
3000
|
const kAxiosSocketListener = Symbol('axios.http.socketListener');
|
|
2860
3001
|
const kAxiosCurrentReq = Symbol('axios.http.currentReq');
|
|
3002
|
+
|
|
3003
|
+
// Tags HttpsProxyAgent instances installed by setProxy() so the redirect path
|
|
3004
|
+
// can strip them without clobbering a user-supplied agent that happens to be
|
|
3005
|
+
// an HttpsProxyAgent.
|
|
3006
|
+
const kAxiosInstalledTunnel = Symbol('axios.http.installedTunnel');
|
|
3007
|
+
|
|
3008
|
+
// Cache of CONNECT-tunneling agents keyed by proxy config so repeat requests
|
|
3009
|
+
// through the same proxy reuse a single agent (and its socket pool). The
|
|
3010
|
+
// keyspace is bounded by the set of distinct proxy configs the process uses,
|
|
3011
|
+
// so unbounded growth is not a concern in practice.
|
|
3012
|
+
const tunnelingAgentCache = new Map();
|
|
3013
|
+
const tunnelingAgentCacheUser = new WeakMap();
|
|
3014
|
+
function getTunnelingAgent(agentOptions, userHttpsAgent) {
|
|
3015
|
+
const key = agentOptions.protocol + '//' + agentOptions.hostname + ':' + (agentOptions.port || '') + '#' + (agentOptions.auth || '');
|
|
3016
|
+
const cache = userHttpsAgent ? tunnelingAgentCacheUser.get(userHttpsAgent) || tunnelingAgentCacheUser.set(userHttpsAgent, new Map()).get(userHttpsAgent) : tunnelingAgentCache;
|
|
3017
|
+
let agent = cache.get(key);
|
|
3018
|
+
if (agent) return agent;
|
|
3019
|
+
// Forward the user's TLS options (custom CA, rejectUnauthorized, client cert,
|
|
3020
|
+
// etc.) into the tunneling agent so they apply to the origin TLS upgrade
|
|
3021
|
+
// performed after CONNECT. Our proxy fields take precedence on conflict.
|
|
3022
|
+
const merged = userHttpsAgent && userHttpsAgent.options ? {
|
|
3023
|
+
...userHttpsAgent.options,
|
|
3024
|
+
...agentOptions
|
|
3025
|
+
} : agentOptions;
|
|
3026
|
+
agent = new HttpsProxyAgent(merged);
|
|
3027
|
+
if (userHttpsAgent && userHttpsAgent.options) {
|
|
3028
|
+
const originTLSOptions = {
|
|
3029
|
+
...userHttpsAgent.options
|
|
3030
|
+
};
|
|
3031
|
+
const callback = agent.callback;
|
|
3032
|
+
agent.callback = function axiosTunnelingAgentCallback(req, opts) {
|
|
3033
|
+
// HttpsProxyAgent v5 reads callback opts for the post-CONNECT origin TLS upgrade.
|
|
3034
|
+
return callback.call(this, req, {
|
|
3035
|
+
...originTLSOptions,
|
|
3036
|
+
...opts
|
|
3037
|
+
});
|
|
3038
|
+
};
|
|
3039
|
+
}
|
|
3040
|
+
agent[kAxiosInstalledTunnel] = true;
|
|
3041
|
+
cache.set(key, agent);
|
|
3042
|
+
return agent;
|
|
3043
|
+
}
|
|
2861
3044
|
const supportedProtocols = platform.protocols.map(protocol => {
|
|
2862
3045
|
return protocol + ':';
|
|
2863
3046
|
});
|
|
@@ -2866,7 +3049,7 @@ const supportedProtocols = platform.protocols.map(protocol => {
|
|
|
2866
3049
|
// Decode before composing the `auth` option so credentials such as
|
|
2867
3050
|
// `my%40email.com:pass` are sent as `my@email.com:pass`. Falls back to the
|
|
2868
3051
|
// original value for malformed input so a bad encoding never throws.
|
|
2869
|
-
const decodeURIComponentSafe = value => {
|
|
3052
|
+
const decodeURIComponentSafe$1 = value => {
|
|
2870
3053
|
if (!utils$1.isString(value)) {
|
|
2871
3054
|
return value;
|
|
2872
3055
|
}
|
|
@@ -2880,84 +3063,11 @@ const flushOnFinish = (stream, [throttled, flush]) => {
|
|
|
2880
3063
|
stream.on('end', flush).on('error', flush);
|
|
2881
3064
|
return throttled;
|
|
2882
3065
|
};
|
|
2883
|
-
class Http2Sessions {
|
|
2884
|
-
constructor() {
|
|
2885
|
-
this.sessions = Object.create(null);
|
|
2886
|
-
}
|
|
2887
|
-
getSession(authority, options) {
|
|
2888
|
-
options = Object.assign({
|
|
2889
|
-
sessionTimeout: 1000
|
|
2890
|
-
}, options);
|
|
2891
|
-
let authoritySessions = this.sessions[authority];
|
|
2892
|
-
if (authoritySessions) {
|
|
2893
|
-
let len = authoritySessions.length;
|
|
2894
|
-
for (let i = 0; i < len; i++) {
|
|
2895
|
-
const [sessionHandle, sessionOptions] = authoritySessions[i];
|
|
2896
|
-
if (!sessionHandle.destroyed && !sessionHandle.closed && util.isDeepStrictEqual(sessionOptions, options)) {
|
|
2897
|
-
return sessionHandle;
|
|
2898
|
-
}
|
|
2899
|
-
}
|
|
2900
|
-
}
|
|
2901
|
-
const session = http2.connect(authority, options);
|
|
2902
|
-
let removed;
|
|
2903
|
-
const removeSession = () => {
|
|
2904
|
-
if (removed) {
|
|
2905
|
-
return;
|
|
2906
|
-
}
|
|
2907
|
-
removed = true;
|
|
2908
|
-
let entries = authoritySessions,
|
|
2909
|
-
len = entries.length,
|
|
2910
|
-
i = len;
|
|
2911
|
-
while (i--) {
|
|
2912
|
-
if (entries[i][0] === session) {
|
|
2913
|
-
if (len === 1) {
|
|
2914
|
-
delete this.sessions[authority];
|
|
2915
|
-
} else {
|
|
2916
|
-
entries.splice(i, 1);
|
|
2917
|
-
}
|
|
2918
|
-
if (!session.closed) {
|
|
2919
|
-
session.close();
|
|
2920
|
-
}
|
|
2921
|
-
return;
|
|
2922
|
-
}
|
|
2923
|
-
}
|
|
2924
|
-
};
|
|
2925
|
-
const originalRequestFn = session.request;
|
|
2926
|
-
const {
|
|
2927
|
-
sessionTimeout
|
|
2928
|
-
} = options;
|
|
2929
|
-
if (sessionTimeout != null) {
|
|
2930
|
-
let timer;
|
|
2931
|
-
let streamsCount = 0;
|
|
2932
|
-
session.request = function () {
|
|
2933
|
-
const stream = originalRequestFn.apply(this, arguments);
|
|
2934
|
-
streamsCount++;
|
|
2935
|
-
if (timer) {
|
|
2936
|
-
clearTimeout(timer);
|
|
2937
|
-
timer = null;
|
|
2938
|
-
}
|
|
2939
|
-
stream.once('close', () => {
|
|
2940
|
-
if (! --streamsCount) {
|
|
2941
|
-
timer = setTimeout(() => {
|
|
2942
|
-
timer = null;
|
|
2943
|
-
removeSession();
|
|
2944
|
-
}, sessionTimeout);
|
|
2945
|
-
}
|
|
2946
|
-
});
|
|
2947
|
-
return stream;
|
|
2948
|
-
};
|
|
2949
|
-
}
|
|
2950
|
-
session.once('close', removeSession);
|
|
2951
|
-
let entry = [session, options];
|
|
2952
|
-
authoritySessions ? authoritySessions.push(entry) : authoritySessions = this.sessions[authority] = [entry];
|
|
2953
|
-
return session;
|
|
2954
|
-
}
|
|
2955
|
-
}
|
|
2956
3066
|
const http2Sessions = new Http2Sessions();
|
|
2957
3067
|
|
|
2958
3068
|
/**
|
|
2959
|
-
* If the proxy or config beforeRedirects functions are defined, call them
|
|
2960
|
-
* object.
|
|
3069
|
+
* If the proxy, auth, or config beforeRedirects functions are defined, call them
|
|
3070
|
+
* with the options object.
|
|
2961
3071
|
*
|
|
2962
3072
|
* @param {Object<string, any>} options - The options object that was passed to the request.
|
|
2963
3073
|
*
|
|
@@ -2967,6 +3077,9 @@ function dispatchBeforeRedirect(options, responseDetails, requestDetails) {
|
|
|
2967
3077
|
if (options.beforeRedirects.proxy) {
|
|
2968
3078
|
options.beforeRedirects.proxy(options);
|
|
2969
3079
|
}
|
|
3080
|
+
if (options.beforeRedirects.auth) {
|
|
3081
|
+
options.beforeRedirects.auth(options);
|
|
3082
|
+
}
|
|
2970
3083
|
if (options.beforeRedirects.config) {
|
|
2971
3084
|
options.beforeRedirects.config(options, responseDetails, requestDetails);
|
|
2972
3085
|
}
|
|
@@ -2981,7 +3094,7 @@ function dispatchBeforeRedirect(options, responseDetails, requestDetails) {
|
|
|
2981
3094
|
*
|
|
2982
3095
|
* @returns {http.ClientRequestArgs}
|
|
2983
3096
|
*/
|
|
2984
|
-
function setProxy(options, configProxy, location, isRedirect) {
|
|
3097
|
+
function setProxy(options, configProxy, location, isRedirect, configHttpsAgent) {
|
|
2985
3098
|
let proxy = configProxy;
|
|
2986
3099
|
if (!proxy && proxy !== false) {
|
|
2987
3100
|
const proxyUrl = getProxyForUrl(location);
|
|
@@ -3002,6 +3115,13 @@ function setProxy(options, configProxy, location, isRedirect) {
|
|
|
3002
3115
|
}
|
|
3003
3116
|
}
|
|
3004
3117
|
}
|
|
3118
|
+
// Strip any tunneling agent we installed for the previous hop so a redirect
|
|
3119
|
+
// that drops the proxy or crosses an HTTPS↔HTTP boundary doesn't reuse a
|
|
3120
|
+
// stale one. Match on our Symbol marker so a user-supplied HttpsProxyAgent
|
|
3121
|
+
// (which won't carry the marker) is left alone.
|
|
3122
|
+
if (isRedirect && options.agent && options.agent[kAxiosInstalledTunnel]) {
|
|
3123
|
+
options.agent = undefined;
|
|
3124
|
+
}
|
|
3005
3125
|
if (proxy) {
|
|
3006
3126
|
// Read proxy fields without traversing the prototype chain. URL instances expose
|
|
3007
3127
|
// username/password/hostname/host/port/protocol via getters on URL.prototype (so
|
|
@@ -3034,37 +3154,84 @@ function setProxy(options, configProxy, location, isRedirect) {
|
|
|
3034
3154
|
proxy
|
|
3035
3155
|
});
|
|
3036
3156
|
}
|
|
3037
|
-
const base64 = Buffer.from(proxyAuth, 'utf8').toString('base64');
|
|
3038
|
-
options.headers['Proxy-Authorization'] = 'Basic ' + base64;
|
|
3039
3157
|
}
|
|
3158
|
+
const targetIsHttps = isHttps.test(options.protocol);
|
|
3159
|
+
if (targetIsHttps) {
|
|
3160
|
+
// CONNECT-tunneling path for HTTPS targets. Preserves end-to-end TLS to
|
|
3161
|
+
// the origin so the proxy cannot inspect the URL, headers, or body — the
|
|
3162
|
+
// behavior already promised by THREATMODEL.md (T-R9). HttpsProxyAgent
|
|
3163
|
+
// sends Proxy-Authorization on the CONNECT request only, never on the
|
|
3164
|
+
// wrapped TLS request, which is why we don't stamp it onto
|
|
3165
|
+
// options.headers here. If the user already supplied an HttpsProxyAgent,
|
|
3166
|
+
// they own tunneling end-to-end and we leave them alone; otherwise we
|
|
3167
|
+
// install our own tunneling agent and forward their TLS options (if any)
|
|
3168
|
+
// so a custom httpsAgent for cert pinning / rejectUnauthorized still
|
|
3169
|
+
// applies to the origin TLS upgrade.
|
|
3170
|
+
if (!(configHttpsAgent instanceof HttpsProxyAgent)) {
|
|
3171
|
+
const proxyHost = readProxyField('hostname') || readProxyField('host');
|
|
3172
|
+
const proxyPort = readProxyField('port');
|
|
3173
|
+
const rawProxyProtocol = readProxyField('protocol');
|
|
3174
|
+
const normalizedProtocol = rawProxyProtocol ? rawProxyProtocol.includes(':') ? rawProxyProtocol : `${rawProxyProtocol}:` : 'http:';
|
|
3175
|
+
// Bracket IPv6 literals for URL parsing; URL.hostname strips the
|
|
3176
|
+
// brackets again on read so the agent receives the raw form.
|
|
3177
|
+
const proxyHostForURL = proxyHost && proxyHost.includes(':') && !proxyHost.startsWith('[') ? `[${proxyHost}]` : proxyHost;
|
|
3178
|
+
const proxyURL = new URL(`${normalizedProtocol}//${proxyHostForURL}${proxyPort ? ':' + proxyPort : ''}`);
|
|
3179
|
+
const agentOptions = {
|
|
3180
|
+
protocol: proxyURL.protocol,
|
|
3181
|
+
hostname: proxyURL.hostname.replace(/^\[|\]$/g, ''),
|
|
3182
|
+
port: proxyURL.port,
|
|
3183
|
+
auth: proxyAuth && typeof proxyAuth === 'string' ? proxyAuth : undefined
|
|
3184
|
+
};
|
|
3185
|
+
if (proxyURL.protocol === 'https:') {
|
|
3186
|
+
agentOptions.ALPNProtocols = ['http/1.1'];
|
|
3187
|
+
}
|
|
3188
|
+
const tunnelingAgent = getTunnelingAgent(agentOptions, configHttpsAgent);
|
|
3189
|
+
// Set both: `options.agent` is consumed by the native https.request path
|
|
3190
|
+
// (config.maxRedirects === 0); `options.agents.https` is consumed by
|
|
3191
|
+
// follow-redirects, which ignores `options.agent` when `options.agents`
|
|
3192
|
+
// is present.
|
|
3193
|
+
options.agent = tunnelingAgent;
|
|
3194
|
+
if (options.agents) {
|
|
3195
|
+
options.agents.https = tunnelingAgent;
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
3198
|
+
} else {
|
|
3199
|
+
// Forward-proxy mode for plaintext HTTP targets. The request line carries
|
|
3200
|
+
// the absolute URL and the proxy sees everything — acceptable for plain
|
|
3201
|
+
// HTTP since the wire was already plaintext.
|
|
3202
|
+
if (proxyAuth) {
|
|
3203
|
+
const base64 = Buffer.from(proxyAuth, 'utf8').toString('base64');
|
|
3204
|
+
options.headers['Proxy-Authorization'] = 'Basic ' + base64;
|
|
3205
|
+
}
|
|
3040
3206
|
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3207
|
+
// Preserve a user-supplied Host header (case-insensitive) so callers can override
|
|
3208
|
+
// the value forwarded to the proxy; otherwise default to the request URL's host.
|
|
3209
|
+
let hasUserHostHeader = false;
|
|
3210
|
+
for (const name of Object.keys(options.headers)) {
|
|
3211
|
+
if (name.toLowerCase() === 'host') {
|
|
3212
|
+
hasUserHostHeader = true;
|
|
3213
|
+
break;
|
|
3214
|
+
}
|
|
3215
|
+
}
|
|
3216
|
+
if (!hasUserHostHeader) {
|
|
3217
|
+
options.headers.host = options.hostname + (options.port ? ':' + options.port : '');
|
|
3218
|
+
}
|
|
3219
|
+
const proxyHost = readProxyField('hostname') || readProxyField('host');
|
|
3220
|
+
options.hostname = proxyHost;
|
|
3221
|
+
// Replace 'host' since options is not a URL object
|
|
3222
|
+
options.host = proxyHost;
|
|
3223
|
+
options.port = readProxyField('port');
|
|
3224
|
+
options.path = location;
|
|
3225
|
+
const proxyProtocol = readProxyField('protocol');
|
|
3226
|
+
if (proxyProtocol) {
|
|
3227
|
+
options.protocol = proxyProtocol.includes(':') ? proxyProtocol : `${proxyProtocol}:`;
|
|
3048
3228
|
}
|
|
3049
|
-
}
|
|
3050
|
-
if (!hasUserHostHeader) {
|
|
3051
|
-
options.headers.host = options.hostname + (options.port ? ':' + options.port : '');
|
|
3052
|
-
}
|
|
3053
|
-
const proxyHost = readProxyField('hostname') || readProxyField('host');
|
|
3054
|
-
options.hostname = proxyHost;
|
|
3055
|
-
// Replace 'host' since options is not a URL object
|
|
3056
|
-
options.host = proxyHost;
|
|
3057
|
-
options.port = readProxyField('port');
|
|
3058
|
-
options.path = location;
|
|
3059
|
-
const proxyProtocol = readProxyField('protocol');
|
|
3060
|
-
if (proxyProtocol) {
|
|
3061
|
-
options.protocol = proxyProtocol.includes(':') ? proxyProtocol : `${proxyProtocol}:`;
|
|
3062
3229
|
}
|
|
3063
3230
|
}
|
|
3064
3231
|
options.beforeRedirects.proxy = function beforeRedirect(redirectOptions) {
|
|
3065
3232
|
// Configure proxy for redirected request, passing the original config proxy to apply
|
|
3066
3233
|
// the exact same logic as if the redirected request was performed by axios directly.
|
|
3067
|
-
setProxy(redirectOptions, configProxy, redirectOptions.href, true);
|
|
3234
|
+
setProxy(redirectOptions, configProxy, redirectOptions.href, true, configHttpsAgent);
|
|
3068
3235
|
};
|
|
3069
3236
|
}
|
|
3070
3237
|
const isHttpAdapterSupported = typeof process !== 'undefined' && utils$1.kindOf(process) === 'process';
|
|
@@ -3148,6 +3315,7 @@ const http2Transport = {
|
|
|
3148
3315
|
var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
3149
3316
|
return wrapAsync(async function dispatchHttpRequest(resolve, reject, onDone) {
|
|
3150
3317
|
const own = key => utils$1.hasOwnProp(config, key) ? config[key] : undefined;
|
|
3318
|
+
const transitional = own('transitional') || transitionalDefaults;
|
|
3151
3319
|
let data = own('data');
|
|
3152
3320
|
let lookup = own('lookup');
|
|
3153
3321
|
let family = own('family');
|
|
@@ -3187,7 +3355,7 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3187
3355
|
try {
|
|
3188
3356
|
abortEmitter.emit('abort', !reason || reason.type ? new CanceledError(null, config, req) : reason);
|
|
3189
3357
|
} catch (err) {
|
|
3190
|
-
|
|
3358
|
+
// ignore emit errors
|
|
3191
3359
|
}
|
|
3192
3360
|
}
|
|
3193
3361
|
function clearConnectPhaseTimer() {
|
|
@@ -3198,7 +3366,6 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3198
3366
|
}
|
|
3199
3367
|
function createTimeoutError() {
|
|
3200
3368
|
let timeoutErrorMessage = config.timeout ? 'timeout of ' + config.timeout + 'ms exceeded' : 'timeout exceeded';
|
|
3201
|
-
const transitional = config.transitional || transitionalDefaults;
|
|
3202
3369
|
if (config.timeoutErrorMessage) {
|
|
3203
3370
|
timeoutErrorMessage = config.timeoutErrorMessage;
|
|
3204
3371
|
}
|
|
@@ -3371,9 +3538,9 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3371
3538
|
const password = configAuth.password || '';
|
|
3372
3539
|
auth = username + ':' + password;
|
|
3373
3540
|
}
|
|
3374
|
-
if (!auth && parsed.username) {
|
|
3375
|
-
const urlUsername = decodeURIComponentSafe(parsed.username);
|
|
3376
|
-
const urlPassword = decodeURIComponentSafe(parsed.password);
|
|
3541
|
+
if (!auth && (parsed.username || parsed.password)) {
|
|
3542
|
+
const urlUsername = decodeURIComponentSafe$1(parsed.username);
|
|
3543
|
+
const urlPassword = decodeURIComponentSafe$1(parsed.password);
|
|
3377
3544
|
auth = urlUsername + ':' + urlPassword;
|
|
3378
3545
|
}
|
|
3379
3546
|
auth && headers.delete('authorization');
|
|
@@ -3387,14 +3554,14 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3387
3554
|
customErr.exists = true;
|
|
3388
3555
|
return reject(customErr);
|
|
3389
3556
|
}
|
|
3390
|
-
headers.set('Accept-Encoding',
|
|
3557
|
+
headers.set('Accept-Encoding', utils$1.hasOwnProp(transitional, 'advertiseZstdAcceptEncoding') && transitional.advertiseZstdAcceptEncoding === true ? ACCEPT_ENCODING_WITH_ZSTD : ACCEPT_ENCODING, false);
|
|
3391
3558
|
|
|
3392
3559
|
// Null-prototype to block prototype pollution gadgets on properties read
|
|
3393
3560
|
// directly by Node's http.request (e.g. insecureHTTPParser, lookup).
|
|
3394
3561
|
const options = Object.assign(Object.create(null), {
|
|
3395
3562
|
path: path$1,
|
|
3396
3563
|
method: method,
|
|
3397
|
-
headers: headers
|
|
3564
|
+
headers: toByteStringHeaderObject(headers),
|
|
3398
3565
|
agents: {
|
|
3399
3566
|
http: config.httpAgent,
|
|
3400
3567
|
https: config.httpsAgent
|
|
@@ -3409,28 +3576,34 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3409
3576
|
|
|
3410
3577
|
// cacheable-lookup integration hotfix
|
|
3411
3578
|
!utils$1.isUndefined(lookup) && (options.lookup = lookup);
|
|
3412
|
-
|
|
3413
|
-
|
|
3579
|
+
const socketPath = own('socketPath');
|
|
3580
|
+
if (socketPath) {
|
|
3581
|
+
if (typeof socketPath !== 'string') {
|
|
3414
3582
|
return reject(new AxiosError('socketPath must be a string', AxiosError.ERR_BAD_OPTION_VALUE, config));
|
|
3415
3583
|
}
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
const
|
|
3584
|
+
const allowedSocketPaths = own('allowedSocketPaths');
|
|
3585
|
+
if (allowedSocketPaths != null) {
|
|
3586
|
+
const allowed = Array.isArray(allowedSocketPaths) ? allowedSocketPaths : [allowedSocketPaths];
|
|
3587
|
+
const resolvedSocket = path.resolve(socketPath);
|
|
3419
3588
|
const isAllowed = allowed.some(entry => typeof entry === 'string' && path.resolve(entry) === resolvedSocket);
|
|
3420
3589
|
if (!isAllowed) {
|
|
3421
|
-
return reject(new AxiosError(`socketPath "${
|
|
3590
|
+
return reject(new AxiosError(`socketPath "${socketPath}" is not permitted by allowedSocketPaths`, AxiosError.ERR_BAD_OPTION_VALUE, config));
|
|
3422
3591
|
}
|
|
3423
3592
|
}
|
|
3424
|
-
options.socketPath =
|
|
3593
|
+
options.socketPath = socketPath;
|
|
3425
3594
|
} else {
|
|
3426
3595
|
options.hostname = parsed.hostname.startsWith('[') ? parsed.hostname.slice(1, -1) : parsed.hostname;
|
|
3427
3596
|
options.port = parsed.port;
|
|
3428
|
-
setProxy(options, config.proxy, protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path);
|
|
3597
|
+
setProxy(options, config.proxy, protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path, false, config.httpsAgent);
|
|
3429
3598
|
}
|
|
3430
3599
|
let transport;
|
|
3431
3600
|
let isNativeTransport = false;
|
|
3432
3601
|
const isHttpsRequest = isHttps.test(options.protocol);
|
|
3433
|
-
|
|
3602
|
+
// Don't clobber a CONNECT-tunneling agent installed by setProxy() for an
|
|
3603
|
+
// HTTPS target.
|
|
3604
|
+
if (options.agent == null) {
|
|
3605
|
+
options.agent = isHttpsRequest ? config.httpsAgent : config.httpAgent;
|
|
3606
|
+
}
|
|
3434
3607
|
if (isHttp2) {
|
|
3435
3608
|
transport = http2Transport;
|
|
3436
3609
|
} else {
|
|
@@ -3448,6 +3621,23 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3448
3621
|
if (configBeforeRedirect) {
|
|
3449
3622
|
options.beforeRedirects.config = configBeforeRedirect;
|
|
3450
3623
|
}
|
|
3624
|
+
if (auth) {
|
|
3625
|
+
// Restore HTTP Basic credentials on same-origin redirects only.
|
|
3626
|
+
// follow-redirects >= 1.15.8 strips Authorization on every redirect (see #6929);
|
|
3627
|
+
// cross-origin stripping is the documented mitigation for T-R2 in THREATMODEL.md
|
|
3628
|
+
// and is preserved by deliberately not restoring on origin change.
|
|
3629
|
+
const requestOrigin = parsed.origin;
|
|
3630
|
+
const authToRestore = auth;
|
|
3631
|
+
options.beforeRedirects.auth = function beforeRedirectAuth(redirectOptions) {
|
|
3632
|
+
try {
|
|
3633
|
+
if (new URL(redirectOptions.href).origin === requestOrigin) {
|
|
3634
|
+
redirectOptions.auth = authToRestore;
|
|
3635
|
+
}
|
|
3636
|
+
} catch (e) {
|
|
3637
|
+
// ignore malformed URL: leaving auth stripped is fail-safe
|
|
3638
|
+
}
|
|
3639
|
+
};
|
|
3640
|
+
}
|
|
3451
3641
|
transport = isHttpsRequest ? httpsFollow : httpFollow;
|
|
3452
3642
|
}
|
|
3453
3643
|
}
|
|
@@ -3516,6 +3706,13 @@ var httpAdapter = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3516
3706
|
streams.push(zlib.createBrotliDecompress(brotliOptions));
|
|
3517
3707
|
delete res.headers['content-encoding'];
|
|
3518
3708
|
}
|
|
3709
|
+
break;
|
|
3710
|
+
case 'zstd':
|
|
3711
|
+
if (isZstdSupported) {
|
|
3712
|
+
streams.push(zlib.createZstdDecompress(zstdOptions));
|
|
3713
|
+
delete res.headers['content-encoding'];
|
|
3714
|
+
}
|
|
3715
|
+
break;
|
|
3519
3716
|
}
|
|
3520
3717
|
}
|
|
3521
3718
|
responseStream = streams.length > 1 ? stream.pipeline(streams, utils$1.noop) : streams[0];
|
|
@@ -3927,8 +4124,8 @@ function setFormDataHeaders(headers, formHeaders, policy) {
|
|
|
3927
4124
|
*
|
|
3928
4125
|
* @returns {string} UTF-8 bytes as a Latin-1 string
|
|
3929
4126
|
*/
|
|
3930
|
-
const encodeUTF8 = str => encodeURIComponent(str).replace(/%([0-9A-F]{2})/gi, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
|
|
3931
|
-
|
|
4127
|
+
const encodeUTF8$1 = str => encodeURIComponent(str).replace(/%([0-9A-F]{2})/gi, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
|
|
4128
|
+
function resolveConfig(config) {
|
|
3932
4129
|
const newConfig = mergeConfig({}, config);
|
|
3933
4130
|
|
|
3934
4131
|
// Read only own properties to prevent prototype pollution gadgets
|
|
@@ -3944,15 +4141,15 @@ var resolveConfig = config => {
|
|
|
3944
4141
|
const allowAbsoluteUrls = own('allowAbsoluteUrls');
|
|
3945
4142
|
const url = own('url');
|
|
3946
4143
|
newConfig.headers = headers = AxiosHeaders.from(headers);
|
|
3947
|
-
newConfig.url = buildURL(buildFullPath(baseURL, url, allowAbsoluteUrls),
|
|
4144
|
+
newConfig.url = buildURL(buildFullPath(baseURL, url, allowAbsoluteUrls), own('params'), own('paramsSerializer'));
|
|
3948
4145
|
|
|
3949
4146
|
// HTTP basic authentication
|
|
3950
4147
|
if (auth) {
|
|
3951
|
-
headers.set('Authorization', 'Basic ' + btoa((auth.username || '') + ':' + (auth.password ? encodeUTF8(auth.password) : '')));
|
|
4148
|
+
headers.set('Authorization', 'Basic ' + btoa((auth.username || '') + ':' + (auth.password ? encodeUTF8$1(auth.password) : '')));
|
|
3952
4149
|
}
|
|
3953
4150
|
if (utils$1.isFormData(data)) {
|
|
3954
|
-
if (platform.hasStandardBrowserEnv || platform.hasStandardBrowserWebWorkerEnv) {
|
|
3955
|
-
headers.setContentType(undefined); // browser handles it
|
|
4151
|
+
if (platform.hasStandardBrowserEnv || platform.hasStandardBrowserWebWorkerEnv || utils$1.isReactNative(data)) {
|
|
4152
|
+
headers.setContentType(undefined); // browser/web worker/RN handles it
|
|
3956
4153
|
} else if (utils$1.isFunction(data.getHeaders)) {
|
|
3957
4154
|
// Node.js FormData (like form-data package)
|
|
3958
4155
|
setFormDataHeaders(headers, data.getHeaders(), own('formDataHeaderPolicy'));
|
|
@@ -3980,7 +4177,7 @@ var resolveConfig = config => {
|
|
|
3980
4177
|
}
|
|
3981
4178
|
}
|
|
3982
4179
|
return newConfig;
|
|
3983
|
-
}
|
|
4180
|
+
}
|
|
3984
4181
|
|
|
3985
4182
|
const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';
|
|
3986
4183
|
var xhrAdapter = isXHRAdapterSupported && function (config) {
|
|
@@ -4102,7 +4299,7 @@ var xhrAdapter = isXHRAdapterSupported && function (config) {
|
|
|
4102
4299
|
|
|
4103
4300
|
// Add headers to the request
|
|
4104
4301
|
if ('setRequestHeader' in request) {
|
|
4105
|
-
utils$1.forEach(requestHeaders
|
|
4302
|
+
utils$1.forEach(toByteStringHeaderObject(requestHeaders), function setRequestHeader(val, key) {
|
|
4106
4303
|
request.setRequestHeader(key, val);
|
|
4107
4304
|
});
|
|
4108
4305
|
}
|
|
@@ -4158,41 +4355,41 @@ var xhrAdapter = isXHRAdapterSupported && function (config) {
|
|
|
4158
4355
|
};
|
|
4159
4356
|
|
|
4160
4357
|
const composeSignals = (signals, timeout) => {
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
if (timeout || length) {
|
|
4165
|
-
let controller = new AbortController();
|
|
4166
|
-
let aborted;
|
|
4167
|
-
const onabort = function (reason) {
|
|
4168
|
-
if (!aborted) {
|
|
4169
|
-
aborted = true;
|
|
4170
|
-
unsubscribe();
|
|
4171
|
-
const err = reason instanceof Error ? reason : this.reason;
|
|
4172
|
-
controller.abort(err instanceof AxiosError ? err : new CanceledError(err instanceof Error ? err.message : err));
|
|
4173
|
-
}
|
|
4174
|
-
};
|
|
4175
|
-
let timer = timeout && setTimeout(() => {
|
|
4176
|
-
timer = null;
|
|
4177
|
-
onabort(new AxiosError(`timeout of ${timeout}ms exceeded`, AxiosError.ETIMEDOUT));
|
|
4178
|
-
}, timeout);
|
|
4179
|
-
const unsubscribe = () => {
|
|
4180
|
-
if (signals) {
|
|
4181
|
-
timer && clearTimeout(timer);
|
|
4182
|
-
timer = null;
|
|
4183
|
-
signals.forEach(signal => {
|
|
4184
|
-
signal.unsubscribe ? signal.unsubscribe(onabort) : signal.removeEventListener('abort', onabort);
|
|
4185
|
-
});
|
|
4186
|
-
signals = null;
|
|
4187
|
-
}
|
|
4188
|
-
};
|
|
4189
|
-
signals.forEach(signal => signal.addEventListener('abort', onabort));
|
|
4190
|
-
const {
|
|
4191
|
-
signal
|
|
4192
|
-
} = controller;
|
|
4193
|
-
signal.unsubscribe = () => utils$1.asap(unsubscribe);
|
|
4194
|
-
return signal;
|
|
4358
|
+
signals = signals ? signals.filter(Boolean) : [];
|
|
4359
|
+
if (!timeout && !signals.length) {
|
|
4360
|
+
return;
|
|
4195
4361
|
}
|
|
4362
|
+
const controller = new AbortController();
|
|
4363
|
+
let aborted = false;
|
|
4364
|
+
const onabort = function (reason) {
|
|
4365
|
+
if (!aborted) {
|
|
4366
|
+
aborted = true;
|
|
4367
|
+
unsubscribe();
|
|
4368
|
+
const err = reason instanceof Error ? reason : this.reason;
|
|
4369
|
+
controller.abort(err instanceof AxiosError ? err : new CanceledError(err instanceof Error ? err.message : err));
|
|
4370
|
+
}
|
|
4371
|
+
};
|
|
4372
|
+
let timer = timeout && setTimeout(() => {
|
|
4373
|
+
timer = null;
|
|
4374
|
+
onabort(new AxiosError(`timeout of ${timeout}ms exceeded`, AxiosError.ETIMEDOUT));
|
|
4375
|
+
}, timeout);
|
|
4376
|
+
const unsubscribe = () => {
|
|
4377
|
+
if (!signals) {
|
|
4378
|
+
return;
|
|
4379
|
+
}
|
|
4380
|
+
timer && clearTimeout(timer);
|
|
4381
|
+
timer = null;
|
|
4382
|
+
signals.forEach(signal => {
|
|
4383
|
+
signal.unsubscribe ? signal.unsubscribe(onabort) : signal.removeEventListener('abort', onabort);
|
|
4384
|
+
});
|
|
4385
|
+
signals = null;
|
|
4386
|
+
};
|
|
4387
|
+
signals.forEach(signal => signal.addEventListener('abort', onabort));
|
|
4388
|
+
const {
|
|
4389
|
+
signal
|
|
4390
|
+
} = controller;
|
|
4391
|
+
signal.unsubscribe = () => utils$1.asap(unsubscribe);
|
|
4392
|
+
return signal;
|
|
4196
4393
|
};
|
|
4197
4394
|
|
|
4198
4395
|
const streamChunk = function* (chunk, chunkSize) {
|
|
@@ -4281,6 +4478,31 @@ const DEFAULT_CHUNK_SIZE = 64 * 1024;
|
|
|
4281
4478
|
const {
|
|
4282
4479
|
isFunction
|
|
4283
4480
|
} = utils$1;
|
|
4481
|
+
|
|
4482
|
+
/**
|
|
4483
|
+
* Encode a UTF-8 string to a Latin-1 byte string for use with btoa().
|
|
4484
|
+
* This is a modern replacement for the deprecated unescape(encodeURIComponent(str)) pattern.
|
|
4485
|
+
*
|
|
4486
|
+
* @param {string} str The string to encode
|
|
4487
|
+
*
|
|
4488
|
+
* @returns {string} UTF-8 bytes as a Latin-1 string
|
|
4489
|
+
*/
|
|
4490
|
+
const encodeUTF8 = str => encodeURIComponent(str).replace(/%([0-9A-F]{2})/gi, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
|
|
4491
|
+
|
|
4492
|
+
// Node's WHATWG URL parser returns `username` and `password` percent-encoded.
|
|
4493
|
+
// Decode before composing the `auth` option so credentials such as
|
|
4494
|
+
// `my%40email.com:pass` are sent as `my@email.com:pass`. Falls back to the
|
|
4495
|
+
// original value for malformed input so a bad encoding never throws.
|
|
4496
|
+
const decodeURIComponentSafe = value => {
|
|
4497
|
+
if (!utils$1.isString(value)) {
|
|
4498
|
+
return value;
|
|
4499
|
+
}
|
|
4500
|
+
try {
|
|
4501
|
+
return decodeURIComponent(value);
|
|
4502
|
+
} catch (error) {
|
|
4503
|
+
return value;
|
|
4504
|
+
}
|
|
4505
|
+
};
|
|
4284
4506
|
const test = (fn, ...args) => {
|
|
4285
4507
|
try {
|
|
4286
4508
|
return !!fn(...args);
|
|
@@ -4288,9 +4510,16 @@ const test = (fn, ...args) => {
|
|
|
4288
4510
|
return false;
|
|
4289
4511
|
}
|
|
4290
4512
|
};
|
|
4513
|
+
const maybeWithAuthCredentials = url => {
|
|
4514
|
+
const protocolIndex = url.indexOf('://');
|
|
4515
|
+
let urlToCheck = url;
|
|
4516
|
+
if (protocolIndex !== -1) {
|
|
4517
|
+
urlToCheck = urlToCheck.slice(protocolIndex + 3);
|
|
4518
|
+
}
|
|
4519
|
+
return urlToCheck.includes('@') || urlToCheck.includes(':');
|
|
4520
|
+
};
|
|
4291
4521
|
const factory = env => {
|
|
4292
|
-
|
|
4293
|
-
const globalObject = (_utils$global = utils$1.global) !== null && _utils$global !== void 0 ? _utils$global : globalThis;
|
|
4522
|
+
const globalObject = utils$1.global !== undefined && utils$1.global !== null ? utils$1.global : globalThis;
|
|
4294
4523
|
const {
|
|
4295
4524
|
ReadableStream,
|
|
4296
4525
|
TextEncoder
|
|
@@ -4392,6 +4621,7 @@ const factory = env => {
|
|
|
4392
4621
|
} = resolveConfig(config);
|
|
4393
4622
|
const hasMaxContentLength = utils$1.isNumber(maxContentLength) && maxContentLength > -1;
|
|
4394
4623
|
const hasMaxBodyLength = utils$1.isNumber(maxBodyLength) && maxBodyLength > -1;
|
|
4624
|
+
const own = key => utils$1.hasOwnProp(config, key) ? config[key] : undefined;
|
|
4395
4625
|
let _fetch = envFetch || fetch;
|
|
4396
4626
|
responseType = responseType ? (responseType + '').toLowerCase() : 'text';
|
|
4397
4627
|
let composedSignal = composeSignals([signal, cancelToken && cancelToken.toAbortSignal()], timeout);
|
|
@@ -4401,6 +4631,38 @@ const factory = env => {
|
|
|
4401
4631
|
});
|
|
4402
4632
|
let requestContentLength;
|
|
4403
4633
|
try {
|
|
4634
|
+
// HTTP basic authentication
|
|
4635
|
+
let auth = undefined;
|
|
4636
|
+
const configAuth = own('auth');
|
|
4637
|
+
if (configAuth) {
|
|
4638
|
+
const username = configAuth.username || '';
|
|
4639
|
+
const password = configAuth.password || '';
|
|
4640
|
+
auth = {
|
|
4641
|
+
username,
|
|
4642
|
+
password
|
|
4643
|
+
};
|
|
4644
|
+
}
|
|
4645
|
+
if (maybeWithAuthCredentials(url)) {
|
|
4646
|
+
const parsedURL = new URL(url, platform.origin);
|
|
4647
|
+
if (!auth && (parsedURL.username || parsedURL.password)) {
|
|
4648
|
+
const urlUsername = decodeURIComponentSafe(parsedURL.username);
|
|
4649
|
+
const urlPassword = decodeURIComponentSafe(parsedURL.password);
|
|
4650
|
+
auth = {
|
|
4651
|
+
username: urlUsername,
|
|
4652
|
+
password: urlPassword
|
|
4653
|
+
};
|
|
4654
|
+
}
|
|
4655
|
+
if (parsedURL.username || parsedURL.password) {
|
|
4656
|
+
parsedURL.username = '';
|
|
4657
|
+
parsedURL.password = '';
|
|
4658
|
+
url = parsedURL.href;
|
|
4659
|
+
}
|
|
4660
|
+
}
|
|
4661
|
+
if (auth) {
|
|
4662
|
+
headers.delete('authorization');
|
|
4663
|
+
headers.set('Authorization', 'Basic ' + btoa(encodeUTF8((auth.username || '') + ':' + (auth.password || ''))));
|
|
4664
|
+
}
|
|
4665
|
+
|
|
4404
4666
|
// Enforce maxContentLength for data: URLs up-front so we never materialize
|
|
4405
4667
|
// an oversized payload. The HTTP adapter applies the same check (see http.js
|
|
4406
4668
|
// "if (protocol === 'data:')" branch).
|
|
@@ -4459,7 +4721,7 @@ const factory = env => {
|
|
|
4459
4721
|
...fetchOptions,
|
|
4460
4722
|
signal: composedSignal,
|
|
4461
4723
|
method: method.toUpperCase(),
|
|
4462
|
-
headers: headers.normalize()
|
|
4724
|
+
headers: toByteStringHeaderObject(headers.normalize()),
|
|
4463
4725
|
body: data,
|
|
4464
4726
|
duplex: 'half',
|
|
4465
4727
|
credentials: isCredentialsSupported ? withCredentials : undefined
|
|
@@ -4917,7 +5179,8 @@ class Axios {
|
|
|
4917
5179
|
silentJSONParsing: validators.transitional(validators.boolean),
|
|
4918
5180
|
forcedJSONParsing: validators.transitional(validators.boolean),
|
|
4919
5181
|
clarifyTimeoutError: validators.transitional(validators.boolean),
|
|
4920
|
-
legacyInterceptorReqResOrdering: validators.transitional(validators.boolean)
|
|
5182
|
+
legacyInterceptorReqResOrdering: validators.transitional(validators.boolean),
|
|
5183
|
+
advertiseZstdAcceptEncoding: validators.transitional(validators.boolean)
|
|
4921
5184
|
}, false);
|
|
4922
5185
|
}
|
|
4923
5186
|
if (paramsSerializer != null) {
|