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