axios 0.31.0 → 0.31.1
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/README.md +26 -7
- package/UPGRADE_GUIDE.md +2 -2
- package/dist/axios.js +66 -30
- package/dist/axios.js.map +1 -1
- package/dist/axios.min.js +1 -1
- package/dist/axios.min.js.map +1 -1
- package/dist/esm/axios.js +66 -30
- package/dist/esm/axios.js.map +1 -1
- package/dist/esm/axios.min.js +1 -1
- package/dist/esm/axios.min.js.map +1 -1
- package/index.d.ts +1 -0
- package/lib/adapters/http.js +82 -6
- package/lib/adapters/xhr.js +7 -3
- package/lib/core/AxiosError.js +2 -1
- package/lib/core/mergeConfig.js +20 -10
- package/lib/defaults/index.js +6 -3
- package/lib/env/data.js +1 -1
- package/lib/helpers/AxiosURLSearchParams.js +4 -3
- package/lib/helpers/toFormData.js +14 -3
- package/lib/utils.js +11 -5
- package/package.json +2 -2
package/lib/adapters/http.js
CHANGED
|
@@ -145,8 +145,9 @@ module.exports = function httpAdapter(config) {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
try {
|
|
148
|
+
var envOption = utils.hasOwnProperty(config, 'env') ? config.env : undefined;
|
|
148
149
|
convertedData = fromDataURI(config.url, responseType === 'blob', {
|
|
149
|
-
Blob:
|
|
150
|
+
Blob: envOption && envOption.Blob
|
|
150
151
|
});
|
|
151
152
|
} catch (err) {
|
|
152
153
|
throw AxiosError.from(err, AxiosError.ERR_BAD_REQUEST, config);
|
|
@@ -200,7 +201,8 @@ module.exports = function httpAdapter(config) {
|
|
|
200
201
|
}
|
|
201
202
|
|
|
202
203
|
// support for https://www.npmjs.com/package/form-data api
|
|
203
|
-
if (utils.isFormData(data) && utils.isFunction(data.getHeaders)
|
|
204
|
+
if (utils.isFormData(data) && utils.isFunction(data.getHeaders) &&
|
|
205
|
+
data.getHeaders !== Object.prototype.getHeaders) {
|
|
204
206
|
Object.assign(headers, data.getHeaders());
|
|
205
207
|
} else if (data && !utils.isStream(data)) {
|
|
206
208
|
if (Buffer.isBuffer(data)) {
|
|
@@ -282,7 +284,7 @@ module.exports = function httpAdapter(config) {
|
|
|
282
284
|
var transport;
|
|
283
285
|
var isHttpsRequest = isHttps.test(options.protocol);
|
|
284
286
|
options.agent = isHttpsRequest ? config.httpsAgent : config.httpAgent;
|
|
285
|
-
if (config.transport) {
|
|
287
|
+
if (utils.hasOwnProperty(config, 'transport') && config.transport) {
|
|
286
288
|
transport = config.transport;
|
|
287
289
|
} else if (config.maxRedirects === 0) {
|
|
288
290
|
transport = isHttpsRequest ? https : http;
|
|
@@ -348,8 +350,47 @@ module.exports = function httpAdapter(config) {
|
|
|
348
350
|
};
|
|
349
351
|
|
|
350
352
|
if (responseType === 'stream') {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
+
// Enforce maxContentLength on streamed responses too (GHSA-vf2m-468p-8v99).
|
|
354
|
+
// Previously the stream path bypassed the size guard because the check only
|
|
355
|
+
// ran on the buffering branch.
|
|
356
|
+
if (config.maxContentLength > -1) {
|
|
357
|
+
var maxContentLength = config.maxContentLength;
|
|
358
|
+
var streamedBytes = 0;
|
|
359
|
+
var limiter = new stream.Transform({
|
|
360
|
+
transform: function transformChunk(chunk, encoding, callback) {
|
|
361
|
+
streamedBytes += chunk.length;
|
|
362
|
+
if (streamedBytes > maxContentLength) {
|
|
363
|
+
callback(new AxiosError(
|
|
364
|
+
'maxContentLength size of ' + maxContentLength + ' exceeded',
|
|
365
|
+
AxiosError.ERR_BAD_RESPONSE,
|
|
366
|
+
config,
|
|
367
|
+
lastRequest
|
|
368
|
+
));
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
callback(null, chunk);
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
limiter.on('error', function handleLimiterError() {
|
|
375
|
+
rejected = true;
|
|
376
|
+
responseStream.destroy();
|
|
377
|
+
});
|
|
378
|
+
responseStream.on('error', function forwardError(err) {
|
|
379
|
+
limiter.destroy(err);
|
|
380
|
+
});
|
|
381
|
+
response.data = limiter;
|
|
382
|
+
settle(resolve, reject, response);
|
|
383
|
+
// Defer piping via setImmediate so the caller's `.then` (a microtask)
|
|
384
|
+
// has run and attached any `error`/`data` listeners before chunks flow
|
|
385
|
+
// through the transform. `process.nextTick` would drain before those
|
|
386
|
+
// microtasks and lose the error event.
|
|
387
|
+
setImmediate(function startPipe() {
|
|
388
|
+
responseStream.pipe(limiter);
|
|
389
|
+
});
|
|
390
|
+
} else {
|
|
391
|
+
response.data = responseStream;
|
|
392
|
+
settle(resolve, reject, response);
|
|
393
|
+
}
|
|
353
394
|
} else {
|
|
354
395
|
var responseBuffer = [];
|
|
355
396
|
var totalResponseBytes = 0;
|
|
@@ -474,7 +515,42 @@ module.exports = function httpAdapter(config) {
|
|
|
474
515
|
if (utils.isStream(data)) {
|
|
475
516
|
data.on('error', function handleStreamError(err) {
|
|
476
517
|
reject(AxiosError.from(err, config, null, req));
|
|
477
|
-
})
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
// follow-redirects enforces options.maxBodyLength for stream uploads, but the
|
|
521
|
+
// native http/https transport (used when maxRedirects === 0) does not.
|
|
522
|
+
// Count bytes ourselves so the limit is always honored (GHSA-5c9x-8gcm-mpgx).
|
|
523
|
+
var nativeTransport = transport === http || transport === https;
|
|
524
|
+
if (nativeTransport && config.maxBodyLength > -1) {
|
|
525
|
+
var maxBodyLength = config.maxBodyLength;
|
|
526
|
+
var uploadedBytes = 0;
|
|
527
|
+
var bodyLimiter = new stream.Transform({
|
|
528
|
+
transform: function transformChunk(chunk, encoding, callback) {
|
|
529
|
+
uploadedBytes += chunk.length;
|
|
530
|
+
if (uploadedBytes > maxBodyLength) {
|
|
531
|
+
callback(new AxiosError(
|
|
532
|
+
'Request body larger than maxBodyLength limit',
|
|
533
|
+
AxiosError.ERR_BAD_REQUEST,
|
|
534
|
+
config,
|
|
535
|
+
req
|
|
536
|
+
));
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
callback(null, chunk);
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
bodyLimiter.on('error', function handleLimiterError(err) {
|
|
543
|
+
if (rejected) return;
|
|
544
|
+
rejected = true;
|
|
545
|
+
try { data.unpipe(bodyLimiter); } catch (e) { /* noop */ }
|
|
546
|
+
try { bodyLimiter.unpipe(req); } catch (e) { /* noop */ }
|
|
547
|
+
req.destroy();
|
|
548
|
+
reject(err);
|
|
549
|
+
});
|
|
550
|
+
data.pipe(bodyLimiter).pipe(req);
|
|
551
|
+
} else {
|
|
552
|
+
data.pipe(req);
|
|
553
|
+
}
|
|
478
554
|
} else {
|
|
479
555
|
req.end(data);
|
|
480
556
|
}
|
package/lib/adapters/xhr.js
CHANGED
|
@@ -18,7 +18,8 @@ module.exports = function xhrAdapter(config) {
|
|
|
18
18
|
var requestData = config.data;
|
|
19
19
|
var requestHeaders = config.headers;
|
|
20
20
|
var responseType = config.responseType;
|
|
21
|
-
|
|
21
|
+
// Guard against prototype pollution (GHSA-xx6v-rp6x-q39c): only honor own properties.
|
|
22
|
+
var withXSRFToken = utils.hasOwnProperty(config, 'withXSRFToken') ? config.withXSRFToken : undefined;
|
|
22
23
|
var onCanceled;
|
|
23
24
|
function done() {
|
|
24
25
|
if (config.cancelToken) {
|
|
@@ -146,8 +147,11 @@ module.exports = function xhrAdapter(config) {
|
|
|
146
147
|
// Specifically not if we're in a web worker, or react-native.
|
|
147
148
|
if (utils.isStandardBrowserEnv()) {
|
|
148
149
|
// Add xsrf header
|
|
149
|
-
|
|
150
|
-
|
|
150
|
+
if (utils.isFunction(withXSRFToken)) {
|
|
151
|
+
withXSRFToken = withXSRFToken(config);
|
|
152
|
+
}
|
|
153
|
+
// Strict boolean check (GHSA-xx6v-rp6x-q39c): only `true` short-circuits the same-origin guard.
|
|
154
|
+
if (withXSRFToken === true || (withXSRFToken !== false && isURLSameOrigin(fullPath))) {
|
|
151
155
|
// Add xsrf header
|
|
152
156
|
var xsrfValue = config.xsrfHeaderName && config.xsrfCookieName && cookies.read(config.xsrfCookieName);
|
|
153
157
|
if (xsrfValue) {
|
package/lib/core/AxiosError.js
CHANGED
|
@@ -66,7 +66,8 @@ var descriptors = {};
|
|
|
66
66
|
'ERR_BAD_REQUEST',
|
|
67
67
|
'ERR_CANCELED',
|
|
68
68
|
'ERR_NOT_SUPPORT',
|
|
69
|
-
'ERR_INVALID_URL'
|
|
69
|
+
'ERR_INVALID_URL',
|
|
70
|
+
'ERR_FORM_DATA_DEPTH_EXCEEDED'
|
|
70
71
|
// eslint-disable-next-line func-names
|
|
71
72
|
].forEach(function(code) {
|
|
72
73
|
descriptors[code] = {value: code};
|
package/lib/core/mergeConfig.js
CHANGED
|
@@ -13,7 +13,17 @@ var utils = require('../utils');
|
|
|
13
13
|
module.exports = function mergeConfig(config1, config2) {
|
|
14
14
|
// eslint-disable-next-line no-param-reassign
|
|
15
15
|
config2 = config2 || {};
|
|
16
|
-
|
|
16
|
+
// Use a null-prototype object so a polluted Object.prototype cannot leak
|
|
17
|
+
// values (e.g. transport, adapter) into the returned config via inheritance.
|
|
18
|
+
var config = Object.create(null);
|
|
19
|
+
|
|
20
|
+
function getOwn(source, prop) {
|
|
21
|
+
return utils.hasOwnProperty(source, prop) ? source[prop] : undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function hasOwn(source, prop) {
|
|
25
|
+
return utils.hasOwnProperty(source, prop);
|
|
26
|
+
}
|
|
17
27
|
|
|
18
28
|
function getMergedValue(target, source) {
|
|
19
29
|
if (utils.isPlainObject(target) && utils.isPlainObject(source)) {
|
|
@@ -30,34 +40,34 @@ module.exports = function mergeConfig(config1, config2) {
|
|
|
30
40
|
|
|
31
41
|
// eslint-disable-next-line consistent-return
|
|
32
42
|
function mergeDeepProperties(prop) {
|
|
33
|
-
if (!utils.isUndefined(config2[prop])) {
|
|
34
|
-
return getMergedValue(config1
|
|
35
|
-
} else if (!utils.isUndefined(config1[prop])) {
|
|
43
|
+
if (hasOwn(config2, prop) && !utils.isUndefined(config2[prop])) {
|
|
44
|
+
return getMergedValue(getOwn(config1, prop), config2[prop]);
|
|
45
|
+
} else if (hasOwn(config1, prop) && !utils.isUndefined(config1[prop])) {
|
|
36
46
|
return getMergedValue(undefined, config1[prop]);
|
|
37
47
|
}
|
|
38
48
|
}
|
|
39
49
|
|
|
40
50
|
// eslint-disable-next-line consistent-return
|
|
41
51
|
function valueFromConfig2(prop) {
|
|
42
|
-
if (!utils.isUndefined(config2[prop])) {
|
|
52
|
+
if (hasOwn(config2, prop) && !utils.isUndefined(config2[prop])) {
|
|
43
53
|
return getMergedValue(undefined, config2[prop]);
|
|
44
54
|
}
|
|
45
55
|
}
|
|
46
56
|
|
|
47
57
|
// eslint-disable-next-line consistent-return
|
|
48
58
|
function defaultToConfig2(prop) {
|
|
49
|
-
if (!utils.isUndefined(config2[prop])) {
|
|
59
|
+
if (hasOwn(config2, prop) && !utils.isUndefined(config2[prop])) {
|
|
50
60
|
return getMergedValue(undefined, config2[prop]);
|
|
51
|
-
} else if (!utils.isUndefined(config1[prop])) {
|
|
61
|
+
} else if (hasOwn(config1, prop) && !utils.isUndefined(config1[prop])) {
|
|
52
62
|
return getMergedValue(undefined, config1[prop]);
|
|
53
63
|
}
|
|
54
64
|
}
|
|
55
65
|
|
|
56
66
|
// eslint-disable-next-line consistent-return
|
|
57
67
|
function mergeDirectKeys(prop) {
|
|
58
|
-
if (prop
|
|
59
|
-
return getMergedValue(config1
|
|
60
|
-
} else if (prop
|
|
68
|
+
if (hasOwn(config2, prop)) {
|
|
69
|
+
return getMergedValue(getOwn(config1, prop), config2[prop]);
|
|
70
|
+
} else if (hasOwn(config1, prop)) {
|
|
61
71
|
return getMergedValue(undefined, config1[prop]);
|
|
62
72
|
}
|
|
63
73
|
}
|
package/lib/defaults/index.js
CHANGED
|
@@ -89,17 +89,20 @@ var defaults = {
|
|
|
89
89
|
var isFileList;
|
|
90
90
|
|
|
91
91
|
if (isObjectPayload) {
|
|
92
|
+
var formSerializer = utils.hasOwnProperty(this, 'formSerializer') ? this.formSerializer : undefined;
|
|
93
|
+
var envOption = utils.hasOwnProperty(this, 'env') ? this.env : undefined;
|
|
94
|
+
|
|
92
95
|
if (contentType.indexOf('application/x-www-form-urlencoded') !== -1) {
|
|
93
|
-
return toURLEncodedForm(data,
|
|
96
|
+
return toURLEncodedForm(data, formSerializer).toString();
|
|
94
97
|
}
|
|
95
98
|
|
|
96
99
|
if ((isFileList = utils.isFileList(data)) || contentType.indexOf('multipart/form-data') > -1) {
|
|
97
|
-
var _FormData =
|
|
100
|
+
var _FormData = envOption && envOption.FormData;
|
|
98
101
|
|
|
99
102
|
return toFormData(
|
|
100
103
|
isFileList ? {'files[]': data} : data,
|
|
101
104
|
_FormData && new _FormData(),
|
|
102
|
-
|
|
105
|
+
formSerializer
|
|
103
106
|
);
|
|
104
107
|
}
|
|
105
108
|
}
|
package/lib/env/data.js
CHANGED
|
@@ -3,16 +3,17 @@
|
|
|
3
3
|
var toFormData = require('./toFormData');
|
|
4
4
|
|
|
5
5
|
function encode(str) {
|
|
6
|
+
// Do not map `%00` back to a raw null byte (GHSA-xhjh-pmcv-23jw): that reversed
|
|
7
|
+
// the safe percent-encoding from encodeURIComponent and enabled null byte injection.
|
|
6
8
|
var charMap = {
|
|
7
9
|
'!': '%21',
|
|
8
10
|
"'": '%27',
|
|
9
11
|
'(': '%28',
|
|
10
12
|
')': '%29',
|
|
11
13
|
'~': '%7E',
|
|
12
|
-
'%20': '+'
|
|
13
|
-
'%00': '\x00'
|
|
14
|
+
'%20': '+'
|
|
14
15
|
};
|
|
15
|
-
return encodeURIComponent(str).replace(/[!'\(\)~]|%20
|
|
16
|
+
return encodeURIComponent(str).replace(/[!'\(\)~]|%20/g, function replacer(match) {
|
|
16
17
|
return charMap[match];
|
|
17
18
|
});
|
|
18
19
|
}
|
|
@@ -69,6 +69,7 @@ function toFormData(obj, formData, options) {
|
|
|
69
69
|
var dots = options.dots;
|
|
70
70
|
var indexes = options.indexes;
|
|
71
71
|
var _Blob = options.Blob || typeof Blob !== 'undefined' && Blob;
|
|
72
|
+
var maxDepth = options.maxDepth === undefined ? 100 : options.maxDepth;
|
|
72
73
|
var useBlob = _Blob && isSpecCompliant(formData);
|
|
73
74
|
|
|
74
75
|
if (!utils.isFunction(visitor)) {
|
|
@@ -145,9 +146,19 @@ function toFormData(obj, formData, options) {
|
|
|
145
146
|
isVisitable: isVisitable
|
|
146
147
|
});
|
|
147
148
|
|
|
148
|
-
function build(value, path) {
|
|
149
|
+
function build(value, path, depth) {
|
|
149
150
|
if (utils.isUndefined(value)) return;
|
|
150
151
|
|
|
152
|
+
// eslint-disable-next-line no-param-reassign
|
|
153
|
+
depth = depth || 0;
|
|
154
|
+
|
|
155
|
+
if (depth > maxDepth) {
|
|
156
|
+
throw new AxiosError(
|
|
157
|
+
'Maximum object depth of ' + maxDepth + ' exceeded (got ' + depth + ' levels)',
|
|
158
|
+
AxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
151
162
|
if (stack.indexOf(value) !== -1) {
|
|
152
163
|
throw Error('Circular reference detected in ' + path.join('.'));
|
|
153
164
|
}
|
|
@@ -160,7 +171,7 @@ function toFormData(obj, formData, options) {
|
|
|
160
171
|
);
|
|
161
172
|
|
|
162
173
|
if (result === true) {
|
|
163
|
-
build(el, path ? path.concat(key) : [key]);
|
|
174
|
+
build(el, path ? path.concat(key) : [key], depth + 1);
|
|
164
175
|
}
|
|
165
176
|
});
|
|
166
177
|
|
|
@@ -171,7 +182,7 @@ function toFormData(obj, formData, options) {
|
|
|
171
182
|
throw new TypeError('data must be an object');
|
|
172
183
|
}
|
|
173
184
|
|
|
174
|
-
build(obj);
|
|
185
|
+
build(obj, null, 0);
|
|
175
186
|
|
|
176
187
|
return formData;
|
|
177
188
|
}
|
package/lib/utils.js
CHANGED
|
@@ -206,11 +206,17 @@ function isStream(val) {
|
|
|
206
206
|
*/
|
|
207
207
|
function isFormData(thing) {
|
|
208
208
|
var pattern = '[object FormData]';
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
);
|
|
209
|
+
if (!thing) return false;
|
|
210
|
+
if (typeof FormData === 'function' && thing instanceof FormData) return true;
|
|
211
|
+
// Reject non-objects (strings, numbers, booleans) up front — Object.getPrototypeOf
|
|
212
|
+
// throws a TypeError on primitives in ES5 environments.
|
|
213
|
+
if (!isObject(thing)) return false;
|
|
214
|
+
// Reject plain objects inheriting directly from Object.prototype so prototype-pollution gadgets can't spoof FormData (GHSA-6chq-wfr3-2hj9).
|
|
215
|
+
var proto = Object.getPrototypeOf(thing);
|
|
216
|
+
if (!proto || proto === Object.prototype) return false;
|
|
217
|
+
if (!isFunction(thing.append)) return false;
|
|
218
|
+
return toString.call(thing) === pattern ||
|
|
219
|
+
(isFunction(thing.toString) && thing.toString() === pattern);
|
|
214
220
|
}
|
|
215
221
|
|
|
216
222
|
/**
|
package/package.json
CHANGED