Spaces:
Running
Running
| import utils from '../utils.js'; | |
| import settle from '../core/settle.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 { progressEventReducer } from '../helpers/progressEventReducer.js'; | |
| import resolveConfig from '../helpers/resolveConfig.js'; | |
| import { toByteStringHeaderObject } from '../helpers/sanitizeHeaderValue.js'; | |
| const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined'; | |
| export default isXHRAdapterSupported && | |
| function (config) { | |
| return new Promise(function dispatchXhrRequest(resolve, reject) { | |
| const _config = resolveConfig(config); | |
| let requestData = _config.data; | |
| const requestHeaders = AxiosHeaders.from(_config.headers).normalize(); | |
| let { responseType, onUploadProgress, onDownloadProgress } = _config; | |
| let onCanceled; | |
| let uploadThrottled, downloadThrottled; | |
| let flushUpload, flushDownload; | |
| function done() { | |
| flushUpload && flushUpload(); // flush events | |
| flushDownload && flushDownload(); // flush events | |
| _config.cancelToken && _config.cancelToken.unsubscribe(onCanceled); | |
| _config.signal && _config.signal.removeEventListener('abort', onCanceled); | |
| } | |
| let request = new XMLHttpRequest(); | |
| request.open(_config.method.toUpperCase(), _config.url, true); | |
| // Set the request timeout in MS | |
| request.timeout = _config.timeout; | |
| function onloadend() { | |
| if (!request) { | |
| return; | |
| } | |
| // Prepare the response | |
| 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 | |
| ); | |
| // Clean up request | |
| request = null; | |
| } | |
| if ('onloadend' in request) { | |
| // Use onloadend if available | |
| request.onloadend = onloadend; | |
| } else { | |
| // Listen for ready state to emulate onloadend | |
| request.onreadystatechange = function handleLoad() { | |
| if (!request || request.readyState !== 4) { | |
| 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.startsWith('file:')) | |
| ) { | |
| return; | |
| } | |
| // readystate handler is calling before onerror or ontimeout handlers, | |
| // so we should call onloadend on the next 'tick' | |
| setTimeout(onloadend); | |
| }; | |
| } | |
| // Handle browser request cancellation (as opposed to a manual cancellation) | |
| request.onabort = function handleAbort() { | |
| if (!request) { | |
| return; | |
| } | |
| reject(new AxiosError('Request aborted', AxiosError.ECONNABORTED, config, request)); | |
| done(); | |
| // Clean up request | |
| request = null; | |
| }; | |
| // Handle low level network errors | |
| request.onerror = function handleError(event) { | |
| // Browsers deliver a ProgressEvent in XHR onerror | |
| // (message may be empty; when present, surface it) | |
| // See https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/error_event | |
| const msg = event && event.message ? event.message : 'Network Error'; | |
| const err = new AxiosError(msg, AxiosError.ERR_NETWORK, config, request); | |
| // attach the underlying event for consumers who want details | |
| err.event = event || null; | |
| reject(err); | |
| done(); | |
| request = null; | |
| }; | |
| // Handle timeout | |
| 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 | |
| ) | |
| ); | |
| done(); | |
| // Clean up request | |
| request = null; | |
| }; | |
| // Remove Content-Type if data is undefined | |
| requestData === undefined && requestHeaders.setContentType(null); | |
| // Add headers to the request | |
| if ('setRequestHeader' in request) { | |
| utils.forEach(toByteStringHeaderObject(requestHeaders), function setRequestHeader(val, key) { | |
| request.setRequestHeader(key, val); | |
| }); | |
| } | |
| // Add withCredentials to request if needed | |
| if (!utils.isUndefined(_config.withCredentials)) { | |
| request.withCredentials = !!_config.withCredentials; | |
| } | |
| // Add responseType to request if needed | |
| if (responseType && responseType !== 'json') { | |
| request.responseType = _config.responseType; | |
| } | |
| // Handle progress if needed | |
| if (onDownloadProgress) { | |
| [downloadThrottled, flushDownload] = progressEventReducer(onDownloadProgress, true); | |
| request.addEventListener('progress', downloadThrottled); | |
| } | |
| // Not all browsers support upload events | |
| if (onUploadProgress && request.upload) { | |
| [uploadThrottled, flushUpload] = progressEventReducer(onUploadProgress); | |
| request.upload.addEventListener('progress', uploadThrottled); | |
| request.upload.addEventListener('loadend', flushUpload); | |
| } | |
| if (_config.cancelToken || _config.signal) { | |
| // Handle cancellation | |
| // eslint-disable-next-line func-names | |
| onCanceled = (cancel) => { | |
| if (!request) { | |
| return; | |
| } | |
| reject(!cancel || cancel.type ? new CanceledError(null, config, request) : cancel); | |
| request.abort(); | |
| done(); | |
| request = null; | |
| }; | |
| _config.cancelToken && _config.cancelToken.subscribe(onCanceled); | |
| if (_config.signal) { | |
| _config.signal.aborted | |
| ? onCanceled() | |
| : _config.signal.addEventListener('abort', onCanceled); | |
| } | |
| } | |
| const protocol = parseProtocol(_config.url); | |
| if (protocol && !platform.protocols.includes(protocol)) { | |
| reject( | |
| new AxiosError( | |
| 'Unsupported protocol ' + protocol + ':', | |
| AxiosError.ERR_BAD_REQUEST, | |
| config | |
| ) | |
| ); | |
| return; | |
| } | |
| // Send the request | |
| request.send(requestData || null); | |
| }); | |
| }; | |