axios 0.27.2 → 1.0.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.
Potentially problematic release.
This version of axios might be problematic. Click here for more details.
- package/CHANGELOG.md +178 -940
- package/LICENSE +4 -16
- package/README.md +292 -93
- package/SECURITY.md +4 -3
- package/UPGRADE_GUIDE.md +1 -166
- package/bin/ssl_hotfix.js +22 -0
- package/dist/axios.js +2537 -2211
- package/dist/axios.js.map +1 -0
- package/dist/axios.min.js +2 -3
- package/dist/axios.min.js.map +1 -0
- package/dist/esm/axios.js +2942 -0
- package/dist/esm/axios.js.map +1 -0
- package/dist/esm/axios.min.js +2 -0
- package/dist/esm/axios.min.js.map +1 -0
- package/dist/node/axios.cjs +3750 -0
- package/dist/node/axios.cjs.map +1 -0
- package/gulpfile.js +88 -0
- package/index.d.ts +293 -70
- package/index.js +2 -1
- package/karma.conf.cjs +250 -0
- package/lib/adapters/http.js +371 -212
- package/lib/adapters/index.js +33 -0
- package/lib/adapters/xhr.js +81 -57
- package/lib/axios.js +34 -22
- package/lib/cancel/CancelToken.js +91 -89
- package/lib/cancel/CanceledError.js +9 -6
- package/lib/cancel/isCancel.js +2 -2
- package/lib/core/Axios.js +127 -99
- package/lib/core/AxiosError.js +22 -8
- package/lib/core/AxiosHeaders.js +274 -0
- package/lib/core/InterceptorManager.js +62 -45
- package/lib/core/buildFullPath.js +5 -4
- package/lib/core/dispatchRequest.js +21 -32
- package/lib/core/mergeConfig.js +8 -7
- package/lib/core/settle.js +6 -4
- package/lib/core/transformData.js +15 -9
- package/lib/defaults/index.js +77 -38
- package/lib/defaults/transitional.js +1 -1
- package/lib/env/classes/FormData.js +2 -0
- package/lib/env/data.js +1 -3
- package/lib/helpers/AxiosTransformStream.js +191 -0
- package/lib/helpers/AxiosURLSearchParams.js +58 -0
- package/lib/helpers/bind.js +3 -7
- package/lib/helpers/buildURL.js +24 -38
- package/lib/helpers/combineURLs.js +3 -2
- package/lib/helpers/cookies.js +43 -44
- package/lib/helpers/deprecatedMethod.js +4 -2
- package/lib/helpers/formDataToJSON.js +92 -0
- package/lib/helpers/fromDataURI.js +53 -0
- package/lib/helpers/isAbsoluteURL.js +3 -2
- package/lib/helpers/isAxiosError.js +4 -3
- package/lib/helpers/isURLSameOrigin.js +44 -45
- package/lib/helpers/null.js +1 -1
- package/lib/helpers/parseHeaders.js +24 -22
- package/lib/helpers/parseProtocol.js +3 -3
- package/lib/helpers/speedometer.js +55 -0
- package/lib/helpers/spread.js +3 -2
- package/lib/helpers/throttle.js +33 -0
- package/lib/helpers/toFormData.js +193 -36
- package/lib/helpers/toURLEncodedForm.js +18 -0
- package/lib/helpers/validator.js +20 -15
- package/lib/platform/browser/classes/FormData.js +3 -0
- package/lib/platform/browser/classes/URLSearchParams.js +4 -0
- package/lib/platform/browser/index.js +43 -0
- package/lib/platform/index.js +3 -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 +12 -0
- package/lib/utils.js +320 -177
- package/package.json +69 -23
- package/rollup.config.js +90 -0
- package/dist/axios.map +0 -1
- package/dist/axios.min.map +0 -1
- package/lib/defaults/env/FormData.js +0 -2
- package/lib/helpers/normalizeHeaderName.js +0 -12
package/lib/adapters/http.js
CHANGED
@@ -1,96 +1,237 @@
|
|
1
1
|
'use strict';
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
3
|
+
import utils from './../utils.js';
|
4
|
+
import settle from './../core/settle.js';
|
5
|
+
import buildFullPath from '../core/buildFullPath.js';
|
6
|
+
import buildURL from './../helpers/buildURL.js';
|
7
|
+
import {getProxyForUrl} from 'proxy-from-env';
|
8
|
+
import http from 'http';
|
9
|
+
import https from 'https';
|
10
|
+
import followRedirects from 'follow-redirects';
|
11
|
+
import zlib from 'zlib';
|
12
|
+
import {VERSION} from '../env/data.js';
|
13
|
+
import transitionalDefaults from '../defaults/transitional.js';
|
14
|
+
import AxiosError from '../core/AxiosError.js';
|
15
|
+
import CanceledError from '../cancel/CanceledError.js';
|
16
|
+
import platform from '../platform/index.js';
|
17
|
+
import fromDataURI from '../helpers/fromDataURI.js';
|
18
|
+
import stream from 'stream';
|
19
|
+
import AxiosHeaders from '../core/AxiosHeaders.js';
|
20
|
+
import AxiosTransformStream from '../helpers/AxiosTransformStream.js';
|
21
|
+
import EventEmitter from 'events';
|
22
|
+
|
23
|
+
const isBrotliSupported = utils.isFunction(zlib.createBrotliDecompress);
|
24
|
+
|
25
|
+
const {http: httpFollow, https: httpsFollow} = followRedirects;
|
26
|
+
|
27
|
+
const isHttps = /https:?/;
|
28
|
+
|
29
|
+
const supportedProtocols = platform.protocols.map(protocol => {
|
30
|
+
return protocol + ':';
|
31
|
+
});
|
21
32
|
|
22
33
|
/**
|
34
|
+
* If the proxy or config beforeRedirects functions are defined, call them with the options
|
35
|
+
* object.
|
36
|
+
*
|
37
|
+
* @param {Object<string, any>} options - The options object that was passed to the request.
|
38
|
+
*
|
39
|
+
* @returns {Object<string, any>}
|
40
|
+
*/
|
41
|
+
function dispatchBeforeRedirect(options) {
|
42
|
+
if (options.beforeRedirects.proxy) {
|
43
|
+
options.beforeRedirects.proxy(options);
|
44
|
+
}
|
45
|
+
if (options.beforeRedirects.config) {
|
46
|
+
options.beforeRedirects.config(options);
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
/**
|
51
|
+
* If the proxy or config afterRedirects functions are defined, call them with the options
|
23
52
|
*
|
24
53
|
* @param {http.ClientRequestArgs} options
|
25
|
-
* @param {AxiosProxyConfig}
|
54
|
+
* @param {AxiosProxyConfig} configProxy
|
26
55
|
* @param {string} location
|
56
|
+
*
|
57
|
+
* @returns {http.ClientRequestArgs}
|
27
58
|
*/
|
28
|
-
function setProxy(options,
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
if (proxy.auth) {
|
36
|
-
var base64 = Buffer.from(proxy.auth.username + ':' + proxy.auth.password, 'utf8').toString('base64');
|
37
|
-
options.headers['Proxy-Authorization'] = 'Basic ' + base64;
|
59
|
+
function setProxy(options, configProxy, location) {
|
60
|
+
let proxy = configProxy;
|
61
|
+
if (!proxy && proxy !== false) {
|
62
|
+
const proxyUrl = getProxyForUrl(location);
|
63
|
+
if (proxyUrl) {
|
64
|
+
proxy = new URL(proxyUrl);
|
65
|
+
}
|
38
66
|
}
|
67
|
+
if (proxy) {
|
68
|
+
// Basic proxy authorization
|
69
|
+
if (proxy.username) {
|
70
|
+
proxy.auth = (proxy.username || '') + ':' + (proxy.password || '');
|
71
|
+
}
|
72
|
+
|
73
|
+
if (proxy.auth) {
|
74
|
+
// Support proxy auth object form
|
75
|
+
if (proxy.auth.username || proxy.auth.password) {
|
76
|
+
proxy.auth = (proxy.auth.username || '') + ':' + (proxy.auth.password || '');
|
77
|
+
}
|
78
|
+
const base64 = Buffer
|
79
|
+
.from(proxy.auth, 'utf8')
|
80
|
+
.toString('base64');
|
81
|
+
options.headers['Proxy-Authorization'] = 'Basic ' + base64;
|
82
|
+
}
|
39
83
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
84
|
+
options.headers.host = options.hostname + (options.port ? ':' + options.port : '');
|
85
|
+
options.hostname = proxy.hostname;
|
86
|
+
// Replace 'host' since options is not a URL object
|
87
|
+
options.host = proxy.hostname;
|
88
|
+
options.port = proxy.port;
|
89
|
+
options.path = location;
|
90
|
+
if (proxy.protocol) {
|
91
|
+
options.protocol = proxy.protocol;
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
options.beforeRedirects.proxy = function beforeRedirect(redirectOptions) {
|
96
|
+
// Configure proxy for redirected request, passing the original config proxy to apply
|
97
|
+
// the exact same logic as if the redirected request was performed by axios directly.
|
98
|
+
setProxy(redirectOptions, configProxy, redirectOptions.href);
|
44
99
|
};
|
45
100
|
}
|
46
101
|
|
47
102
|
/*eslint consistent-return:0*/
|
48
|
-
|
103
|
+
export default function httpAdapter(config) {
|
49
104
|
return new Promise(function dispatchHttpRequest(resolvePromise, rejectPromise) {
|
50
|
-
|
51
|
-
|
105
|
+
let data = config.data;
|
106
|
+
const responseType = config.responseType;
|
107
|
+
const responseEncoding = config.responseEncoding;
|
108
|
+
const method = config.method.toUpperCase();
|
109
|
+
let isFinished;
|
110
|
+
let isDone;
|
111
|
+
let rejected = false;
|
112
|
+
let req;
|
113
|
+
|
114
|
+
// temporary internal emitter until the AxiosRequest class will be implemented
|
115
|
+
const emitter = new EventEmitter();
|
116
|
+
|
117
|
+
function onFinished() {
|
118
|
+
if (isFinished) return;
|
119
|
+
isFinished = true;
|
120
|
+
|
52
121
|
if (config.cancelToken) {
|
53
|
-
config.cancelToken.unsubscribe(
|
122
|
+
config.cancelToken.unsubscribe(abort);
|
54
123
|
}
|
55
124
|
|
56
125
|
if (config.signal) {
|
57
|
-
config.signal.removeEventListener('abort',
|
126
|
+
config.signal.removeEventListener('abort', abort);
|
58
127
|
}
|
128
|
+
|
129
|
+
emitter.removeAllListeners();
|
59
130
|
}
|
60
|
-
|
61
|
-
|
62
|
-
|
131
|
+
|
132
|
+
function done(value, isRejected) {
|
133
|
+
if (isDone) return;
|
134
|
+
|
135
|
+
isDone = true;
|
136
|
+
|
137
|
+
if (isRejected) {
|
138
|
+
rejected = true;
|
139
|
+
onFinished();
|
140
|
+
}
|
141
|
+
|
142
|
+
isRejected ? rejectPromise(value) : resolvePromise(value);
|
143
|
+
}
|
144
|
+
|
145
|
+
const resolve = function resolve(value) {
|
146
|
+
done(value);
|
63
147
|
};
|
64
|
-
|
65
|
-
|
66
|
-
done();
|
67
|
-
rejected = true;
|
68
|
-
rejectPromise(value);
|
148
|
+
|
149
|
+
const reject = function reject(value) {
|
150
|
+
done(value, true);
|
69
151
|
};
|
70
|
-
var data = config.data;
|
71
|
-
var headers = config.headers;
|
72
|
-
var headerNames = {};
|
73
152
|
|
74
|
-
|
75
|
-
|
76
|
-
}
|
153
|
+
function abort(reason) {
|
154
|
+
emitter.emit('abort', !reason || reason.type ? new CanceledError(null, config, req) : reason);
|
155
|
+
}
|
77
156
|
|
78
|
-
|
79
|
-
|
80
|
-
if (
|
81
|
-
|
82
|
-
if (
|
83
|
-
|
157
|
+
emitter.once('abort', reject);
|
158
|
+
|
159
|
+
if (config.cancelToken || config.signal) {
|
160
|
+
config.cancelToken && config.cancelToken.subscribe(abort);
|
161
|
+
if (config.signal) {
|
162
|
+
config.signal.aborted ? abort() : config.signal.addEventListener('abort', abort);
|
84
163
|
}
|
85
|
-
// Otherwise, use specified value
|
86
|
-
} else {
|
87
|
-
// Only set header if it hasn't been set in config
|
88
|
-
headers['User-Agent'] = 'axios/' + VERSION;
|
89
164
|
}
|
90
165
|
|
166
|
+
// Parse url
|
167
|
+
const fullPath = buildFullPath(config.baseURL, config.url);
|
168
|
+
const parsed = new URL(fullPath);
|
169
|
+
const protocol = parsed.protocol || supportedProtocols[0];
|
170
|
+
|
171
|
+
if (protocol === 'data:') {
|
172
|
+
let convertedData;
|
173
|
+
|
174
|
+
if (method !== 'GET') {
|
175
|
+
return settle(resolve, reject, {
|
176
|
+
status: 405,
|
177
|
+
statusText: 'method not allowed',
|
178
|
+
headers: {},
|
179
|
+
config
|
180
|
+
});
|
181
|
+
}
|
182
|
+
|
183
|
+
try {
|
184
|
+
convertedData = fromDataURI(config.url, responseType === 'blob', {
|
185
|
+
Blob: config.env && config.env.Blob
|
186
|
+
});
|
187
|
+
} catch (err) {
|
188
|
+
throw AxiosError.from(err, AxiosError.ERR_BAD_REQUEST, config);
|
189
|
+
}
|
190
|
+
|
191
|
+
if (responseType === 'text') {
|
192
|
+
convertedData = convertedData.toString(responseEncoding);
|
193
|
+
|
194
|
+
if (!responseEncoding || responseEncoding === 'utf8') {
|
195
|
+
data = utils.stripBOM(convertedData);
|
196
|
+
}
|
197
|
+
} else if (responseType === 'stream') {
|
198
|
+
convertedData = stream.Readable.from(convertedData);
|
199
|
+
}
|
200
|
+
|
201
|
+
return settle(resolve, reject, {
|
202
|
+
data: convertedData,
|
203
|
+
status: 200,
|
204
|
+
statusText: 'OK',
|
205
|
+
headers: {},
|
206
|
+
config
|
207
|
+
});
|
208
|
+
}
|
209
|
+
|
210
|
+
if (supportedProtocols.indexOf(protocol) === -1) {
|
211
|
+
return reject(new AxiosError(
|
212
|
+
'Unsupported protocol ' + protocol,
|
213
|
+
AxiosError.ERR_BAD_REQUEST,
|
214
|
+
config
|
215
|
+
));
|
216
|
+
}
|
217
|
+
|
218
|
+
const headers = AxiosHeaders.from(config.headers).normalize();
|
219
|
+
|
220
|
+
// Set User-Agent (required by some servers)
|
221
|
+
// See https://github.com/axios/axios/issues/69
|
222
|
+
// User-Agent is specified; handle case where no UA header is desired
|
223
|
+
// Only set header if it hasn't been set in config
|
224
|
+
headers.set('User-Agent', 'axios/' + VERSION, false);
|
225
|
+
|
226
|
+
const onDownloadProgress = config.onDownloadProgress;
|
227
|
+
const onUploadProgress = config.onUploadProgress;
|
228
|
+
const maxRate = config.maxRate;
|
229
|
+
let maxUploadRate = undefined;
|
230
|
+
let maxDownloadRate = undefined;
|
231
|
+
|
91
232
|
// support for https://www.npmjs.com/package/form-data api
|
92
233
|
if (utils.isFormData(data) && utils.isFunction(data.getHeaders)) {
|
93
|
-
|
234
|
+
headers.set(data.getHeaders());
|
94
235
|
} else if (data && !utils.isStream(data)) {
|
95
236
|
if (Buffer.isBuffer(data)) {
|
96
237
|
// Nothing to do...
|
@@ -106,6 +247,9 @@ module.exports = function httpAdapter(config) {
|
|
106
247
|
));
|
107
248
|
}
|
108
249
|
|
250
|
+
// Add Content-Length header if data exists
|
251
|
+
headers.set('Content-Length', data.length, false);
|
252
|
+
|
109
253
|
if (config.maxBodyLength > -1 && data.length > config.maxBodyLength) {
|
110
254
|
return reject(new AxiosError(
|
111
255
|
'Request body larger than maxBodyLength limit',
|
@@ -113,65 +257,72 @@ module.exports = function httpAdapter(config) {
|
|
113
257
|
config
|
114
258
|
));
|
115
259
|
}
|
260
|
+
}
|
116
261
|
|
117
|
-
|
118
|
-
|
119
|
-
|
262
|
+
const contentLength = +headers.getContentLength();
|
263
|
+
|
264
|
+
if (utils.isArray(maxRate)) {
|
265
|
+
maxUploadRate = maxRate[0];
|
266
|
+
maxDownloadRate = maxRate[1];
|
267
|
+
} else {
|
268
|
+
maxUploadRate = maxDownloadRate = maxRate;
|
269
|
+
}
|
270
|
+
|
271
|
+
if (data && (onUploadProgress || maxUploadRate)) {
|
272
|
+
if (!utils.isStream(data)) {
|
273
|
+
data = stream.Readable.from(data, {objectMode: false});
|
120
274
|
}
|
275
|
+
|
276
|
+
data = stream.pipeline([data, new AxiosTransformStream({
|
277
|
+
length: utils.toFiniteNumber(contentLength),
|
278
|
+
maxRate: utils.toFiniteNumber(maxUploadRate)
|
279
|
+
})], utils.noop);
|
280
|
+
|
281
|
+
onUploadProgress && data.on('progress', progress => {
|
282
|
+
onUploadProgress(Object.assign(progress, {
|
283
|
+
upload: true
|
284
|
+
}));
|
285
|
+
});
|
121
286
|
}
|
122
287
|
|
123
288
|
// HTTP basic authentication
|
124
|
-
|
289
|
+
let auth = undefined;
|
125
290
|
if (config.auth) {
|
126
|
-
|
127
|
-
|
291
|
+
const username = config.auth.username || '';
|
292
|
+
const password = config.auth.password || '';
|
128
293
|
auth = username + ':' + password;
|
129
294
|
}
|
130
295
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
var protocol = parsed.protocol || supportedProtocols[0];
|
135
|
-
|
136
|
-
if (supportedProtocols.indexOf(protocol) === -1) {
|
137
|
-
return reject(new AxiosError(
|
138
|
-
'Unsupported protocol ' + protocol,
|
139
|
-
AxiosError.ERR_BAD_REQUEST,
|
140
|
-
config
|
141
|
-
));
|
142
|
-
}
|
143
|
-
|
144
|
-
if (!auth && parsed.auth) {
|
145
|
-
var urlAuth = parsed.auth.split(':');
|
146
|
-
var urlUsername = urlAuth[0] || '';
|
147
|
-
var urlPassword = urlAuth[1] || '';
|
296
|
+
if (!auth && parsed.username) {
|
297
|
+
const urlUsername = parsed.username;
|
298
|
+
const urlPassword = parsed.password;
|
148
299
|
auth = urlUsername + ':' + urlPassword;
|
149
300
|
}
|
150
301
|
|
151
|
-
|
152
|
-
delete headers[headerNames.authorization];
|
153
|
-
}
|
154
|
-
|
155
|
-
var isHttpsRequest = isHttps.test(protocol);
|
156
|
-
var agent = isHttpsRequest ? config.httpsAgent : config.httpAgent;
|
302
|
+
auth && headers.delete('authorization');
|
157
303
|
|
304
|
+
const path = parsed.pathname.concat(parsed.searchParams);
|
158
305
|
try {
|
159
|
-
buildURL(
|
306
|
+
buildURL(path, config.params, config.paramsSerializer).replace(/^\?/, '');
|
160
307
|
} catch (err) {
|
161
|
-
|
308
|
+
const customErr = new Error(err.message);
|
162
309
|
customErr.config = config;
|
163
310
|
customErr.url = config.url;
|
164
311
|
customErr.exists = true;
|
165
|
-
reject(customErr);
|
312
|
+
return reject(customErr);
|
166
313
|
}
|
167
314
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
315
|
+
headers.set('Accept-Encoding', 'gzip, deflate, br', false);
|
316
|
+
|
317
|
+
const options = {
|
318
|
+
path: buildURL(path, config.params, config.paramsSerializer).replace(/^\?/, ''),
|
319
|
+
method: method,
|
320
|
+
headers: headers.toJSON(),
|
173
321
|
agents: { http: config.httpAgent, https: config.httpsAgent },
|
174
|
-
auth
|
322
|
+
auth,
|
323
|
+
protocol,
|
324
|
+
beforeRedirect: dispatchBeforeRedirect,
|
325
|
+
beforeRedirects: {}
|
175
326
|
};
|
176
327
|
|
177
328
|
if (config.socketPath) {
|
@@ -179,79 +330,31 @@ module.exports = function httpAdapter(config) {
|
|
179
330
|
} else {
|
180
331
|
options.hostname = parsed.hostname;
|
181
332
|
options.port = parsed.port;
|
333
|
+
setProxy(options, config.proxy, protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path);
|
182
334
|
}
|
183
335
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
var proxyUrl = process.env[proxyEnv] || process.env[proxyEnv.toUpperCase()];
|
188
|
-
if (proxyUrl) {
|
189
|
-
var parsedProxyUrl = url.parse(proxyUrl);
|
190
|
-
var noProxyEnv = process.env.no_proxy || process.env.NO_PROXY;
|
191
|
-
var shouldProxy = true;
|
192
|
-
|
193
|
-
if (noProxyEnv) {
|
194
|
-
var noProxy = noProxyEnv.split(',').map(function trim(s) {
|
195
|
-
return s.trim();
|
196
|
-
});
|
197
|
-
|
198
|
-
shouldProxy = !noProxy.some(function proxyMatch(proxyElement) {
|
199
|
-
if (!proxyElement) {
|
200
|
-
return false;
|
201
|
-
}
|
202
|
-
if (proxyElement === '*') {
|
203
|
-
return true;
|
204
|
-
}
|
205
|
-
if (proxyElement[0] === '.' &&
|
206
|
-
parsed.hostname.substr(parsed.hostname.length - proxyElement.length) === proxyElement) {
|
207
|
-
return true;
|
208
|
-
}
|
209
|
-
|
210
|
-
return parsed.hostname === proxyElement;
|
211
|
-
});
|
212
|
-
}
|
213
|
-
|
214
|
-
if (shouldProxy) {
|
215
|
-
proxy = {
|
216
|
-
host: parsedProxyUrl.hostname,
|
217
|
-
port: parsedProxyUrl.port,
|
218
|
-
protocol: parsedProxyUrl.protocol
|
219
|
-
};
|
220
|
-
|
221
|
-
if (parsedProxyUrl.auth) {
|
222
|
-
var proxyUrlAuth = parsedProxyUrl.auth.split(':');
|
223
|
-
proxy.auth = {
|
224
|
-
username: proxyUrlAuth[0],
|
225
|
-
password: proxyUrlAuth[1]
|
226
|
-
};
|
227
|
-
}
|
228
|
-
}
|
229
|
-
}
|
230
|
-
}
|
231
|
-
|
232
|
-
if (proxy) {
|
233
|
-
options.headers.host = parsed.hostname + (parsed.port ? ':' + parsed.port : '');
|
234
|
-
setProxy(options, proxy, protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path);
|
235
|
-
}
|
236
|
-
|
237
|
-
var transport;
|
238
|
-
var isHttpsProxy = isHttpsRequest && (proxy ? isHttps.test(proxy.protocol) : true);
|
336
|
+
let transport;
|
337
|
+
const isHttpsRequest = isHttps.test(options.protocol);
|
338
|
+
options.agent = isHttpsRequest ? config.httpsAgent : config.httpAgent;
|
239
339
|
if (config.transport) {
|
240
340
|
transport = config.transport;
|
241
341
|
} else if (config.maxRedirects === 0) {
|
242
|
-
transport =
|
342
|
+
transport = isHttpsRequest ? https : http;
|
243
343
|
} else {
|
244
344
|
if (config.maxRedirects) {
|
245
345
|
options.maxRedirects = config.maxRedirects;
|
246
346
|
}
|
247
347
|
if (config.beforeRedirect) {
|
248
|
-
options.
|
348
|
+
options.beforeRedirects.config = config.beforeRedirect;
|
249
349
|
}
|
250
|
-
transport =
|
350
|
+
transport = isHttpsRequest ? httpsFollow : httpFollow;
|
251
351
|
}
|
252
352
|
|
253
353
|
if (config.maxBodyLength > -1) {
|
254
354
|
options.maxBodyLength = config.maxBodyLength;
|
355
|
+
} else {
|
356
|
+
// follow-redirects does not skip comparison, so it should always succeed for axios -1 unlimited
|
357
|
+
options.maxBodyLength = Infinity;
|
255
358
|
}
|
256
359
|
|
257
360
|
if (config.insecureHTTPParser) {
|
@@ -259,84 +362,123 @@ module.exports = function httpAdapter(config) {
|
|
259
362
|
}
|
260
363
|
|
261
364
|
// Create the request
|
262
|
-
|
263
|
-
if (req.
|
365
|
+
req = transport.request(options, function handleResponse(res) {
|
366
|
+
if (req.destroyed) return;
|
367
|
+
|
368
|
+
const streams = [res];
|
264
369
|
|
265
370
|
// uncompress the response body transparently if required
|
266
|
-
|
371
|
+
let responseStream = res;
|
267
372
|
|
268
373
|
// return the last request in case of redirects
|
269
|
-
|
374
|
+
const lastRequest = res.req || req;
|
270
375
|
|
376
|
+
// if decompress disabled we should not decompress
|
377
|
+
if (config.decompress !== false) {
|
378
|
+
// if no content, but headers still say that it is encoded,
|
379
|
+
// remove the header not confuse downstream operations
|
380
|
+
if (data && data.length === 0 && res.headers['content-encoding']) {
|
381
|
+
delete res.headers['content-encoding'];
|
382
|
+
}
|
271
383
|
|
272
|
-
// if no content, is HEAD request or decompress disabled we should not decompress
|
273
|
-
if (res.statusCode !== 204 && lastRequest.method !== 'HEAD' && config.decompress !== false) {
|
274
384
|
switch (res.headers['content-encoding']) {
|
275
385
|
/*eslint default-case:0*/
|
276
386
|
case 'gzip':
|
277
387
|
case 'compress':
|
278
388
|
case 'deflate':
|
279
|
-
|
280
|
-
|
389
|
+
// add the unzipper to the body stream processing pipeline
|
390
|
+
streams.push(zlib.createUnzip());
|
281
391
|
|
282
392
|
// remove the content-encoding in order to not confuse downstream operations
|
283
393
|
delete res.headers['content-encoding'];
|
284
394
|
break;
|
395
|
+
case 'br':
|
396
|
+
if (isBrotliSupported) {
|
397
|
+
streams.push(zlib.createBrotliDecompress());
|
398
|
+
delete res.headers['content-encoding'];
|
399
|
+
}
|
285
400
|
}
|
286
401
|
}
|
287
402
|
|
288
|
-
|
403
|
+
if (onDownloadProgress) {
|
404
|
+
const responseLength = +res.headers['content-length'];
|
405
|
+
|
406
|
+
const transformStream = new AxiosTransformStream({
|
407
|
+
length: utils.toFiniteNumber(responseLength),
|
408
|
+
maxRate: utils.toFiniteNumber(maxDownloadRate)
|
409
|
+
});
|
410
|
+
|
411
|
+
onDownloadProgress && transformStream.on('progress', progress => {
|
412
|
+
onDownloadProgress(Object.assign(progress, {
|
413
|
+
download: true
|
414
|
+
}));
|
415
|
+
});
|
416
|
+
|
417
|
+
streams.push(transformStream);
|
418
|
+
}
|
419
|
+
|
420
|
+
responseStream = streams.length > 1 ? stream.pipeline(streams, utils.noop) : streams[0];
|
421
|
+
|
422
|
+
const offListeners = stream.finished(responseStream, () => {
|
423
|
+
offListeners();
|
424
|
+
onFinished();
|
425
|
+
});
|
426
|
+
|
427
|
+
const response = {
|
289
428
|
status: res.statusCode,
|
290
429
|
statusText: res.statusMessage,
|
291
|
-
headers: res.headers,
|
292
|
-
config
|
430
|
+
headers: new AxiosHeaders(res.headers),
|
431
|
+
config,
|
293
432
|
request: lastRequest
|
294
433
|
};
|
295
434
|
|
296
|
-
if (
|
297
|
-
response.data =
|
435
|
+
if (responseType === 'stream') {
|
436
|
+
response.data = responseStream;
|
298
437
|
settle(resolve, reject, response);
|
299
438
|
} else {
|
300
|
-
|
301
|
-
|
302
|
-
|
439
|
+
const responseBuffer = [];
|
440
|
+
let totalResponseBytes = 0;
|
441
|
+
|
442
|
+
responseStream.on('data', function handleStreamData(chunk) {
|
303
443
|
responseBuffer.push(chunk);
|
304
444
|
totalResponseBytes += chunk.length;
|
305
445
|
|
306
446
|
// make sure the content length is not over the maxContentLength if specified
|
307
447
|
if (config.maxContentLength > -1 && totalResponseBytes > config.maxContentLength) {
|
308
|
-
// stream.
|
448
|
+
// stream.destroy() emit aborted event before calling reject() on Node.js v16
|
309
449
|
rejected = true;
|
310
|
-
|
450
|
+
responseStream.destroy();
|
311
451
|
reject(new AxiosError('maxContentLength size of ' + config.maxContentLength + ' exceeded',
|
312
452
|
AxiosError.ERR_BAD_RESPONSE, config, lastRequest));
|
313
453
|
}
|
314
454
|
});
|
315
455
|
|
316
|
-
|
456
|
+
responseStream.on('aborted', function handlerStreamAborted() {
|
317
457
|
if (rejected) {
|
318
458
|
return;
|
319
459
|
}
|
320
|
-
|
321
|
-
|
460
|
+
|
461
|
+
const err = new AxiosError(
|
322
462
|
'maxContentLength size of ' + config.maxContentLength + ' exceeded',
|
323
463
|
AxiosError.ERR_BAD_RESPONSE,
|
324
464
|
config,
|
325
465
|
lastRequest
|
326
|
-
)
|
466
|
+
);
|
467
|
+
responseStream.destroy(err);
|
468
|
+
reject(err);
|
327
469
|
});
|
328
470
|
|
329
|
-
|
330
|
-
if (req.
|
471
|
+
responseStream.on('error', function handleStreamError(err) {
|
472
|
+
if (req.destroyed) return;
|
331
473
|
reject(AxiosError.from(err, null, config, lastRequest));
|
332
474
|
});
|
333
475
|
|
334
|
-
|
476
|
+
responseStream.on('end', function handleStreamEnd() {
|
335
477
|
try {
|
336
|
-
|
337
|
-
if (
|
338
|
-
responseData = responseData.toString(
|
339
|
-
if (!
|
478
|
+
let responseData = responseBuffer.length === 1 ? responseBuffer[0] : Buffer.concat(responseBuffer);
|
479
|
+
if (responseType !== 'arraybuffer') {
|
480
|
+
responseData = responseData.toString(responseEncoding);
|
481
|
+
if (!responseEncoding || responseEncoding === 'utf8') {
|
340
482
|
responseData = utils.stripBOM(responseData);
|
341
483
|
}
|
342
484
|
}
|
@@ -347,6 +489,18 @@ module.exports = function httpAdapter(config) {
|
|
347
489
|
settle(resolve, reject, response);
|
348
490
|
});
|
349
491
|
}
|
492
|
+
|
493
|
+
emitter.once('abort', err => {
|
494
|
+
if (!responseStream.destroyed) {
|
495
|
+
responseStream.emit('error', err);
|
496
|
+
responseStream.destroy();
|
497
|
+
}
|
498
|
+
});
|
499
|
+
});
|
500
|
+
|
501
|
+
emitter.once('abort', err => {
|
502
|
+
reject(err);
|
503
|
+
req.destroy(err);
|
350
504
|
});
|
351
505
|
|
352
506
|
// Handle errors
|
@@ -365,7 +519,7 @@ module.exports = function httpAdapter(config) {
|
|
365
519
|
// Handle request timeout
|
366
520
|
if (config.timeout) {
|
367
521
|
// This is forcing a int timeout to avoid problems if the `req` interface doesn't handle other types.
|
368
|
-
|
522
|
+
const timeout = parseInt(config.timeout, 10);
|
369
523
|
|
370
524
|
if (isNaN(timeout)) {
|
371
525
|
reject(new AxiosError(
|
@@ -381,44 +535,49 @@ module.exports = function httpAdapter(config) {
|
|
381
535
|
// Sometime, the response will be very slow, and does not respond, the connect event will be block by event loop system.
|
382
536
|
// And timer callback will be fired, and abort() will be invoked before connection, then get "socket hang up" and code ECONNRESET.
|
383
537
|
// At this time, if we have a large number of request, nodejs will hang up some socket on background. and the number will up and up.
|
384
|
-
// And then these socket which be hang up will
|
538
|
+
// And then these socket which be hang up will devouring CPU little by little.
|
385
539
|
// ClientRequest.setTimeout will be fired on the specify milliseconds, and can make sure that abort() will be fired after connect.
|
386
540
|
req.setTimeout(timeout, function handleRequestTimeout() {
|
387
|
-
|
388
|
-
|
541
|
+
if (isDone) return;
|
542
|
+
let timeoutErrorMessage = config.timeout ? 'timeout of ' + config.timeout + 'ms exceeded' : 'timeout exceeded';
|
543
|
+
const transitional = config.transitional || transitionalDefaults;
|
544
|
+
if (config.timeoutErrorMessage) {
|
545
|
+
timeoutErrorMessage = config.timeoutErrorMessage;
|
546
|
+
}
|
389
547
|
reject(new AxiosError(
|
390
|
-
|
548
|
+
timeoutErrorMessage,
|
391
549
|
transitional.clarifyTimeoutError ? AxiosError.ETIMEDOUT : AxiosError.ECONNABORTED,
|
392
550
|
config,
|
393
551
|
req
|
394
552
|
));
|
553
|
+
abort();
|
395
554
|
});
|
396
555
|
}
|
397
556
|
|
398
|
-
if (config.cancelToken || config.signal) {
|
399
|
-
// Handle cancellation
|
400
|
-
// eslint-disable-next-line func-names
|
401
|
-
onCanceled = function(cancel) {
|
402
|
-
if (req.aborted) return;
|
403
557
|
|
404
|
-
|
405
|
-
|
406
|
-
|
558
|
+
// Send the request
|
559
|
+
if (utils.isStream(data)) {
|
560
|
+
let ended = false;
|
561
|
+
let errored = false;
|
407
562
|
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
}
|
412
|
-
}
|
563
|
+
data.on('end', () => {
|
564
|
+
ended = true;
|
565
|
+
});
|
413
566
|
|
567
|
+
data.once('error', err => {
|
568
|
+
errored = true;
|
569
|
+
req.destroy(err);
|
570
|
+
});
|
414
571
|
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
})
|
572
|
+
data.on('close', () => {
|
573
|
+
if (!ended && !errored) {
|
574
|
+
abort(new CanceledError('Request stream has been aborted', config, req));
|
575
|
+
}
|
576
|
+
});
|
577
|
+
|
578
|
+
data.pipe(req);
|
420
579
|
} else {
|
421
580
|
req.end(data);
|
422
581
|
}
|
423
582
|
});
|
424
|
-
}
|
583
|
+
}
|