| 'use strict'; |
| |
| var utils = require('./../utils'); |
| var settle = require('./../core/settle'); |
| var buildURL = require('./../helpers/buildURL'); |
| var parseHeaders = require('./../helpers/parseHeaders'); |
| var isURLSameOrigin = require('./../helpers/isURLSameOrigin'); |
| var createError = require('../core/createError'); |
| var btoa = (typeof window !== 'undefined' && window.btoa && window.btoa.bind(window)) || require('./../helpers/btoa'); |
| |
| module.exports = function xhrAdapter(config) { |
| return new Promise(function dispatchXhrRequest(resolve, reject) { |
| var requestData = config.data; |
| var requestHeaders = config.headers; |
| |
| if (utils.isFormData(requestData)) { |
| delete requestHeaders['Content-Type']; // Let the browser set it |
| } |
| |
| var request = new XMLHttpRequest(); |
| var loadEvent = 'onreadystatechange'; |
| var xDomain = false; |
| |
| // For IE 8/9 CORS support |
| // Only supports POST and GET calls and doesn't returns the response headers. |
| // DON'T do this for testing b/c XMLHttpRequest is mocked, not XDomainRequest. |
| if (process.env.NODE_ENV !== 'test' && |
| typeof window !== 'undefined' && |
| window.XDomainRequest && !('withCredentials' in request) && |
| !isURLSameOrigin(config.url)) { |
| request = new window.XDomainRequest(); |
| loadEvent = 'onload'; |
| xDomain = true; |
| request.onprogress = function handleProgress() {}; |
| request.ontimeout = function handleTimeout() {}; |
| } |
| |
| // HTTP basic authentication |
| if (config.auth) { |
| var username = config.auth.username || ''; |
| var password = config.auth.password || ''; |
| requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password); |
| } |
| |
| request.open(config.method.toUpperCase(), buildURL(config.url, config.params, config.paramsSerializer), true); |
| |
| // Set the request timeout in MS |
| request.timeout = config.timeout; |
| |
| // Listen for ready state |
| request[loadEvent] = function handleLoad() { |
| if (!request || (request.readyState !== 4 && !xDomain)) { |
| return; |
| } |
| |
| // The request errored out and we didn't get a response, this will be |
| // handled by onerror instead |
| // With one exception: request that using file: protocol, most browsers |
| // will return status as 0 even though it's a successful request |
| if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) { |
| return; |
| } |
| |
| // Prepare the response |
| var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null; |
| var responseData = !config.responseType || config.responseType === 'text' ? request.responseText : request.response; |
| var response = { |
| data: responseData, |
| // IE sends 1223 instead of 204 (https://github.com/mzabriskie/axios/issues/201) |
| status: request.status === 1223 ? 204 : request.status, |
| statusText: request.status === 1223 ? 'No Content' : request.statusText, |
| headers: responseHeaders, |
| config: config, |
| request: request |
| }; |
| |
| settle(resolve, reject, response); |
| |
| // Clean up request |
| request = null; |
| }; |
| |
| // Handle low level network errors |
| request.onerror = function handleError() { |
| // Real errors are hidden from us by the browser |
| // onerror should only fire if it's a network error |
| reject(createError('Network Error', config)); |
| |
| // Clean up request |
| request = null; |
| }; |
| |
| // Handle timeout |
| request.ontimeout = function handleTimeout() { |
| reject(createError('timeout of ' + config.timeout + 'ms exceeded', config, 'ECONNABORTED')); |
| |
| // Clean up request |
| request = null; |
| }; |
| |
| // Add xsrf header |
| // This is only done if running in a standard browser environment. |
| // Specifically not if we're in a web worker, or react-native. |
| if (utils.isStandardBrowserEnv()) { |
| var cookies = require('./../helpers/cookies'); |
| |
| // Add xsrf header |
| var xsrfValue = (config.withCredentials || isURLSameOrigin(config.url)) && config.xsrfCookieName ? |
| cookies.read(config.xsrfCookieName) : |
| undefined; |
| |
| if (xsrfValue) { |
| requestHeaders[config.xsrfHeaderName] = xsrfValue; |
| } |
| } |
| |
| // Add headers to the request |
| if ('setRequestHeader' in request) { |
| utils.forEach(requestHeaders, function setRequestHeader(val, key) { |
| if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') { |
| // Remove Content-Type if data is undefined |
| delete requestHeaders[key]; |
| } else { |
| // Otherwise add header to the request |
| request.setRequestHeader(key, val); |
| } |
| }); |
| } |
| |
| // Add withCredentials to request if needed |
| if (config.withCredentials) { |
| request.withCredentials = true; |
| } |
| |
| // Add responseType to request if needed |
| if (config.responseType) { |
| try { |
| request.responseType = config.responseType; |
| } catch (e) { |
| if (request.responseType !== 'json') { |
| throw e; |
| } |
| } |
| } |
| |
| // Handle progress if needed |
| if (typeof config.onDownloadProgress === 'function') { |
| request.addEventListener('progress', config.onDownloadProgress); |
| } |
| |
| // Not all browsers support upload events |
| if (typeof config.onUploadProgress === 'function' && request.upload) { |
| request.upload.addEventListener('progress', config.onUploadProgress); |
| } |
| |
| if (config.cancelToken) { |
| // Handle cancellation |
| config.cancelToken.promise.then(function onCanceled(cancel) { |
| if (!request) { |
| return; |
| } |
| |
| request.abort(); |
| reject(cancel); |
| // Clean up request |
| request = null; |
| }); |
| } |
| |
| if (requestData === undefined) { |
| requestData = null; |
| } |
| |
| // Send the request |
| request.send(requestData); |
| }); |
| }; |