|
'use strict'; |
|
|
|
import utils from './../utils.js'; |
|
import settle from './../core/settle.js'; |
|
import cookies from './../helpers/cookies.js'; |
|
import buildURL from './../helpers/buildURL.js'; |
|
import buildFullPath from '../core/buildFullPath.js'; |
|
import isURLSameOrigin from './../helpers/isURLSameOrigin.js'; |
|
import transitionalDefaults from '../defaults/transitional.js'; |
|
import AxiosError from '../core/AxiosError.js'; |
|
import CanceledError from '../cancel/CanceledError.js'; |
|
import parseProtocol from '../helpers/parseProtocol.js'; |
|
import platform from '../platform/index.js'; |
|
import AxiosHeaders from '../core/AxiosHeaders.js'; |
|
import speedometer from '../helpers/speedometer.js'; |
|
|
|
function progressEventReducer(listener, isDownloadStream) { |
|
let bytesNotified = 0; |
|
const _speedometer = speedometer(50, 250); |
|
|
|
return e => { |
|
const loaded = e.loaded; |
|
const total = e.lengthComputable ? e.total : undefined; |
|
const progressBytes = loaded - bytesNotified; |
|
const rate = _speedometer(progressBytes); |
|
const inRange = loaded <= total; |
|
|
|
bytesNotified = loaded; |
|
|
|
const data = { |
|
loaded, |
|
total, |
|
progress: total ? (loaded / total) : undefined, |
|
bytes: progressBytes, |
|
rate: rate ? rate : undefined, |
|
estimated: rate && total && inRange ? (total - loaded) / rate : undefined, |
|
event: e |
|
}; |
|
|
|
data[isDownloadStream ? 'download' : 'upload'] = true; |
|
|
|
listener(data); |
|
}; |
|
} |
|
|
|
const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined'; |
|
|
|
export default isXHRAdapterSupported && function (config) { |
|
return new Promise(function dispatchXhrRequest(resolve, reject) { |
|
let requestData = config.data; |
|
const requestHeaders = AxiosHeaders.from(config.headers).normalize(); |
|
let {responseType, withXSRFToken} = config; |
|
let onCanceled; |
|
function done() { |
|
if (config.cancelToken) { |
|
config.cancelToken.unsubscribe(onCanceled); |
|
} |
|
|
|
if (config.signal) { |
|
config.signal.removeEventListener('abort', onCanceled); |
|
} |
|
} |
|
|
|
let contentType; |
|
|
|
if (utils.isFormData(requestData)) { |
|
if (platform.hasStandardBrowserEnv || platform.hasStandardBrowserWebWorkerEnv) { |
|
requestHeaders.setContentType(false); |
|
} else if ((contentType = requestHeaders.getContentType()) !== false) { |
|
|
|
const [type, ...tokens] = contentType ? contentType.split(';').map(token => token.trim()).filter(Boolean) : []; |
|
requestHeaders.setContentType([type || 'multipart/form-data', ...tokens].join('; ')); |
|
} |
|
} |
|
|
|
let request = new XMLHttpRequest(); |
|
|
|
|
|
if (config.auth) { |
|
const username = config.auth.username || ''; |
|
const password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : ''; |
|
requestHeaders.set('Authorization', 'Basic ' + btoa(username + ':' + password)); |
|
} |
|
|
|
const fullPath = buildFullPath(config.baseURL, config.url); |
|
|
|
request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true); |
|
|
|
|
|
request.timeout = config.timeout; |
|
|
|
function onloadend() { |
|
if (!request) { |
|
return; |
|
} |
|
|
|
const responseHeaders = AxiosHeaders.from( |
|
'getAllResponseHeaders' in request && request.getAllResponseHeaders() |
|
); |
|
const responseData = !responseType || responseType === 'text' || responseType === 'json' ? |
|
request.responseText : request.response; |
|
const response = { |
|
data: responseData, |
|
status: request.status, |
|
statusText: request.statusText, |
|
headers: responseHeaders, |
|
config, |
|
request |
|
}; |
|
|
|
settle(function _resolve(value) { |
|
resolve(value); |
|
done(); |
|
}, function _reject(err) { |
|
reject(err); |
|
done(); |
|
}, response); |
|
|
|
|
|
request = null; |
|
} |
|
|
|
if ('onloadend' in request) { |
|
|
|
request.onloadend = onloadend; |
|
} else { |
|
|
|
request.onreadystatechange = function handleLoad() { |
|
if (!request || request.readyState !== 4) { |
|
return; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) { |
|
return; |
|
} |
|
|
|
|
|
setTimeout(onloadend); |
|
}; |
|
} |
|
|
|
|
|
request.onabort = function handleAbort() { |
|
if (!request) { |
|
return; |
|
} |
|
|
|
reject(new AxiosError('Request aborted', AxiosError.ECONNABORTED, config, request)); |
|
|
|
|
|
request = null; |
|
}; |
|
|
|
|
|
request.onerror = function handleError() { |
|
|
|
|
|
reject(new AxiosError('Network Error', AxiosError.ERR_NETWORK, config, request)); |
|
|
|
|
|
request = null; |
|
}; |
|
|
|
|
|
request.ontimeout = function handleTimeout() { |
|
let timeoutErrorMessage = config.timeout ? 'timeout of ' + config.timeout + 'ms exceeded' : 'timeout exceeded'; |
|
const transitional = config.transitional || transitionalDefaults; |
|
if (config.timeoutErrorMessage) { |
|
timeoutErrorMessage = config.timeoutErrorMessage; |
|
} |
|
reject(new AxiosError( |
|
timeoutErrorMessage, |
|
transitional.clarifyTimeoutError ? AxiosError.ETIMEDOUT : AxiosError.ECONNABORTED, |
|
config, |
|
request)); |
|
|
|
|
|
request = null; |
|
}; |
|
|
|
|
|
|
|
|
|
if(platform.hasStandardBrowserEnv) { |
|
withXSRFToken && utils.isFunction(withXSRFToken) && (withXSRFToken = withXSRFToken(config)); |
|
|
|
if (withXSRFToken || (withXSRFToken !== false && isURLSameOrigin(fullPath))) { |
|
|
|
const xsrfValue = config.xsrfHeaderName && config.xsrfCookieName && cookies.read(config.xsrfCookieName); |
|
|
|
if (xsrfValue) { |
|
requestHeaders.set(config.xsrfHeaderName, xsrfValue); |
|
} |
|
} |
|
} |
|
|
|
|
|
requestData === undefined && requestHeaders.setContentType(null); |
|
|
|
|
|
if ('setRequestHeader' in request) { |
|
utils.forEach(requestHeaders.toJSON(), function setRequestHeader(val, key) { |
|
request.setRequestHeader(key, val); |
|
}); |
|
} |
|
|
|
|
|
if (!utils.isUndefined(config.withCredentials)) { |
|
request.withCredentials = !!config.withCredentials; |
|
} |
|
|
|
|
|
if (responseType && responseType !== 'json') { |
|
request.responseType = config.responseType; |
|
} |
|
|
|
|
|
if (typeof config.onDownloadProgress === 'function') { |
|
request.addEventListener('progress', progressEventReducer(config.onDownloadProgress, true)); |
|
} |
|
|
|
|
|
if (typeof config.onUploadProgress === 'function' && request.upload) { |
|
request.upload.addEventListener('progress', progressEventReducer(config.onUploadProgress)); |
|
} |
|
|
|
if (config.cancelToken || config.signal) { |
|
|
|
|
|
onCanceled = cancel => { |
|
if (!request) { |
|
return; |
|
} |
|
reject(!cancel || cancel.type ? new CanceledError(null, config, request) : cancel); |
|
request.abort(); |
|
request = null; |
|
}; |
|
|
|
config.cancelToken && config.cancelToken.subscribe(onCanceled); |
|
if (config.signal) { |
|
config.signal.aborted ? onCanceled() : config.signal.addEventListener('abort', onCanceled); |
|
} |
|
} |
|
|
|
const protocol = parseProtocol(fullPath); |
|
|
|
if (protocol && platform.protocols.indexOf(protocol) === -1) { |
|
reject(new AxiosError('Unsupported protocol ' + protocol + ':', AxiosError.ERR_BAD_REQUEST, config)); |
|
return; |
|
} |
|
|
|
|
|
|
|
request.send(requestData || null); |
|
}); |
|
} |
|
|