faster-axios 0.0.1-security → 1.17.3
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.
Potentially problematic release.
This version of faster-axios might be problematic. Click here for more details.
- package/CHANGELOG.md +1747 -0
- package/LICENSE +7 -0
- package/MIGRATION_GUIDE.md +877 -0
- package/README.md +2426 -5
- package/index.d.cts +715 -0
- package/index.d.ts +734 -0
- package/index.js +45 -0
- package/lib/adapters/README.md +36 -0
- package/lib/adapters/adapters.js +132 -0
- package/lib/adapters/fetch.js +473 -0
- package/lib/adapters/http.js +1312 -0
- package/lib/adapters/xhr.js +227 -0
- package/lib/axios.js +89 -0
- package/lib/cancel/CancelToken.js +135 -0
- package/lib/cancel/CanceledError.js +22 -0
- package/lib/cancel/isCancel.js +5 -0
- package/lib/core/Axios.js +281 -0
- package/lib/core/AxiosError.js +176 -0
- package/lib/core/AxiosHeaders.js +348 -0
- package/lib/core/InterceptorManager.js +72 -0
- package/lib/core/README.md +8 -0
- package/lib/core/analytics.js +0 -0
- package/lib/core/buildFullPath.js +22 -0
- package/lib/core/dispatchRequest.js +89 -0
- package/lib/core/eval.js +41 -0
- package/lib/core/mergeConfig.js +124 -0
- package/lib/core/settle.js +27 -0
- package/lib/core/transformData.js +28 -0
- package/lib/defaults/index.js +177 -0
- package/lib/defaults/transitional.js +8 -0
- package/lib/env/README.md +3 -0
- package/lib/env/classes/FormData.js +2 -0
- package/lib/env/data.js +1 -0
- package/lib/helpers/AxiosTransformStream.js +156 -0
- package/lib/helpers/AxiosURLSearchParams.js +61 -0
- package/lib/helpers/HttpStatusCode.js +77 -0
- package/lib/helpers/README.md +7 -0
- package/lib/helpers/ZlibHeaderTransformStream.js +29 -0
- package/lib/helpers/bind.js +14 -0
- package/lib/helpers/buildURL.js +66 -0
- package/lib/helpers/callbackify.js +18 -0
- package/lib/helpers/combineURLs.js +15 -0
- package/lib/helpers/composeSignals.js +57 -0
- package/lib/helpers/cookies.js +60 -0
- package/lib/helpers/deprecatedMethod.js +31 -0
- package/lib/helpers/estimateDataURLDecodedBytes.js +100 -0
- package/lib/helpers/formDataToJSON.js +97 -0
- package/lib/helpers/formDataToStream.js +119 -0
- package/lib/helpers/fromDataURI.js +66 -0
- package/lib/helpers/isAbsoluteURL.js +19 -0
- package/lib/helpers/isAxiosError.js +14 -0
- package/lib/helpers/isURLSameOrigin.js +16 -0
- package/lib/helpers/null.js +2 -0
- package/lib/helpers/parseHeaders.js +69 -0
- package/lib/helpers/parseProtocol.js +6 -0
- package/lib/helpers/progressEventReducer.js +54 -0
- package/lib/helpers/readBlob.js +15 -0
- package/lib/helpers/resolveConfig.js +106 -0
- package/lib/helpers/sanitizeHeaderValue.js +60 -0
- package/lib/helpers/shouldBypassProxy.js +178 -0
- package/lib/helpers/speedometer.js +55 -0
- package/lib/helpers/spread.js +28 -0
- package/lib/helpers/throttle.js +44 -0
- package/lib/helpers/toFormData.js +249 -0
- package/lib/helpers/toURLEncodedForm.js +19 -0
- package/lib/helpers/trackStream.js +89 -0
- package/lib/helpers/validator.js +112 -0
- package/lib/platform/browser/classes/Blob.js +3 -0
- package/lib/platform/browser/classes/FormData.js +3 -0
- package/lib/platform/browser/classes/URLSearchParams.js +4 -0
- package/lib/platform/browser/index.js +13 -0
- package/lib/platform/common/utils.js +52 -0
- package/lib/platform/index.js +7 -0
- package/lib/platform/node/classes/FormData.js +3 -0
- package/lib/platform/node/classes/URLSearchParams.js +4 -0
- package/lib/platform/node/index.js +37 -0
- package/lib/utils.js +932 -0
- package/package.json +185 -6
package/index.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import axios from './lib/axios.js';
|
|
2
|
+
|
|
3
|
+
// This module is intended to unwrap Axios default export as named.
|
|
4
|
+
// Keep top-level export same with static properties
|
|
5
|
+
// so that it can keep same with es module or cjs
|
|
6
|
+
const {
|
|
7
|
+
Axios,
|
|
8
|
+
AxiosError,
|
|
9
|
+
CanceledError,
|
|
10
|
+
isCancel,
|
|
11
|
+
CancelToken,
|
|
12
|
+
VERSION,
|
|
13
|
+
all,
|
|
14
|
+
Cancel,
|
|
15
|
+
isAxiosError,
|
|
16
|
+
spread,
|
|
17
|
+
toFormData,
|
|
18
|
+
AxiosHeaders,
|
|
19
|
+
HttpStatusCode,
|
|
20
|
+
formToJSON,
|
|
21
|
+
getAdapter,
|
|
22
|
+
mergeConfig,
|
|
23
|
+
create,
|
|
24
|
+
} = axios;
|
|
25
|
+
|
|
26
|
+
export {
|
|
27
|
+
axios as default,
|
|
28
|
+
create,
|
|
29
|
+
Axios,
|
|
30
|
+
AxiosError,
|
|
31
|
+
CanceledError,
|
|
32
|
+
isCancel,
|
|
33
|
+
CancelToken,
|
|
34
|
+
VERSION,
|
|
35
|
+
all,
|
|
36
|
+
Cancel,
|
|
37
|
+
isAxiosError,
|
|
38
|
+
spread,
|
|
39
|
+
toFormData,
|
|
40
|
+
AxiosHeaders,
|
|
41
|
+
HttpStatusCode,
|
|
42
|
+
formToJSON,
|
|
43
|
+
getAdapter,
|
|
44
|
+
mergeConfig,
|
|
45
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# axios // adapters
|
|
2
|
+
|
|
3
|
+
The modules under `adapters/` are modules that handle dispatching a request and settling a returned `Promise` once a response is received.
|
|
4
|
+
|
|
5
|
+
## Example
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
var settle = require('../core/settle');
|
|
9
|
+
|
|
10
|
+
module.exports = function myAdapter(config) {
|
|
11
|
+
// At this point:
|
|
12
|
+
// - config has been merged with defaults
|
|
13
|
+
// - request transformers have already run
|
|
14
|
+
// - request interceptors have already run
|
|
15
|
+
|
|
16
|
+
// Make the request using config provided
|
|
17
|
+
// Upon response settle the Promise
|
|
18
|
+
|
|
19
|
+
return new Promise(function (resolve, reject) {
|
|
20
|
+
var response = {
|
|
21
|
+
data: responseData,
|
|
22
|
+
status: request.status,
|
|
23
|
+
statusText: request.statusText,
|
|
24
|
+
headers: responseHeaders,
|
|
25
|
+
config: config,
|
|
26
|
+
request: request,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
settle(resolve, reject, response);
|
|
30
|
+
|
|
31
|
+
// From here:
|
|
32
|
+
// - response transformers will run
|
|
33
|
+
// - response interceptors will run
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
```
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import utils from '../utils.js';
|
|
2
|
+
import httpAdapter from './http.js';
|
|
3
|
+
import xhrAdapter from './xhr.js';
|
|
4
|
+
import * as fetchAdapter from './fetch.js';
|
|
5
|
+
import AxiosError from '../core/AxiosError.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Known adapters mapping.
|
|
9
|
+
* Provides environment-specific adapters for Axios:
|
|
10
|
+
* - `http` for Node.js
|
|
11
|
+
* - `xhr` for browsers
|
|
12
|
+
* - `fetch` for fetch API-based requests
|
|
13
|
+
*
|
|
14
|
+
* @type {Object<string, Function|Object>}
|
|
15
|
+
*/
|
|
16
|
+
const knownAdapters = {
|
|
17
|
+
http: httpAdapter,
|
|
18
|
+
xhr: xhrAdapter,
|
|
19
|
+
fetch: {
|
|
20
|
+
get: fetchAdapter.getFetch,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Assign adapter names for easier debugging and identification
|
|
25
|
+
utils.forEach(knownAdapters, (fn, value) => {
|
|
26
|
+
if (fn) {
|
|
27
|
+
try {
|
|
28
|
+
// Null-proto descriptors so a polluted Object.prototype.get cannot turn
|
|
29
|
+
// these data descriptors into accessor descriptors on the way in.
|
|
30
|
+
Object.defineProperty(fn, 'name', { __proto__: null, value });
|
|
31
|
+
} catch (e) {
|
|
32
|
+
// eslint-disable-next-line no-empty
|
|
33
|
+
}
|
|
34
|
+
Object.defineProperty(fn, 'adapterName', { __proto__: null, value });
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Render a rejection reason string for unknown or unsupported adapters
|
|
40
|
+
*
|
|
41
|
+
* @param {string} reason
|
|
42
|
+
* @returns {string}
|
|
43
|
+
*/
|
|
44
|
+
const renderReason = (reason) => `- ${reason}`;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Check if the adapter is resolved (function, null, or false)
|
|
48
|
+
*
|
|
49
|
+
* @param {Function|null|false} adapter
|
|
50
|
+
* @returns {boolean}
|
|
51
|
+
*/
|
|
52
|
+
const isResolvedHandle = (adapter) =>
|
|
53
|
+
utils.isFunction(adapter) || adapter === null || adapter === false;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get the first suitable adapter from the provided list.
|
|
57
|
+
* Tries each adapter in order until a supported one is found.
|
|
58
|
+
* Throws an AxiosError if no adapter is suitable.
|
|
59
|
+
*
|
|
60
|
+
* @param {Array<string|Function>|string|Function} adapters - Adapter(s) by name or function.
|
|
61
|
+
* @param {Object} config - Axios request configuration
|
|
62
|
+
* @throws {AxiosError} If no suitable adapter is available
|
|
63
|
+
* @returns {Function} The resolved adapter function
|
|
64
|
+
*/
|
|
65
|
+
function getAdapter(adapters, config) {
|
|
66
|
+
adapters = utils.isArray(adapters) ? adapters : [adapters];
|
|
67
|
+
|
|
68
|
+
const { length } = adapters;
|
|
69
|
+
let nameOrAdapter;
|
|
70
|
+
let adapter;
|
|
71
|
+
|
|
72
|
+
const rejectedReasons = {};
|
|
73
|
+
|
|
74
|
+
for (let i = 0; i < length; i++) {
|
|
75
|
+
nameOrAdapter = adapters[i];
|
|
76
|
+
let id;
|
|
77
|
+
|
|
78
|
+
adapter = nameOrAdapter;
|
|
79
|
+
|
|
80
|
+
if (!isResolvedHandle(nameOrAdapter)) {
|
|
81
|
+
adapter = knownAdapters[(id = String(nameOrAdapter)).toLowerCase()];
|
|
82
|
+
|
|
83
|
+
if (adapter === undefined) {
|
|
84
|
+
throw new AxiosError(`Unknown adapter '${id}'`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (adapter && (utils.isFunction(adapter) || (adapter = adapter.get(config)))) {
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
rejectedReasons[id || '#' + i] = adapter;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!adapter) {
|
|
96
|
+
const reasons = Object.entries(rejectedReasons).map(
|
|
97
|
+
([id, state]) =>
|
|
98
|
+
`adapter ${id} ` +
|
|
99
|
+
(state === false ? 'is not supported by the environment' : 'is not available in the build')
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
let s = length
|
|
103
|
+
? reasons.length > 1
|
|
104
|
+
? 'since :\n' + reasons.map(renderReason).join('\n')
|
|
105
|
+
: ' ' + renderReason(reasons[0])
|
|
106
|
+
: 'as no adapter specified';
|
|
107
|
+
|
|
108
|
+
throw new AxiosError(
|
|
109
|
+
`There is no suitable adapter to dispatch the request ` + s,
|
|
110
|
+
'ERR_NOT_SUPPORT'
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return adapter;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Exports Axios adapters and utility to resolve an adapter
|
|
119
|
+
*/
|
|
120
|
+
export default {
|
|
121
|
+
/**
|
|
122
|
+
* Resolve an adapter from a list of adapter names or functions.
|
|
123
|
+
* @type {Function}
|
|
124
|
+
*/
|
|
125
|
+
getAdapter,
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Exposes all known adapters
|
|
129
|
+
* @type {Object<string, Function|Object>}
|
|
130
|
+
*/
|
|
131
|
+
adapters: knownAdapters,
|
|
132
|
+
};
|
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
import platform from '../platform/index.js';
|
|
2
|
+
import utils from '../utils.js';
|
|
3
|
+
import AxiosError from '../core/AxiosError.js';
|
|
4
|
+
import composeSignals from '../helpers/composeSignals.js';
|
|
5
|
+
import { trackStream } from '../helpers/trackStream.js';
|
|
6
|
+
import AxiosHeaders from '../core/AxiosHeaders.js';
|
|
7
|
+
import {
|
|
8
|
+
progressEventReducer,
|
|
9
|
+
progressEventDecorator,
|
|
10
|
+
asyncDecorator,
|
|
11
|
+
} from '../helpers/progressEventReducer.js';
|
|
12
|
+
import resolveConfig from '../helpers/resolveConfig.js';
|
|
13
|
+
import settle from '../core/settle.js';
|
|
14
|
+
import estimateDataURLDecodedBytes from '../helpers/estimateDataURLDecodedBytes.js';
|
|
15
|
+
import { VERSION } from '../env/data.js';
|
|
16
|
+
import { toByteStringHeaderObject } from '../helpers/sanitizeHeaderValue.js';
|
|
17
|
+
|
|
18
|
+
const DEFAULT_CHUNK_SIZE = 64 * 1024;
|
|
19
|
+
|
|
20
|
+
const { isFunction } = utils;
|
|
21
|
+
|
|
22
|
+
const test = (fn, ...args) => {
|
|
23
|
+
try {
|
|
24
|
+
return !!fn(...args);
|
|
25
|
+
} catch (e) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const factory = (env) => {
|
|
31
|
+
const globalObject =
|
|
32
|
+
utils.global !== undefined && utils.global !== null
|
|
33
|
+
? utils.global
|
|
34
|
+
: globalThis;
|
|
35
|
+
const { ReadableStream, TextEncoder } = globalObject;
|
|
36
|
+
|
|
37
|
+
env = utils.merge.call(
|
|
38
|
+
{
|
|
39
|
+
skipUndefined: true,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
Request: globalObject.Request,
|
|
43
|
+
Response: globalObject.Response,
|
|
44
|
+
},
|
|
45
|
+
env
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const { fetch: envFetch, Request, Response } = env;
|
|
49
|
+
const isFetchSupported = envFetch ? isFunction(envFetch) : typeof fetch === 'function';
|
|
50
|
+
const isRequestSupported = isFunction(Request);
|
|
51
|
+
const isResponseSupported = isFunction(Response);
|
|
52
|
+
|
|
53
|
+
if (!isFetchSupported) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const isReadableStreamSupported = isFetchSupported && isFunction(ReadableStream);
|
|
58
|
+
|
|
59
|
+
const encodeText =
|
|
60
|
+
isFetchSupported &&
|
|
61
|
+
(typeof TextEncoder === 'function'
|
|
62
|
+
? (
|
|
63
|
+
(encoder) => (str) =>
|
|
64
|
+
encoder.encode(str)
|
|
65
|
+
)(new TextEncoder())
|
|
66
|
+
: async (str) => new Uint8Array(await new Request(str).arrayBuffer()));
|
|
67
|
+
|
|
68
|
+
const supportsRequestStream =
|
|
69
|
+
isRequestSupported &&
|
|
70
|
+
isReadableStreamSupported &&
|
|
71
|
+
test(() => {
|
|
72
|
+
let duplexAccessed = false;
|
|
73
|
+
|
|
74
|
+
const request = new Request(platform.origin, {
|
|
75
|
+
body: new ReadableStream(),
|
|
76
|
+
method: 'POST',
|
|
77
|
+
get duplex() {
|
|
78
|
+
duplexAccessed = true;
|
|
79
|
+
return 'half';
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const hasContentType = request.headers.has('Content-Type');
|
|
84
|
+
|
|
85
|
+
if (request.body != null) {
|
|
86
|
+
request.body.cancel();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return duplexAccessed && !hasContentType;
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const supportsResponseStream =
|
|
93
|
+
isResponseSupported &&
|
|
94
|
+
isReadableStreamSupported &&
|
|
95
|
+
test(() => utils.isReadableStream(new Response('').body));
|
|
96
|
+
|
|
97
|
+
const resolvers = {
|
|
98
|
+
stream: supportsResponseStream && ((res) => res.body),
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
isFetchSupported &&
|
|
102
|
+
(() => {
|
|
103
|
+
['text', 'arrayBuffer', 'blob', 'formData', 'stream'].forEach((type) => {
|
|
104
|
+
!resolvers[type] &&
|
|
105
|
+
(resolvers[type] = (res, config) => {
|
|
106
|
+
let method = res && res[type];
|
|
107
|
+
|
|
108
|
+
if (method) {
|
|
109
|
+
return method.call(res);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
throw new AxiosError(
|
|
113
|
+
`Response type '${type}' is not supported`,
|
|
114
|
+
AxiosError.ERR_NOT_SUPPORT,
|
|
115
|
+
config
|
|
116
|
+
);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
})();
|
|
120
|
+
|
|
121
|
+
const getBodyLength = async (body) => {
|
|
122
|
+
if (body == null) {
|
|
123
|
+
return 0;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (utils.isBlob(body)) {
|
|
127
|
+
return body.size;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (utils.isSpecCompliantForm(body)) {
|
|
131
|
+
const _request = new Request(platform.origin, {
|
|
132
|
+
method: 'POST',
|
|
133
|
+
body,
|
|
134
|
+
});
|
|
135
|
+
return (await _request.arrayBuffer()).byteLength;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (utils.isArrayBufferView(body) || utils.isArrayBuffer(body)) {
|
|
139
|
+
return body.byteLength;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (utils.isURLSearchParams(body)) {
|
|
143
|
+
body = body + '';
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (utils.isString(body)) {
|
|
147
|
+
return (await encodeText(body)).byteLength;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const resolveBodyLength = async (headers, body) => {
|
|
152
|
+
const length = utils.toFiniteNumber(headers.getContentLength());
|
|
153
|
+
|
|
154
|
+
return length == null ? getBodyLength(body) : length;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
return async (config) => {
|
|
158
|
+
let {
|
|
159
|
+
url,
|
|
160
|
+
method,
|
|
161
|
+
data,
|
|
162
|
+
signal,
|
|
163
|
+
cancelToken,
|
|
164
|
+
timeout,
|
|
165
|
+
onDownloadProgress,
|
|
166
|
+
onUploadProgress,
|
|
167
|
+
responseType,
|
|
168
|
+
headers,
|
|
169
|
+
withCredentials = 'same-origin',
|
|
170
|
+
fetchOptions,
|
|
171
|
+
maxContentLength,
|
|
172
|
+
maxBodyLength,
|
|
173
|
+
} = resolveConfig(config);
|
|
174
|
+
|
|
175
|
+
const hasMaxContentLength = utils.isNumber(maxContentLength) && maxContentLength > -1;
|
|
176
|
+
const hasMaxBodyLength = utils.isNumber(maxBodyLength) && maxBodyLength > -1;
|
|
177
|
+
|
|
178
|
+
let _fetch = envFetch || fetch;
|
|
179
|
+
|
|
180
|
+
responseType = responseType ? (responseType + '').toLowerCase() : 'text';
|
|
181
|
+
|
|
182
|
+
let composedSignal = composeSignals(
|
|
183
|
+
[signal, cancelToken && cancelToken.toAbortSignal()],
|
|
184
|
+
timeout
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
let request = null;
|
|
188
|
+
|
|
189
|
+
const unsubscribe =
|
|
190
|
+
composedSignal &&
|
|
191
|
+
composedSignal.unsubscribe &&
|
|
192
|
+
(() => {
|
|
193
|
+
composedSignal.unsubscribe();
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
let requestContentLength;
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
// Enforce maxContentLength for data: URLs up-front so we never materialize
|
|
200
|
+
// an oversized payload. The HTTP adapter applies the same check (see http.js
|
|
201
|
+
// "if (protocol === 'data:')" branch).
|
|
202
|
+
if (hasMaxContentLength && typeof url === 'string' && url.startsWith('data:')) {
|
|
203
|
+
const estimated = estimateDataURLDecodedBytes(url);
|
|
204
|
+
if (estimated > maxContentLength) {
|
|
205
|
+
throw new AxiosError(
|
|
206
|
+
'maxContentLength size of ' + maxContentLength + ' exceeded',
|
|
207
|
+
AxiosError.ERR_BAD_RESPONSE,
|
|
208
|
+
config,
|
|
209
|
+
request
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Enforce maxBodyLength against the outbound request body before dispatch.
|
|
215
|
+
// Mirrors http.js behavior (ERR_BAD_REQUEST / 'Request body larger than
|
|
216
|
+
// maxBodyLength limit'). Skip when the body length cannot be determined
|
|
217
|
+
// (e.g. a live ReadableStream supplied by the caller).
|
|
218
|
+
if (hasMaxBodyLength && method !== 'get' && method !== 'head') {
|
|
219
|
+
const outboundLength = await resolveBodyLength(headers, data);
|
|
220
|
+
if (
|
|
221
|
+
typeof outboundLength === 'number' &&
|
|
222
|
+
isFinite(outboundLength) &&
|
|
223
|
+
outboundLength > maxBodyLength
|
|
224
|
+
) {
|
|
225
|
+
throw new AxiosError(
|
|
226
|
+
'Request body larger than maxBodyLength limit',
|
|
227
|
+
AxiosError.ERR_BAD_REQUEST,
|
|
228
|
+
config,
|
|
229
|
+
request
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (
|
|
235
|
+
onUploadProgress &&
|
|
236
|
+
supportsRequestStream &&
|
|
237
|
+
method !== 'get' &&
|
|
238
|
+
method !== 'head' &&
|
|
239
|
+
(requestContentLength = await resolveBodyLength(headers, data)) !== 0
|
|
240
|
+
) {
|
|
241
|
+
let _request = new Request(url, {
|
|
242
|
+
method: 'POST',
|
|
243
|
+
body: data,
|
|
244
|
+
duplex: 'half',
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
let contentTypeHeader;
|
|
248
|
+
|
|
249
|
+
if (utils.isFormData(data) && (contentTypeHeader = _request.headers.get('content-type'))) {
|
|
250
|
+
headers.setContentType(contentTypeHeader);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (_request.body) {
|
|
254
|
+
const [onProgress, flush] = progressEventDecorator(
|
|
255
|
+
requestContentLength,
|
|
256
|
+
progressEventReducer(asyncDecorator(onUploadProgress))
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
data = trackStream(_request.body, DEFAULT_CHUNK_SIZE, onProgress, flush);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (!utils.isString(withCredentials)) {
|
|
264
|
+
withCredentials = withCredentials ? 'include' : 'omit';
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Cloudflare Workers throws when credentials are defined
|
|
268
|
+
// see https://github.com/cloudflare/workerd/issues/902
|
|
269
|
+
const isCredentialsSupported = isRequestSupported && 'credentials' in Request.prototype;
|
|
270
|
+
|
|
271
|
+
// If data is FormData and Content-Type is multipart/form-data without boundary,
|
|
272
|
+
// delete it so fetch can set it correctly with the boundary
|
|
273
|
+
if (utils.isFormData(data)) {
|
|
274
|
+
const contentType = headers.getContentType();
|
|
275
|
+
if (
|
|
276
|
+
contentType &&
|
|
277
|
+
/^multipart\/form-data/i.test(contentType) &&
|
|
278
|
+
!/boundary=/i.test(contentType)
|
|
279
|
+
) {
|
|
280
|
+
headers.delete('content-type');
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Set User-Agent header if not already set (fetch defaults to 'node' in Node.js)
|
|
285
|
+
headers.set('User-Agent', 'axios/' + VERSION, false);
|
|
286
|
+
|
|
287
|
+
const resolvedOptions = {
|
|
288
|
+
...fetchOptions,
|
|
289
|
+
signal: composedSignal,
|
|
290
|
+
method: method.toUpperCase(),
|
|
291
|
+
headers: toByteStringHeaderObject(headers.normalize()),
|
|
292
|
+
body: data,
|
|
293
|
+
duplex: 'half',
|
|
294
|
+
credentials: isCredentialsSupported ? withCredentials : undefined,
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
request = isRequestSupported && new Request(url, resolvedOptions);
|
|
298
|
+
|
|
299
|
+
let response = await (isRequestSupported
|
|
300
|
+
? _fetch(request, fetchOptions)
|
|
301
|
+
: _fetch(url, resolvedOptions));
|
|
302
|
+
|
|
303
|
+
// Cheap pre-check: if the server honestly declares a content-length that
|
|
304
|
+
// already exceeds the cap, reject before we start streaming.
|
|
305
|
+
if (hasMaxContentLength) {
|
|
306
|
+
const declaredLength = utils.toFiniteNumber(response.headers.get('content-length'));
|
|
307
|
+
if (declaredLength != null && declaredLength > maxContentLength) {
|
|
308
|
+
throw new AxiosError(
|
|
309
|
+
'maxContentLength size of ' + maxContentLength + ' exceeded',
|
|
310
|
+
AxiosError.ERR_BAD_RESPONSE,
|
|
311
|
+
config,
|
|
312
|
+
request
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const isStreamResponse =
|
|
318
|
+
supportsResponseStream && (responseType === 'stream' || responseType === 'response');
|
|
319
|
+
|
|
320
|
+
if (
|
|
321
|
+
supportsResponseStream &&
|
|
322
|
+
response.body &&
|
|
323
|
+
(onDownloadProgress || hasMaxContentLength || (isStreamResponse && unsubscribe))
|
|
324
|
+
) {
|
|
325
|
+
const options = {};
|
|
326
|
+
|
|
327
|
+
['status', 'statusText', 'headers'].forEach((prop) => {
|
|
328
|
+
options[prop] = response[prop];
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
const responseContentLength = utils.toFiniteNumber(response.headers.get('content-length'));
|
|
332
|
+
|
|
333
|
+
const [onProgress, flush] =
|
|
334
|
+
(onDownloadProgress &&
|
|
335
|
+
progressEventDecorator(
|
|
336
|
+
responseContentLength,
|
|
337
|
+
progressEventReducer(asyncDecorator(onDownloadProgress), true)
|
|
338
|
+
)) ||
|
|
339
|
+
[];
|
|
340
|
+
|
|
341
|
+
let bytesRead = 0;
|
|
342
|
+
const onChunkProgress = (loadedBytes) => {
|
|
343
|
+
if (hasMaxContentLength) {
|
|
344
|
+
bytesRead = loadedBytes;
|
|
345
|
+
if (bytesRead > maxContentLength) {
|
|
346
|
+
throw new AxiosError(
|
|
347
|
+
'maxContentLength size of ' + maxContentLength + ' exceeded',
|
|
348
|
+
AxiosError.ERR_BAD_RESPONSE,
|
|
349
|
+
config,
|
|
350
|
+
request
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
onProgress && onProgress(loadedBytes);
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
response = new Response(
|
|
358
|
+
trackStream(response.body, DEFAULT_CHUNK_SIZE, onChunkProgress, () => {
|
|
359
|
+
flush && flush();
|
|
360
|
+
unsubscribe && unsubscribe();
|
|
361
|
+
}),
|
|
362
|
+
options
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
responseType = responseType || 'text';
|
|
367
|
+
|
|
368
|
+
let responseData = await resolvers[utils.findKey(resolvers, responseType) || 'text'](
|
|
369
|
+
response,
|
|
370
|
+
config
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
// Fallback enforcement for environments without ReadableStream support
|
|
374
|
+
// (legacy runtimes). Detect materialized size from typed output; skip
|
|
375
|
+
// streams/Response passthrough since the user will read those themselves.
|
|
376
|
+
if (hasMaxContentLength && !supportsResponseStream && !isStreamResponse) {
|
|
377
|
+
let materializedSize;
|
|
378
|
+
if (responseData != null) {
|
|
379
|
+
if (typeof responseData.byteLength === 'number') {
|
|
380
|
+
materializedSize = responseData.byteLength;
|
|
381
|
+
} else if (typeof responseData.size === 'number') {
|
|
382
|
+
materializedSize = responseData.size;
|
|
383
|
+
} else if (typeof responseData === 'string') {
|
|
384
|
+
materializedSize =
|
|
385
|
+
typeof TextEncoder === 'function'
|
|
386
|
+
? new TextEncoder().encode(responseData).byteLength
|
|
387
|
+
: responseData.length;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
if (typeof materializedSize === 'number' && materializedSize > maxContentLength) {
|
|
391
|
+
throw new AxiosError(
|
|
392
|
+
'maxContentLength size of ' + maxContentLength + ' exceeded',
|
|
393
|
+
AxiosError.ERR_BAD_RESPONSE,
|
|
394
|
+
config,
|
|
395
|
+
request
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
!isStreamResponse && unsubscribe && unsubscribe();
|
|
401
|
+
|
|
402
|
+
return await new Promise((resolve, reject) => {
|
|
403
|
+
settle(resolve, reject, {
|
|
404
|
+
data: responseData,
|
|
405
|
+
headers: AxiosHeaders.from(response.headers),
|
|
406
|
+
status: response.status,
|
|
407
|
+
statusText: response.statusText,
|
|
408
|
+
config,
|
|
409
|
+
request,
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
} catch (err) {
|
|
413
|
+
unsubscribe && unsubscribe();
|
|
414
|
+
|
|
415
|
+
// Safari can surface fetch aborts as a DOMException-like object whose
|
|
416
|
+
// branded getters throw. Prefer our composed signal reason before reading
|
|
417
|
+
// the caught error, preserving timeout vs cancellation semantics.
|
|
418
|
+
if (composedSignal && composedSignal.aborted && composedSignal.reason instanceof AxiosError) {
|
|
419
|
+
const canceledError = composedSignal.reason;
|
|
420
|
+
canceledError.config = config;
|
|
421
|
+
request && (canceledError.request = request);
|
|
422
|
+
err !== canceledError && (canceledError.cause = err);
|
|
423
|
+
throw canceledError;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
if (err && err.name === 'TypeError' && /Load failed|fetch/i.test(err.message)) {
|
|
427
|
+
throw Object.assign(
|
|
428
|
+
new AxiosError(
|
|
429
|
+
'Network Error',
|
|
430
|
+
AxiosError.ERR_NETWORK,
|
|
431
|
+
config,
|
|
432
|
+
request,
|
|
433
|
+
err && err.response
|
|
434
|
+
),
|
|
435
|
+
{
|
|
436
|
+
cause: err.cause || err,
|
|
437
|
+
}
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
throw AxiosError.from(err, err && err.code, config, request, err && err.response);
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
const seedCache = new Map();
|
|
447
|
+
|
|
448
|
+
export const getFetch = (config) => {
|
|
449
|
+
let env = (config && config.env) || {};
|
|
450
|
+
const { fetch, Request, Response } = env;
|
|
451
|
+
const seeds = [Request, Response, fetch];
|
|
452
|
+
|
|
453
|
+
let len = seeds.length,
|
|
454
|
+
i = len,
|
|
455
|
+
seed,
|
|
456
|
+
target,
|
|
457
|
+
map = seedCache;
|
|
458
|
+
|
|
459
|
+
while (i--) {
|
|
460
|
+
seed = seeds[i];
|
|
461
|
+
target = map.get(seed);
|
|
462
|
+
|
|
463
|
+
target === undefined && map.set(seed, (target = i ? new Map() : factory(env)));
|
|
464
|
+
|
|
465
|
+
map = target;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
return target;
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
const adapter = getFetch();
|
|
472
|
+
|
|
473
|
+
export default adapter;
|