axios 0.21.1 → 0.22.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.
package/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export interface AxiosTransformer {
2
- (data: any, headers?: any): any;
2
+ (data: any, headers?: Record<string, string>): any;
3
3
  }
4
4
 
5
5
  export interface AxiosAdapter {
@@ -41,16 +41,22 @@ export type ResponseType =
41
41
  | 'text'
42
42
  | 'stream'
43
43
 
44
- export interface AxiosRequestConfig {
44
+ export interface TransitionalOptions{
45
+ silentJSONParsing: boolean;
46
+ forcedJSONParsing: boolean;
47
+ clarifyTimeoutError: boolean;
48
+ }
49
+
50
+ export interface AxiosRequestConfig<T = any> {
45
51
  url?: string;
46
52
  method?: Method;
47
53
  baseURL?: string;
48
54
  transformRequest?: AxiosTransformer | AxiosTransformer[];
49
55
  transformResponse?: AxiosTransformer | AxiosTransformer[];
50
- headers?: any;
56
+ headers?: Record<string, string>;
51
57
  params?: any;
52
58
  paramsSerializer?: (params: any) => string;
53
- data?: any;
59
+ data?: T;
54
60
  timeout?: number;
55
61
  timeoutErrorMessage?: string;
56
62
  withCredentials?: boolean;
@@ -71,18 +77,20 @@ export interface AxiosRequestConfig {
71
77
  proxy?: AxiosProxyConfig | false;
72
78
  cancelToken?: CancelToken;
73
79
  decompress?: boolean;
80
+ transitional?: TransitionalOptions
81
+ signal?: AbortSignal;
74
82
  }
75
83
 
76
- export interface AxiosResponse<T = any> {
84
+ export interface AxiosResponse<T = never> {
77
85
  data: T;
78
86
  status: number;
79
87
  statusText: string;
80
- headers: any;
81
- config: AxiosRequestConfig;
88
+ headers: Record<string, string>;
89
+ config: AxiosRequestConfig<T>;
82
90
  request?: any;
83
91
  }
84
92
 
85
- export interface AxiosError<T = any> extends Error {
93
+ export interface AxiosError<T = never> extends Error {
86
94
  config: AxiosRequestConfig;
87
95
  code?: string;
88
96
  request?: any;
@@ -91,7 +99,7 @@ export interface AxiosError<T = any> extends Error {
91
99
  toJSON: () => object;
92
100
  }
93
101
 
94
- export interface AxiosPromise<T = any> extends Promise<AxiosResponse<T>> {
102
+ export interface AxiosPromise<T = never> extends Promise<AxiosResponse<T>> {
95
103
  }
96
104
 
97
105
  export interface CancelStatic {
@@ -123,33 +131,39 @@ export interface CancelTokenSource {
123
131
  }
124
132
 
125
133
  export interface AxiosInterceptorManager<V> {
126
- use(onFulfilled?: (value: V) => V | Promise<V>, onRejected?: (error: any) => any): number;
134
+ use<T = V>(onFulfilled?: (value: V) => T | Promise<T>, onRejected?: (error: any) => any): number;
127
135
  eject(id: number): void;
128
136
  }
129
137
 
130
- export interface AxiosInstance {
131
- (config: AxiosRequestConfig): AxiosPromise;
132
- (url: string, config?: AxiosRequestConfig): AxiosPromise;
138
+ export class Axios {
139
+ constructor(config?: AxiosRequestConfig);
133
140
  defaults: AxiosRequestConfig;
134
141
  interceptors: {
135
142
  request: AxiosInterceptorManager<AxiosRequestConfig>;
136
143
  response: AxiosInterceptorManager<AxiosResponse>;
137
144
  };
138
145
  getUri(config?: AxiosRequestConfig): string;
139
- request<T = any, R = AxiosResponse<T>> (config: AxiosRequestConfig): Promise<R>;
140
- get<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
141
- delete<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
142
- head<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
143
- options<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
144
- post<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>;
145
- put<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>;
146
- patch<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>;
146
+ request<T = never, R = AxiosResponse<T>> (config: AxiosRequestConfig<T>): Promise<R>;
147
+ get<T = never, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig<T>): Promise<R>;
148
+ delete<T = never, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig<T>): Promise<R>;
149
+ head<T = never, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig<T>): Promise<R>;
150
+ options<T = never, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig<T>): Promise<R>;
151
+ post<T = never, R = AxiosResponse<T>>(url: string, data?: T, config?: AxiosRequestConfig<T>): Promise<R>;
152
+ put<T = never, R = AxiosResponse<T>>(url: string, data?: T, config?: AxiosRequestConfig<T>): Promise<R>;
153
+ patch<T = never, R = AxiosResponse<T>>(url: string, data?: T, config?: AxiosRequestConfig<T>): Promise<R>;
154
+ }
155
+
156
+ export interface AxiosInstance extends Axios {
157
+ (config: AxiosRequestConfig): AxiosPromise;
158
+ (url: string, config?: AxiosRequestConfig): AxiosPromise;
147
159
  }
148
160
 
149
161
  export interface AxiosStatic extends AxiosInstance {
150
162
  create(config?: AxiosRequestConfig): AxiosInstance;
151
163
  Cancel: CancelStatic;
152
164
  CancelToken: CancelTokenStatic;
165
+ Axios: typeof Axios;
166
+ readonly VERSION: string;
153
167
  isCancel(value: any): boolean;
154
168
  all<T>(values: (T | Promise<T>)[]): Promise<T[]>;
155
169
  spread<T, R>(callback: (...args: T[]) => R): (array: T[]) => R;
@@ -10,9 +10,11 @@ var httpFollow = require('follow-redirects').http;
10
10
  var httpsFollow = require('follow-redirects').https;
11
11
  var url = require('url');
12
12
  var zlib = require('zlib');
13
- var pkg = require('./../../package.json');
13
+ var VERSION = require('./../env/data').version;
14
14
  var createError = require('../core/createError');
15
15
  var enhanceError = require('../core/enhanceError');
16
+ var defaults = require('../defaults');
17
+ var Cancel = require('../cancel/Cancel');
16
18
 
17
19
  var isHttps = /https:?/;
18
20
 
@@ -44,20 +46,43 @@ function setProxy(options, proxy, location) {
44
46
  /*eslint consistent-return:0*/
45
47
  module.exports = function httpAdapter(config) {
46
48
  return new Promise(function dispatchHttpRequest(resolvePromise, rejectPromise) {
49
+ var onCanceled;
50
+ function done() {
51
+ if (config.cancelToken) {
52
+ config.cancelToken.unsubscribe(onCanceled);
53
+ }
54
+
55
+ if (config.signal) {
56
+ config.signal.removeEventListener('abort', onCanceled);
57
+ }
58
+ }
47
59
  var resolve = function resolve(value) {
60
+ done();
48
61
  resolvePromise(value);
49
62
  };
50
63
  var reject = function reject(value) {
64
+ done();
51
65
  rejectPromise(value);
52
66
  };
53
67
  var data = config.data;
54
68
  var headers = config.headers;
69
+ var headerNames = {};
70
+
71
+ Object.keys(headers).forEach(function storeLowerName(name) {
72
+ headerNames[name.toLowerCase()] = name;
73
+ });
55
74
 
56
75
  // Set User-Agent (required by some servers)
57
- // Only set header if it hasn't been set in config
58
76
  // See https://github.com/axios/axios/issues/69
59
- if (!headers['User-Agent'] && !headers['user-agent']) {
60
- headers['User-Agent'] = 'axios/' + pkg.version;
77
+ if ('user-agent' in headerNames) {
78
+ // User-Agent is specified; handle case where no UA header is desired
79
+ if (!headers[headerNames['user-agent']]) {
80
+ delete headers[headerNames['user-agent']];
81
+ }
82
+ // Otherwise, use specified value
83
+ } else {
84
+ // Only set header if it hasn't been set in config
85
+ headers['User-Agent'] = 'axios/' + VERSION;
61
86
  }
62
87
 
63
88
  if (data && !utils.isStream(data)) {
@@ -75,7 +100,9 @@ module.exports = function httpAdapter(config) {
75
100
  }
76
101
 
77
102
  // Add Content-Length header if data exists
78
- headers['Content-Length'] = data.length;
103
+ if (!headerNames['content-length']) {
104
+ headers['Content-Length'] = data.length;
105
+ }
79
106
  }
80
107
 
81
108
  // HTTP basic authentication
@@ -98,8 +125,8 @@ module.exports = function httpAdapter(config) {
98
125
  auth = urlUsername + ':' + urlPassword;
99
126
  }
100
127
 
101
- if (auth) {
102
- delete headers.Authorization;
128
+ if (auth && headerNames.authorization) {
129
+ delete headers[headerNames.authorization];
103
130
  }
104
131
 
105
132
  var isHttpsRequest = isHttps.test(protocol);
@@ -191,6 +218,10 @@ module.exports = function httpAdapter(config) {
191
218
  options.maxBodyLength = config.maxBodyLength;
192
219
  }
193
220
 
221
+ if (config.insecureHTTPParser) {
222
+ options.insecureHTTPParser = config.insecureHTTPParser;
223
+ }
224
+
194
225
  // Create the request
195
226
  var req = transport.request(options, function handleResponse(res) {
196
227
  if (req.aborted) return;
@@ -231,11 +262,13 @@ module.exports = function httpAdapter(config) {
231
262
  settle(resolve, reject, response);
232
263
  } else {
233
264
  var responseBuffer = [];
265
+ var totalResponseBytes = 0;
234
266
  stream.on('data', function handleStreamData(chunk) {
235
267
  responseBuffer.push(chunk);
268
+ totalResponseBytes += chunk.length;
236
269
 
237
270
  // make sure the content length is not over the maxContentLength if specified
238
- if (config.maxContentLength > -1 && Buffer.concat(responseBuffer).length > config.maxContentLength) {
271
+ if (config.maxContentLength > -1 && totalResponseBytes > config.maxContentLength) {
239
272
  stream.destroy();
240
273
  reject(createError('maxContentLength size of ' + config.maxContentLength + ' exceeded',
241
274
  config, null, lastRequest));
@@ -270,27 +303,54 @@ module.exports = function httpAdapter(config) {
270
303
 
271
304
  // Handle request timeout
272
305
  if (config.timeout) {
306
+ // This is forcing a int timeout to avoid problems if the `req` interface doesn't handle other types.
307
+ var timeout = parseInt(config.timeout, 10);
308
+
309
+ if (isNaN(timeout)) {
310
+ reject(createError(
311
+ 'error trying to parse `config.timeout` to int',
312
+ config,
313
+ 'ERR_PARSE_TIMEOUT',
314
+ req
315
+ ));
316
+
317
+ return;
318
+ }
319
+
273
320
  // Sometime, the response will be very slow, and does not respond, the connect event will be block by event loop system.
274
321
  // And timer callback will be fired, and abort() will be invoked before connection, then get "socket hang up" and code ECONNRESET.
275
322
  // 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.
276
323
  // And then these socket which be hang up will devoring CPU little by little.
277
324
  // ClientRequest.setTimeout will be fired on the specify milliseconds, and can make sure that abort() will be fired after connect.
278
- req.setTimeout(config.timeout, function handleRequestTimeout() {
325
+ req.setTimeout(timeout, function handleRequestTimeout() {
279
326
  req.abort();
280
- reject(createError('timeout of ' + config.timeout + 'ms exceeded', config, 'ECONNABORTED', req));
327
+ var transitional = config.transitional || defaults.transitional;
328
+ reject(createError(
329
+ 'timeout of ' + timeout + 'ms exceeded',
330
+ config,
331
+ transitional.clarifyTimeoutError ? 'ETIMEDOUT' : 'ECONNABORTED',
332
+ req
333
+ ));
281
334
  });
282
335
  }
283
336
 
284
- if (config.cancelToken) {
337
+ if (config.cancelToken || config.signal) {
285
338
  // Handle cancellation
286
- config.cancelToken.promise.then(function onCanceled(cancel) {
339
+ // eslint-disable-next-line func-names
340
+ onCanceled = function(cancel) {
287
341
  if (req.aborted) return;
288
342
 
289
343
  req.abort();
290
- reject(cancel);
291
- });
344
+ reject(!cancel || (cancel && cancel.type) ? new Cancel('canceled') : cancel);
345
+ };
346
+
347
+ config.cancelToken && config.cancelToken.subscribe(onCanceled);
348
+ if (config.signal) {
349
+ config.signal.aborted ? onCanceled() : config.signal.addEventListener('abort', onCanceled);
350
+ }
292
351
  }
293
352
 
353
+
294
354
  // Send the request
295
355
  if (utils.isStream(data)) {
296
356
  data.on('error', function handleStreamError(err) {
@@ -8,11 +8,24 @@ var buildFullPath = require('../core/buildFullPath');
8
8
  var parseHeaders = require('./../helpers/parseHeaders');
9
9
  var isURLSameOrigin = require('./../helpers/isURLSameOrigin');
10
10
  var createError = require('../core/createError');
11
+ var defaults = require('../defaults');
12
+ var Cancel = require('../cancel/Cancel');
11
13
 
12
14
  module.exports = function xhrAdapter(config) {
13
15
  return new Promise(function dispatchXhrRequest(resolve, reject) {
14
16
  var requestData = config.data;
15
17
  var requestHeaders = config.headers;
18
+ var responseType = config.responseType;
19
+ var onCanceled;
20
+ function done() {
21
+ if (config.cancelToken) {
22
+ config.cancelToken.unsubscribe(onCanceled);
23
+ }
24
+
25
+ if (config.signal) {
26
+ config.signal.removeEventListener('abort', onCanceled);
27
+ }
28
+ }
16
29
 
17
30
  if (utils.isFormData(requestData)) {
18
31
  delete requestHeaders['Content-Type']; // Let the browser set it
@@ -33,23 +46,14 @@ module.exports = function xhrAdapter(config) {
33
46
  // Set the request timeout in MS
34
47
  request.timeout = config.timeout;
35
48
 
36
- // Listen for ready state
37
- request.onreadystatechange = function handleLoad() {
38
- if (!request || request.readyState !== 4) {
39
- return;
40
- }
41
-
42
- // The request errored out and we didn't get a response, this will be
43
- // handled by onerror instead
44
- // With one exception: request that using file: protocol, most browsers
45
- // will return status as 0 even though it's a successful request
46
- if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {
49
+ function onloadend() {
50
+ if (!request) {
47
51
  return;
48
52
  }
49
-
50
53
  // Prepare the response
51
54
  var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null;
52
- var responseData = !config.responseType || config.responseType === 'text' ? request.responseText : request.response;
55
+ var responseData = !responseType || responseType === 'text' || responseType === 'json' ?
56
+ request.responseText : request.response;
53
57
  var response = {
54
58
  data: responseData,
55
59
  status: request.status,
@@ -59,11 +63,40 @@ module.exports = function xhrAdapter(config) {
59
63
  request: request
60
64
  };
61
65
 
62
- settle(resolve, reject, response);
66
+ settle(function _resolve(value) {
67
+ resolve(value);
68
+ done();
69
+ }, function _reject(err) {
70
+ reject(err);
71
+ done();
72
+ }, response);
63
73
 
64
74
  // Clean up request
65
75
  request = null;
66
- };
76
+ }
77
+
78
+ if ('onloadend' in request) {
79
+ // Use onloadend if available
80
+ request.onloadend = onloadend;
81
+ } else {
82
+ // Listen for ready state to emulate onloadend
83
+ request.onreadystatechange = function handleLoad() {
84
+ if (!request || request.readyState !== 4) {
85
+ return;
86
+ }
87
+
88
+ // The request errored out and we didn't get a response, this will be
89
+ // handled by onerror instead
90
+ // With one exception: request that using file: protocol, most browsers
91
+ // will return status as 0 even though it's a successful request
92
+ if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {
93
+ return;
94
+ }
95
+ // readystate handler is calling before onerror or ontimeout handlers,
96
+ // so we should call onloadend on the next 'tick'
97
+ setTimeout(onloadend);
98
+ };
99
+ }
67
100
 
68
101
  // Handle browser request cancellation (as opposed to a manual cancellation)
69
102
  request.onabort = function handleAbort() {
@@ -90,10 +123,14 @@ module.exports = function xhrAdapter(config) {
90
123
  // Handle timeout
91
124
  request.ontimeout = function handleTimeout() {
92
125
  var timeoutErrorMessage = 'timeout of ' + config.timeout + 'ms exceeded';
126
+ var transitional = config.transitional || defaults.transitional;
93
127
  if (config.timeoutErrorMessage) {
94
128
  timeoutErrorMessage = config.timeoutErrorMessage;
95
129
  }
96
- reject(createError(timeoutErrorMessage, config, 'ECONNABORTED',
130
+ reject(createError(
131
+ timeoutErrorMessage,
132
+ config,
133
+ transitional.clarifyTimeoutError ? 'ETIMEDOUT' : 'ECONNABORTED',
97
134
  request));
98
135
 
99
136
  // Clean up request
@@ -133,16 +170,8 @@ module.exports = function xhrAdapter(config) {
133
170
  }
134
171
 
135
172
  // Add responseType to request if needed
136
- if (config.responseType) {
137
- try {
138
- request.responseType = config.responseType;
139
- } catch (e) {
140
- // Expected DOMException thrown by browsers not compatible XMLHttpRequest Level 2.
141
- // But, this can be suppressed for 'json' type as it can be parsed by default 'transformResponse' function.
142
- if (config.responseType !== 'json') {
143
- throw e;
144
- }
145
- }
173
+ if (responseType && responseType !== 'json') {
174
+ request.responseType = config.responseType;
146
175
  }
147
176
 
148
177
  // Handle progress if needed
@@ -155,18 +184,22 @@ module.exports = function xhrAdapter(config) {
155
184
  request.upload.addEventListener('progress', config.onUploadProgress);
156
185
  }
157
186
 
158
- if (config.cancelToken) {
187
+ if (config.cancelToken || config.signal) {
159
188
  // Handle cancellation
160
- config.cancelToken.promise.then(function onCanceled(cancel) {
189
+ // eslint-disable-next-line func-names
190
+ onCanceled = function(cancel) {
161
191
  if (!request) {
162
192
  return;
163
193
  }
164
-
194
+ reject(!cancel || (cancel && cancel.type) ? new Cancel('canceled') : cancel);
165
195
  request.abort();
166
- reject(cancel);
167
- // Clean up request
168
196
  request = null;
169
- });
197
+ };
198
+
199
+ config.cancelToken && config.cancelToken.subscribe(onCanceled);
200
+ if (config.signal) {
201
+ config.signal.aborted ? onCanceled() : config.signal.addEventListener('abort', onCanceled);
202
+ }
170
203
  }
171
204
 
172
205
  if (!requestData) {
package/lib/axios.js CHANGED
@@ -22,6 +22,11 @@ function createInstance(defaultConfig) {
22
22
  // Copy context to instance
23
23
  utils.extend(instance, context);
24
24
 
25
+ // Factory for creating new instances
26
+ instance.create = function create(instanceConfig) {
27
+ return createInstance(mergeConfig(defaultConfig, instanceConfig));
28
+ };
29
+
25
30
  return instance;
26
31
  }
27
32
 
@@ -31,15 +36,11 @@ var axios = createInstance(defaults);
31
36
  // Expose Axios class to allow class inheritance
32
37
  axios.Axios = Axios;
33
38
 
34
- // Factory for creating new instances
35
- axios.create = function create(instanceConfig) {
36
- return createInstance(mergeConfig(axios.defaults, instanceConfig));
37
- };
38
-
39
39
  // Expose Cancel & CancelToken
40
40
  axios.Cancel = require('./cancel/Cancel');
41
41
  axios.CancelToken = require('./cancel/CancelToken');
42
42
  axios.isCancel = require('./cancel/isCancel');
43
+ axios.VERSION = require('./env/data').version;
43
44
 
44
45
  // Expose all/spread
45
46
  axios.all = function all(promises) {
@@ -14,11 +14,42 @@ function CancelToken(executor) {
14
14
  }
15
15
 
16
16
  var resolvePromise;
17
+
17
18
  this.promise = new Promise(function promiseExecutor(resolve) {
18
19
  resolvePromise = resolve;
19
20
  });
20
21
 
21
22
  var token = this;
23
+
24
+ // eslint-disable-next-line func-names
25
+ this.promise.then(function(cancel) {
26
+ if (!token._listeners) return;
27
+
28
+ var i;
29
+ var l = token._listeners.length;
30
+
31
+ for (i = 0; i < l; i++) {
32
+ token._listeners[i](cancel);
33
+ }
34
+ token._listeners = null;
35
+ });
36
+
37
+ // eslint-disable-next-line func-names
38
+ this.promise.then = function(onfulfilled) {
39
+ var _resolve;
40
+ // eslint-disable-next-line func-names
41
+ var promise = new Promise(function(resolve) {
42
+ token.subscribe(resolve);
43
+ _resolve = resolve;
44
+ }).then(onfulfilled);
45
+
46
+ promise.cancel = function reject() {
47
+ token.unsubscribe(_resolve);
48
+ };
49
+
50
+ return promise;
51
+ };
52
+
22
53
  executor(function cancel(message) {
23
54
  if (token.reason) {
24
55
  // Cancellation has already been requested
@@ -39,6 +70,37 @@ CancelToken.prototype.throwIfRequested = function throwIfRequested() {
39
70
  }
40
71
  };
41
72
 
73
+ /**
74
+ * Subscribe to the cancel signal
75
+ */
76
+
77
+ CancelToken.prototype.subscribe = function subscribe(listener) {
78
+ if (this.reason) {
79
+ listener(this.reason);
80
+ return;
81
+ }
82
+
83
+ if (this._listeners) {
84
+ this._listeners.push(listener);
85
+ } else {
86
+ this._listeners = [listener];
87
+ }
88
+ };
89
+
90
+ /**
91
+ * Unsubscribe from the cancel signal
92
+ */
93
+
94
+ CancelToken.prototype.unsubscribe = function unsubscribe(listener) {
95
+ if (!this._listeners) {
96
+ return;
97
+ }
98
+ var index = this._listeners.indexOf(listener);
99
+ if (index !== -1) {
100
+ this._listeners.splice(index, 1);
101
+ }
102
+ };
103
+
42
104
  /**
43
105
  * Returns an object that contains a new `CancelToken` and a function that, when called,
44
106
  * cancels the `CancelToken`.
package/lib/core/Axios.js CHANGED
@@ -5,7 +5,9 @@ var buildURL = require('../helpers/buildURL');
5
5
  var InterceptorManager = require('./InterceptorManager');
6
6
  var dispatchRequest = require('./dispatchRequest');
7
7
  var mergeConfig = require('./mergeConfig');
8
+ var validator = require('../helpers/validator');
8
9
 
10
+ var validators = validator.validators;
9
11
  /**
10
12
  * Create a new instance of Axios
11
13
  *
@@ -45,20 +47,71 @@ Axios.prototype.request = function request(config) {
45
47
  config.method = 'get';
46
48
  }
47
49
 
48
- // Hook up interceptors middleware
49
- var chain = [dispatchRequest, undefined];
50
- var promise = Promise.resolve(config);
50
+ var transitional = config.transitional;
51
51
 
52
+ if (transitional !== undefined) {
53
+ validator.assertOptions(transitional, {
54
+ silentJSONParsing: validators.transitional(validators.boolean),
55
+ forcedJSONParsing: validators.transitional(validators.boolean),
56
+ clarifyTimeoutError: validators.transitional(validators.boolean)
57
+ }, false);
58
+ }
59
+
60
+ // filter out skipped interceptors
61
+ var requestInterceptorChain = [];
62
+ var synchronousRequestInterceptors = true;
52
63
  this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
53
- chain.unshift(interceptor.fulfilled, interceptor.rejected);
64
+ if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {
65
+ return;
66
+ }
67
+
68
+ synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
69
+
70
+ requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
54
71
  });
55
72
 
73
+ var responseInterceptorChain = [];
56
74
  this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
57
- chain.push(interceptor.fulfilled, interceptor.rejected);
75
+ responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
58
76
  });
59
77
 
60
- while (chain.length) {
61
- promise = promise.then(chain.shift(), chain.shift());
78
+ var promise;
79
+
80
+ if (!synchronousRequestInterceptors) {
81
+ var chain = [dispatchRequest, undefined];
82
+
83
+ Array.prototype.unshift.apply(chain, requestInterceptorChain);
84
+ chain = chain.concat(responseInterceptorChain);
85
+
86
+ promise = Promise.resolve(config);
87
+ while (chain.length) {
88
+ promise = promise.then(chain.shift(), chain.shift());
89
+ }
90
+
91
+ return promise;
92
+ }
93
+
94
+
95
+ var newConfig = config;
96
+ while (requestInterceptorChain.length) {
97
+ var onFulfilled = requestInterceptorChain.shift();
98
+ var onRejected = requestInterceptorChain.shift();
99
+ try {
100
+ newConfig = onFulfilled(newConfig);
101
+ } catch (error) {
102
+ onRejected(error);
103
+ break;
104
+ }
105
+ }
106
+
107
+ try {
108
+ promise = dispatchRequest(newConfig);
109
+ } catch (error) {
110
+ return Promise.reject(error);
111
+ }
112
+
113
+ while (responseInterceptorChain.length) {
114
+ promise = promise.then(responseInterceptorChain.shift(), responseInterceptorChain.shift());
62
115
  }
63
116
 
64
117
  return promise;
@@ -14,10 +14,12 @@ function InterceptorManager() {
14
14
  *
15
15
  * @return {Number} An ID used to remove interceptor later
16
16
  */
17
- InterceptorManager.prototype.use = function use(fulfilled, rejected) {
17
+ InterceptorManager.prototype.use = function use(fulfilled, rejected, options) {
18
18
  this.handlers.push({
19
19
  fulfilled: fulfilled,
20
- rejected: rejected
20
+ rejected: rejected,
21
+ synchronous: options ? options.synchronous : false,
22
+ runWhen: options ? options.runWhen : null
21
23
  });
22
24
  return this.handlers.length - 1;
23
25
  };
@@ -3,5 +3,6 @@
3
3
  The modules found in `core/` should be modules that are specific to the domain logic of axios. These modules would most likely not make sense to be consumed outside of the axios module, as their logic is too specific. Some examples of core modules are:
4
4
 
5
5
  - Dispatching requests
6
+ - Requests sent via `adapters/` (see lib/adapters/README.md)
6
7
  - Managing interceptors
7
8
  - Handling config