axios 1.0.0-alpha.1 → 1.1.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.

Files changed (70) hide show
  1. package/CHANGELOG.md +74 -1
  2. package/README.md +59 -48
  3. package/SECURITY.md +3 -2
  4. package/bin/ssl_hotfix.js +1 -1
  5. package/dist/axios.js +1564 -981
  6. package/dist/axios.js.map +1 -1
  7. package/dist/axios.min.js +1 -1
  8. package/dist/axios.min.js.map +1 -1
  9. package/dist/esm/axios.js +1472 -866
  10. package/dist/esm/axios.js.map +1 -1
  11. package/dist/esm/axios.min.js +1 -1
  12. package/dist/esm/axios.min.js.map +1 -1
  13. package/dist/node/axios.cjs +3761 -0
  14. package/dist/node/axios.cjs.map +1 -0
  15. package/gulpfile.js +88 -0
  16. package/index.d.ts +213 -67
  17. package/index.js +2 -1
  18. package/karma.conf.cjs +250 -0
  19. package/lib/adapters/http.js +256 -131
  20. package/lib/adapters/index.js +33 -0
  21. package/lib/adapters/xhr.js +79 -56
  22. package/lib/axios.js +41 -25
  23. package/lib/cancel/CancelToken.js +91 -88
  24. package/lib/cancel/CanceledError.js +5 -4
  25. package/lib/cancel/isCancel.js +2 -2
  26. package/lib/core/Axios.js +127 -100
  27. package/lib/core/AxiosError.js +10 -7
  28. package/lib/core/AxiosHeaders.js +274 -0
  29. package/lib/core/InterceptorManager.js +61 -53
  30. package/lib/core/buildFullPath.js +5 -4
  31. package/lib/core/dispatchRequest.js +21 -39
  32. package/lib/core/mergeConfig.js +8 -7
  33. package/lib/core/settle.js +6 -4
  34. package/lib/core/transformData.js +15 -10
  35. package/lib/defaults/index.js +46 -39
  36. package/lib/defaults/transitional.js +1 -1
  37. package/lib/env/classes/FormData.js +2 -2
  38. package/lib/env/data.js +1 -3
  39. package/lib/helpers/AxiosTransformStream.js +191 -0
  40. package/lib/helpers/AxiosURLSearchParams.js +23 -7
  41. package/lib/helpers/bind.js +2 -2
  42. package/lib/helpers/buildURL.js +16 -7
  43. package/lib/helpers/combineURLs.js +3 -2
  44. package/lib/helpers/cookies.js +43 -44
  45. package/lib/helpers/deprecatedMethod.js +4 -2
  46. package/lib/helpers/formDataToJSON.js +36 -15
  47. package/lib/helpers/fromDataURI.js +15 -13
  48. package/lib/helpers/isAbsoluteURL.js +3 -2
  49. package/lib/helpers/isAxiosError.js +4 -3
  50. package/lib/helpers/isURLSameOrigin.js +55 -56
  51. package/lib/helpers/null.js +1 -1
  52. package/lib/helpers/parseHeaders.js +24 -22
  53. package/lib/helpers/parseProtocol.js +3 -3
  54. package/lib/helpers/speedometer.js +55 -0
  55. package/lib/helpers/spread.js +3 -2
  56. package/lib/helpers/throttle.js +33 -0
  57. package/lib/helpers/toFormData.js +68 -18
  58. package/lib/helpers/toURLEncodedForm.js +5 -5
  59. package/lib/helpers/validator.js +20 -15
  60. package/lib/platform/browser/classes/FormData.js +1 -1
  61. package/lib/platform/browser/classes/URLSearchParams.js +2 -3
  62. package/lib/platform/browser/index.js +38 -6
  63. package/lib/platform/index.js +2 -2
  64. package/lib/platform/node/classes/FormData.js +2 -2
  65. package/lib/platform/node/classes/URLSearchParams.js +2 -3
  66. package/lib/platform/node/index.js +5 -4
  67. package/lib/utils.js +294 -192
  68. package/package.json +55 -22
  69. package/rollup.config.js +37 -7
  70. package/lib/helpers/normalizeHeaderName.js +0 -12
@@ -1,30 +1,43 @@
1
1
  'use strict';
2
2
 
3
- var utils = require('./../utils');
4
- var settle = require('./../core/settle');
5
- var buildFullPath = require('../core/buildFullPath');
6
- var buildURL = require('./../helpers/buildURL');
7
- var getProxyForUrl = require('proxy-from-env').getProxyForUrl;
8
- var http = require('http');
9
- var https = require('https');
10
- var httpFollow = require('follow-redirects/http');
11
- var httpsFollow = require('follow-redirects/https');
12
- var url = require('url');
13
- var zlib = require('zlib');
14
- var VERSION = require('./../env/data').version;
15
- var transitionalDefaults = require('../defaults/transitional');
16
- var AxiosError = require('../core/AxiosError');
17
- var CanceledError = require('../cancel/CanceledError');
18
- var platform = require('../platform');
19
- var fromDataURI = require('../helpers/fromDataURI');
20
- var stream = require('stream');
21
-
22
- var isHttps = /https:?/;
23
-
24
- var supportedProtocols = platform.protocols.map(function(protocol) {
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 => {
25
30
  return protocol + ':';
26
31
  });
27
32
 
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
+ */
28
41
  function dispatchBeforeRedirect(options) {
29
42
  if (options.beforeRedirects.proxy) {
30
43
  options.beforeRedirects.proxy(options);
@@ -35,37 +48,43 @@ function dispatchBeforeRedirect(options) {
35
48
  }
36
49
 
37
50
  /**
51
+ * If the proxy or config afterRedirects functions are defined, call them with the options
38
52
  *
39
53
  * @param {http.ClientRequestArgs} options
40
54
  * @param {AxiosProxyConfig} configProxy
41
55
  * @param {string} location
56
+ *
57
+ * @returns {http.ClientRequestArgs}
42
58
  */
43
59
  function setProxy(options, configProxy, location) {
44
- var proxy = configProxy;
60
+ let proxy = configProxy;
45
61
  if (!proxy && proxy !== false) {
46
- var proxyUrl = getProxyForUrl(location);
62
+ const proxyUrl = getProxyForUrl(location);
47
63
  if (proxyUrl) {
48
- proxy = url.parse(proxyUrl);
49
- // replace 'host' since the proxy object is not a URL object
50
- proxy.host = proxy.hostname;
64
+ proxy = new URL(proxyUrl);
51
65
  }
52
66
  }
53
67
  if (proxy) {
54
68
  // Basic proxy authorization
69
+ if (proxy.username) {
70
+ proxy.auth = (proxy.username || '') + ':' + (proxy.password || '');
71
+ }
72
+
55
73
  if (proxy.auth) {
56
74
  // Support proxy auth object form
57
75
  if (proxy.auth.username || proxy.auth.password) {
58
76
  proxy.auth = (proxy.auth.username || '') + ':' + (proxy.auth.password || '');
59
77
  }
60
- var base64 = Buffer
78
+ const base64 = Buffer
61
79
  .from(proxy.auth, 'utf8')
62
80
  .toString('base64');
63
81
  options.headers['Proxy-Authorization'] = 'Basic ' + base64;
64
82
  }
65
83
 
66
84
  options.headers.host = options.hostname + (options.port ? ':' + options.port : '');
67
- options.hostname = proxy.host;
68
- options.host = proxy.host;
85
+ options.hostname = proxy.hostname;
86
+ // Replace 'host' since options is not a URL object
87
+ options.host = proxy.hostname;
69
88
  options.port = proxy.port;
70
89
  options.path = location;
71
90
  if (proxy.protocol) {
@@ -81,47 +100,83 @@ function setProxy(options, configProxy, location) {
81
100
  }
82
101
 
83
102
  /*eslint consistent-return:0*/
84
- module.exports = function httpAdapter(config) {
103
+ export default function httpAdapter(config) {
85
104
  return new Promise(function dispatchHttpRequest(resolvePromise, rejectPromise) {
86
- var onCanceled;
87
- function done() {
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
+
88
121
  if (config.cancelToken) {
89
- config.cancelToken.unsubscribe(onCanceled);
122
+ config.cancelToken.unsubscribe(abort);
90
123
  }
91
124
 
92
125
  if (config.signal) {
93
- config.signal.removeEventListener('abort', onCanceled);
126
+ config.signal.removeEventListener('abort', abort);
94
127
  }
128
+
129
+ emitter.removeAllListeners();
95
130
  }
96
- var resolve = function resolve(value) {
97
- done();
98
- resolvePromise(value);
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);
99
147
  };
100
- var rejected = false;
101
- var reject = function reject(value) {
102
- done();
103
- rejected = true;
104
- rejectPromise(value);
148
+
149
+ const reject = function reject(value) {
150
+ done(value, true);
105
151
  };
106
- var data = config.data;
107
- var responseType = config.responseType;
108
- var responseEncoding = config.responseEncoding;
109
- var method = config.method.toUpperCase();
152
+
153
+ function abort(reason) {
154
+ emitter.emit('abort', !reason || reason.type ? new CanceledError(null, config, req) : reason);
155
+ }
156
+
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);
163
+ }
164
+ }
110
165
 
111
166
  // Parse url
112
- var fullPath = buildFullPath(config.baseURL, config.url);
113
- var parsed = url.parse(fullPath);
114
- var protocol = parsed.protocol || supportedProtocols[0];
167
+ const fullPath = buildFullPath(config.baseURL, config.url);
168
+ const parsed = new URL(fullPath);
169
+ const protocol = parsed.protocol || supportedProtocols[0];
115
170
 
116
171
  if (protocol === 'data:') {
117
- var convertedData;
172
+ let convertedData;
118
173
 
119
174
  if (method !== 'GET') {
120
175
  return settle(resolve, reject, {
121
176
  status: 405,
122
177
  statusText: 'method not allowed',
123
178
  headers: {},
124
- config: config
179
+ config
125
180
  });
126
181
  }
127
182
 
@@ -148,7 +203,7 @@ module.exports = function httpAdapter(config) {
148
203
  status: 200,
149
204
  statusText: 'OK',
150
205
  headers: {},
151
- config: config
206
+ config
152
207
  });
153
208
  }
154
209
 
@@ -160,29 +215,23 @@ module.exports = function httpAdapter(config) {
160
215
  ));
161
216
  }
162
217
 
163
- var headers = config.headers;
164
- var headerNames = {};
165
-
166
- Object.keys(headers).forEach(function storeLowerName(name) {
167
- headerNames[name.toLowerCase()] = name;
168
- });
218
+ const headers = AxiosHeaders.from(config.headers).normalize();
169
219
 
170
220
  // Set User-Agent (required by some servers)
171
221
  // See https://github.com/axios/axios/issues/69
172
- if ('user-agent' in headerNames) {
173
- // User-Agent is specified; handle case where no UA header is desired
174
- if (!headers[headerNames['user-agent']]) {
175
- delete headers[headerNames['user-agent']];
176
- }
177
- // Otherwise, use specified value
178
- } else {
179
- // Only set header if it hasn't been set in config
180
- headers['User-Agent'] = 'axios/' + VERSION;
181
- }
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;
182
231
 
183
232
  // support for https://www.npmjs.com/package/form-data api
184
233
  if (utils.isFormData(data) && utils.isFunction(data.getHeaders)) {
185
- Object.assign(headers, data.getHeaders());
234
+ headers.set(data.getHeaders());
186
235
  } else if (data && !utils.isStream(data)) {
187
236
  if (Buffer.isBuffer(data)) {
188
237
  // Nothing to do...
@@ -198,6 +247,9 @@ module.exports = function httpAdapter(config) {
198
247
  ));
199
248
  }
200
249
 
250
+ // Add Content-Length header if data exists
251
+ headers.set('Content-Length', data.length, false);
252
+
201
253
  if (config.maxBodyLength > -1 && data.length > config.maxBodyLength) {
202
254
  return reject(new AxiosError(
203
255
  'Request body larger than maxBodyLength limit',
@@ -205,49 +257,75 @@ module.exports = function httpAdapter(config) {
205
257
  config
206
258
  ));
207
259
  }
260
+ }
208
261
 
209
- // Add Content-Length header if data exists
210
- if (!headerNames['content-length']) {
211
- headers['Content-Length'] = data.length;
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});
212
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
+ });
213
286
  }
214
287
 
215
288
  // HTTP basic authentication
216
- var auth = undefined;
289
+ let auth = undefined;
217
290
  if (config.auth) {
218
- var username = config.auth.username || '';
219
- var password = config.auth.password || '';
291
+ const username = config.auth.username || '';
292
+ const password = config.auth.password || '';
220
293
  auth = username + ':' + password;
221
294
  }
222
295
 
223
- if (!auth && parsed.auth) {
224
- var urlAuth = parsed.auth.split(':');
225
- var urlUsername = urlAuth[0] || '';
226
- var urlPassword = urlAuth[1] || '';
296
+ if (!auth && parsed.username) {
297
+ const urlUsername = parsed.username;
298
+ const urlPassword = parsed.password;
227
299
  auth = urlUsername + ':' + urlPassword;
228
300
  }
229
301
 
230
- if (auth && headerNames.authorization) {
231
- delete headers[headerNames.authorization];
232
- }
302
+ auth && headers.delete('authorization');
303
+
304
+ let path;
233
305
 
234
306
  try {
235
- buildURL(parsed.path, config.params, config.paramsSerializer).replace(/^\?/, '');
307
+ path = buildURL(
308
+ parsed.pathname + parsed.search,
309
+ config.params,
310
+ config.paramsSerializer
311
+ ).replace(/^\?/, '');
236
312
  } catch (err) {
237
- var customErr = new Error(err.message);
313
+ const customErr = new Error(err.message);
238
314
  customErr.config = config;
239
315
  customErr.url = config.url;
240
316
  customErr.exists = true;
241
- reject(customErr);
317
+ return reject(customErr);
242
318
  }
243
319
 
244
- var options = {
245
- path: buildURL(parsed.path, config.params, config.paramsSerializer).replace(/^\?/, ''),
320
+ headers.set('Accept-Encoding', 'gzip, deflate, br', false);
321
+
322
+ const options = {
323
+ path,
246
324
  method: method,
247
- headers: headers,
325
+ headers: headers.toJSON(),
248
326
  agents: { http: config.httpAgent, https: config.httpsAgent },
249
- auth: auth,
250
- protocol: protocol,
327
+ auth,
328
+ protocol,
251
329
  beforeRedirect: dispatchBeforeRedirect,
252
330
  beforeRedirects: {}
253
331
  };
@@ -260,8 +338,8 @@ module.exports = function httpAdapter(config) {
260
338
  setProxy(options, config.proxy, protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path);
261
339
  }
262
340
 
263
- var transport;
264
- var isHttpsRequest = isHttps.test(options.protocol);
341
+ let transport;
342
+ const isHttpsRequest = isHttps.test(options.protocol);
265
343
  options.agent = isHttpsRequest ? config.httpsAgent : config.httpAgent;
266
344
  if (config.transport) {
267
345
  transport = config.transport;
@@ -289,14 +367,16 @@ module.exports = function httpAdapter(config) {
289
367
  }
290
368
 
291
369
  // Create the request
292
- var req = transport.request(options, function handleResponse(res) {
293
- if (req.aborted) return;
370
+ req = transport.request(options, function handleResponse(res) {
371
+ if (req.destroyed) return;
372
+
373
+ const streams = [res];
294
374
 
295
375
  // uncompress the response body transparently if required
296
- var responseStream = res;
376
+ let responseStream = res;
297
377
 
298
378
  // return the last request in case of redirects
299
- var lastRequest = res.req || req;
379
+ const lastRequest = res.req || req;
300
380
 
301
381
  // if decompress disabled we should not decompress
302
382
  if (config.decompress !== false) {
@@ -312,19 +392,48 @@ module.exports = function httpAdapter(config) {
312
392
  case 'compress':
313
393
  case 'deflate':
314
394
  // add the unzipper to the body stream processing pipeline
315
- responseStream = responseStream.pipe(zlib.createUnzip());
395
+ streams.push(zlib.createUnzip());
316
396
 
317
397
  // remove the content-encoding in order to not confuse downstream operations
318
398
  delete res.headers['content-encoding'];
319
399
  break;
400
+ case 'br':
401
+ if (isBrotliSupported) {
402
+ streams.push(zlib.createBrotliDecompress());
403
+ delete res.headers['content-encoding'];
404
+ }
320
405
  }
321
406
  }
322
407
 
323
- var response = {
408
+ if (onDownloadProgress) {
409
+ const responseLength = +res.headers['content-length'];
410
+
411
+ const transformStream = new AxiosTransformStream({
412
+ length: utils.toFiniteNumber(responseLength),
413
+ maxRate: utils.toFiniteNumber(maxDownloadRate)
414
+ });
415
+
416
+ onDownloadProgress && transformStream.on('progress', progress => {
417
+ onDownloadProgress(Object.assign(progress, {
418
+ download: true
419
+ }));
420
+ });
421
+
422
+ streams.push(transformStream);
423
+ }
424
+
425
+ responseStream = streams.length > 1 ? stream.pipeline(streams, utils.noop) : streams[0];
426
+
427
+ const offListeners = stream.finished(responseStream, () => {
428
+ offListeners();
429
+ onFinished();
430
+ });
431
+
432
+ const response = {
324
433
  status: res.statusCode,
325
434
  statusText: res.statusMessage,
326
- headers: res.headers,
327
- config: config,
435
+ headers: new AxiosHeaders(res.headers),
436
+ config,
328
437
  request: lastRequest
329
438
  };
330
439
 
@@ -332,8 +441,9 @@ module.exports = function httpAdapter(config) {
332
441
  response.data = responseStream;
333
442
  settle(resolve, reject, response);
334
443
  } else {
335
- var responseBuffer = [];
336
- var totalResponseBytes = 0;
444
+ const responseBuffer = [];
445
+ let totalResponseBytes = 0;
446
+
337
447
  responseStream.on('data', function handleStreamData(chunk) {
338
448
  responseBuffer.push(chunk);
339
449
  totalResponseBytes += chunk.length;
@@ -352,23 +462,25 @@ module.exports = function httpAdapter(config) {
352
462
  if (rejected) {
353
463
  return;
354
464
  }
355
- responseStream.destroy();
356
- reject(new AxiosError(
465
+
466
+ const err = new AxiosError(
357
467
  'maxContentLength size of ' + config.maxContentLength + ' exceeded',
358
468
  AxiosError.ERR_BAD_RESPONSE,
359
469
  config,
360
470
  lastRequest
361
- ));
471
+ );
472
+ responseStream.destroy(err);
473
+ reject(err);
362
474
  });
363
475
 
364
476
  responseStream.on('error', function handleStreamError(err) {
365
- if (req.aborted) return;
477
+ if (req.destroyed) return;
366
478
  reject(AxiosError.from(err, null, config, lastRequest));
367
479
  });
368
480
 
369
481
  responseStream.on('end', function handleStreamEnd() {
370
482
  try {
371
- var responseData = responseBuffer.length === 1 ? responseBuffer[0] : Buffer.concat(responseBuffer);
483
+ let responseData = responseBuffer.length === 1 ? responseBuffer[0] : Buffer.concat(responseBuffer);
372
484
  if (responseType !== 'arraybuffer') {
373
485
  responseData = responseData.toString(responseEncoding);
374
486
  if (!responseEncoding || responseEncoding === 'utf8') {
@@ -382,6 +494,18 @@ module.exports = function httpAdapter(config) {
382
494
  settle(resolve, reject, response);
383
495
  });
384
496
  }
497
+
498
+ emitter.once('abort', err => {
499
+ if (!responseStream.destroyed) {
500
+ responseStream.emit('error', err);
501
+ responseStream.destroy();
502
+ }
503
+ });
504
+ });
505
+
506
+ emitter.once('abort', err => {
507
+ reject(err);
508
+ req.destroy(err);
385
509
  });
386
510
 
387
511
  // Handle errors
@@ -400,7 +524,7 @@ module.exports = function httpAdapter(config) {
400
524
  // Handle request timeout
401
525
  if (config.timeout) {
402
526
  // This is forcing a int timeout to avoid problems if the `req` interface doesn't handle other types.
403
- var timeout = parseInt(config.timeout, 10);
527
+ const timeout = parseInt(config.timeout, 10);
404
528
 
405
529
  if (isNaN(timeout)) {
406
530
  reject(new AxiosError(
@@ -419,9 +543,9 @@ module.exports = function httpAdapter(config) {
419
543
  // And then these socket which be hang up will devouring CPU little by little.
420
544
  // ClientRequest.setTimeout will be fired on the specify milliseconds, and can make sure that abort() will be fired after connect.
421
545
  req.setTimeout(timeout, function handleRequestTimeout() {
422
- req.abort();
423
- var timeoutErrorMessage = config.timeout ? 'timeout of ' + config.timeout + 'ms exceeded' : 'timeout exceeded';
424
- var transitional = config.transitional || transitionalDefaults;
546
+ if (isDone) return;
547
+ let timeoutErrorMessage = config.timeout ? 'timeout of ' + config.timeout + 'ms exceeded' : 'timeout exceeded';
548
+ const transitional = config.transitional || transitionalDefaults;
425
549
  if (config.timeoutErrorMessage) {
426
550
  timeoutErrorMessage = config.timeoutErrorMessage;
427
551
  }
@@ -431,33 +555,34 @@ module.exports = function httpAdapter(config) {
431
555
  config,
432
556
  req
433
557
  ));
558
+ abort();
434
559
  });
435
560
  }
436
561
 
437
- if (config.cancelToken || config.signal) {
438
- // Handle cancellation
439
- // eslint-disable-next-line func-names
440
- onCanceled = function(cancel) {
441
- if (req.aborted) return;
442
562
 
443
- req.abort();
444
- reject(!cancel || cancel.type ? new CanceledError(null, config, req) : cancel);
445
- };
563
+ // Send the request
564
+ if (utils.isStream(data)) {
565
+ let ended = false;
566
+ let errored = false;
446
567
 
447
- config.cancelToken && config.cancelToken.subscribe(onCanceled);
448
- if (config.signal) {
449
- config.signal.aborted ? onCanceled() : config.signal.addEventListener('abort', onCanceled);
450
- }
451
- }
568
+ data.on('end', () => {
569
+ ended = true;
570
+ });
452
571
 
572
+ data.once('error', err => {
573
+ errored = true;
574
+ req.destroy(err);
575
+ });
453
576
 
454
- // Send the request
455
- if (utils.isStream(data)) {
456
- data.on('error', function handleStreamError(err) {
457
- reject(AxiosError.from(err, config, null, req));
458
- }).pipe(req);
577
+ data.on('close', () => {
578
+ if (!ended && !errored) {
579
+ abort(new CanceledError('Request stream has been aborted', config, req));
580
+ }
581
+ });
582
+
583
+ data.pipe(req);
459
584
  } else {
460
585
  req.end(data);
461
586
  }
462
587
  });
463
- };
588
+ }
@@ -0,0 +1,33 @@
1
+ import utils from '../utils.js';
2
+ import httpAdapter from './http.js';
3
+ import xhrAdapter from './xhr.js';
4
+
5
+ const adapters = {
6
+ http: httpAdapter,
7
+ xhr: xhrAdapter
8
+ }
9
+
10
+ export default {
11
+ getAdapter: (nameOrAdapter) => {
12
+ if(utils.isString(nameOrAdapter)){
13
+ const adapter = adapters[nameOrAdapter];
14
+
15
+ if (!nameOrAdapter) {
16
+ throw Error(
17
+ utils.hasOwnProp(nameOrAdapter) ?
18
+ `Adapter '${nameOrAdapter}' is not available in the build` :
19
+ `Can not resolve adapter '${nameOrAdapter}'`
20
+ );
21
+ }
22
+
23
+ return adapter
24
+ }
25
+
26
+ if (!utils.isFunction(nameOrAdapter)) {
27
+ throw new TypeError('adapter is not a function');
28
+ }
29
+
30
+ return nameOrAdapter;
31
+ },
32
+ adapters
33
+ }