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

Files changed (70) hide show
  1. package/CHANGELOG.md +55 -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 +1552 -975
  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 +1471 -865
  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 +3750 -0
  14. package/dist/node/axios.cjs.map +1 -0
  15. package/gulpfile.js +88 -0
  16. package/index.d.ts +208 -63
  17. package/index.js +2 -1
  18. package/karma.conf.cjs +250 -0
  19. package/lib/adapters/http.js +251 -131
  20. package/lib/adapters/index.js +33 -0
  21. package/lib/adapters/xhr.js +79 -56
  22. package/lib/axios.js +33 -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 +293 -191
  68. package/package.json +55 -22
  69. package/rollup.config.js +36 -6
  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,70 @@ 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');
233
303
 
304
+ const path = parsed.pathname.concat(parsed.searchParams);
234
305
  try {
235
- buildURL(parsed.path, config.params, config.paramsSerializer).replace(/^\?/, '');
306
+ buildURL(path, config.params, config.paramsSerializer).replace(/^\?/, '');
236
307
  } catch (err) {
237
- var customErr = new Error(err.message);
308
+ const customErr = new Error(err.message);
238
309
  customErr.config = config;
239
310
  customErr.url = config.url;
240
311
  customErr.exists = true;
241
- reject(customErr);
312
+ return reject(customErr);
242
313
  }
243
314
 
244
- var options = {
245
- path: buildURL(parsed.path, config.params, config.paramsSerializer).replace(/^\?/, ''),
315
+ headers.set('Accept-Encoding', 'gzip, deflate, br', false);
316
+
317
+ const options = {
318
+ path: buildURL(path, config.params, config.paramsSerializer).replace(/^\?/, ''),
246
319
  method: method,
247
- headers: headers,
320
+ headers: headers.toJSON(),
248
321
  agents: { http: config.httpAgent, https: config.httpsAgent },
249
- auth: auth,
250
- protocol: protocol,
322
+ auth,
323
+ protocol,
251
324
  beforeRedirect: dispatchBeforeRedirect,
252
325
  beforeRedirects: {}
253
326
  };
@@ -260,8 +333,8 @@ module.exports = function httpAdapter(config) {
260
333
  setProxy(options, config.proxy, protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path);
261
334
  }
262
335
 
263
- var transport;
264
- var isHttpsRequest = isHttps.test(options.protocol);
336
+ let transport;
337
+ const isHttpsRequest = isHttps.test(options.protocol);
265
338
  options.agent = isHttpsRequest ? config.httpsAgent : config.httpAgent;
266
339
  if (config.transport) {
267
340
  transport = config.transport;
@@ -289,14 +362,16 @@ module.exports = function httpAdapter(config) {
289
362
  }
290
363
 
291
364
  // Create the request
292
- var req = transport.request(options, function handleResponse(res) {
293
- if (req.aborted) return;
365
+ req = transport.request(options, function handleResponse(res) {
366
+ if (req.destroyed) return;
367
+
368
+ const streams = [res];
294
369
 
295
370
  // uncompress the response body transparently if required
296
- var responseStream = res;
371
+ let responseStream = res;
297
372
 
298
373
  // return the last request in case of redirects
299
- var lastRequest = res.req || req;
374
+ const lastRequest = res.req || req;
300
375
 
301
376
  // if decompress disabled we should not decompress
302
377
  if (config.decompress !== false) {
@@ -312,19 +387,48 @@ module.exports = function httpAdapter(config) {
312
387
  case 'compress':
313
388
  case 'deflate':
314
389
  // add the unzipper to the body stream processing pipeline
315
- responseStream = responseStream.pipe(zlib.createUnzip());
390
+ streams.push(zlib.createUnzip());
316
391
 
317
392
  // remove the content-encoding in order to not confuse downstream operations
318
393
  delete res.headers['content-encoding'];
319
394
  break;
395
+ case 'br':
396
+ if (isBrotliSupported) {
397
+ streams.push(zlib.createBrotliDecompress());
398
+ delete res.headers['content-encoding'];
399
+ }
320
400
  }
321
401
  }
322
402
 
323
- var response = {
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 = {
324
428
  status: res.statusCode,
325
429
  statusText: res.statusMessage,
326
- headers: res.headers,
327
- config: config,
430
+ headers: new AxiosHeaders(res.headers),
431
+ config,
328
432
  request: lastRequest
329
433
  };
330
434
 
@@ -332,8 +436,9 @@ module.exports = function httpAdapter(config) {
332
436
  response.data = responseStream;
333
437
  settle(resolve, reject, response);
334
438
  } else {
335
- var responseBuffer = [];
336
- var totalResponseBytes = 0;
439
+ const responseBuffer = [];
440
+ let totalResponseBytes = 0;
441
+
337
442
  responseStream.on('data', function handleStreamData(chunk) {
338
443
  responseBuffer.push(chunk);
339
444
  totalResponseBytes += chunk.length;
@@ -352,23 +457,25 @@ module.exports = function httpAdapter(config) {
352
457
  if (rejected) {
353
458
  return;
354
459
  }
355
- responseStream.destroy();
356
- reject(new AxiosError(
460
+
461
+ const err = new AxiosError(
357
462
  'maxContentLength size of ' + config.maxContentLength + ' exceeded',
358
463
  AxiosError.ERR_BAD_RESPONSE,
359
464
  config,
360
465
  lastRequest
361
- ));
466
+ );
467
+ responseStream.destroy(err);
468
+ reject(err);
362
469
  });
363
470
 
364
471
  responseStream.on('error', function handleStreamError(err) {
365
- if (req.aborted) return;
472
+ if (req.destroyed) return;
366
473
  reject(AxiosError.from(err, null, config, lastRequest));
367
474
  });
368
475
 
369
476
  responseStream.on('end', function handleStreamEnd() {
370
477
  try {
371
- var responseData = responseBuffer.length === 1 ? responseBuffer[0] : Buffer.concat(responseBuffer);
478
+ let responseData = responseBuffer.length === 1 ? responseBuffer[0] : Buffer.concat(responseBuffer);
372
479
  if (responseType !== 'arraybuffer') {
373
480
  responseData = responseData.toString(responseEncoding);
374
481
  if (!responseEncoding || responseEncoding === 'utf8') {
@@ -382,6 +489,18 @@ module.exports = function httpAdapter(config) {
382
489
  settle(resolve, reject, response);
383
490
  });
384
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);
385
504
  });
386
505
 
387
506
  // Handle errors
@@ -400,7 +519,7 @@ module.exports = function httpAdapter(config) {
400
519
  // Handle request timeout
401
520
  if (config.timeout) {
402
521
  // 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);
522
+ const timeout = parseInt(config.timeout, 10);
404
523
 
405
524
  if (isNaN(timeout)) {
406
525
  reject(new AxiosError(
@@ -419,9 +538,9 @@ module.exports = function httpAdapter(config) {
419
538
  // And then these socket which be hang up will devouring CPU little by little.
420
539
  // ClientRequest.setTimeout will be fired on the specify milliseconds, and can make sure that abort() will be fired after connect.
421
540
  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;
541
+ if (isDone) return;
542
+ let timeoutErrorMessage = config.timeout ? 'timeout of ' + config.timeout + 'ms exceeded' : 'timeout exceeded';
543
+ const transitional = config.transitional || transitionalDefaults;
425
544
  if (config.timeoutErrorMessage) {
426
545
  timeoutErrorMessage = config.timeoutErrorMessage;
427
546
  }
@@ -431,33 +550,34 @@ module.exports = function httpAdapter(config) {
431
550
  config,
432
551
  req
433
552
  ));
553
+ abort();
434
554
  });
435
555
  }
436
556
 
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
557
 
443
- req.abort();
444
- reject(!cancel || cancel.type ? new CanceledError(null, config, req) : cancel);
445
- };
558
+ // Send the request
559
+ if (utils.isStream(data)) {
560
+ let ended = false;
561
+ let errored = false;
446
562
 
447
- config.cancelToken && config.cancelToken.subscribe(onCanceled);
448
- if (config.signal) {
449
- config.signal.aborted ? onCanceled() : config.signal.addEventListener('abort', onCanceled);
450
- }
451
- }
563
+ data.on('end', () => {
564
+ ended = true;
565
+ });
452
566
 
567
+ data.once('error', err => {
568
+ errored = true;
569
+ req.destroy(err);
570
+ });
453
571
 
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);
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);
459
579
  } else {
460
580
  req.end(data);
461
581
  }
462
582
  });
463
- };
583
+ }
@@ -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
+ }