codekingpro/portable-devtools
114k
1'use strict';2 3import utils from './../utils.js';4import settle from './../core/settle.js';5import cookies from './../helpers/cookies.js';6import buildURL from './../helpers/buildURL.js';7import buildFullPath from '../core/buildFullPath.js';8import isURLSameOrigin from './../helpers/isURLSameOrigin.js';9import transitionalDefaults from '../defaults/transitional.js';10import AxiosError from '../core/AxiosError.js';11import CanceledError from '../cancel/CanceledError.js';12import parseProtocol from '../helpers/parseProtocol.js';13import platform from '../platform/index.js';14import AxiosHeaders from '../core/AxiosHeaders.js';15import speedometer from '../helpers/speedometer.js';16 17function progressEventReducer(listener, isDownloadStream) {18 let bytesNotified = 0;19 const _speedometer = speedometer(50, 250);20 21 return e => {22 const loaded = e.loaded;23 const total = e.lengthComputable ? e.total : undefined;24 const progressBytes = loaded - bytesNotified;25 const rate = _speedometer(progressBytes);26 const inRange = loaded <= total;27 28 bytesNotified = loaded;29 30 const data = {31 loaded,32 total,33 progress: total ? (loaded / total) : undefined,34 bytes: progressBytes,35 rate: rate ? rate : undefined,36 estimated: rate && total && inRange ? (total - loaded) / rate : undefined,37 event: e38 };39 40 data[isDownloadStream ? 'download' : 'upload'] = true;41 42 listener(data);43 };44}45 46const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';47 48export default isXHRAdapterSupported && function (config) {49 return new Promise(function dispatchXhrRequest(resolve, reject) {50 let requestData = config.data;51 const requestHeaders = AxiosHeaders.from(config.headers).normalize();52 let {responseType, withXSRFToken} = config;53 let onCanceled;54 function done() {55 if (config.cancelToken) {56 config.cancelToken.unsubscribe(onCanceled);57 }58 59 if (config.signal) {60 config.signal.removeEventListener('abort', onCanceled);61 }62 }63 64 let contentType;65 66 if (utils.isFormData(requestData)) {67 if (platform.hasStandardBrowserEnv || platform.hasStandardBrowserWebWorkerEnv) {68 requestHeaders.setContentType(false); // Let the browser set it69 } else if ((contentType = requestHeaders.getContentType()) !== false) {70 // fix semicolon duplication issue for ReactNative FormData implementation71 const [type, ...tokens] = contentType ? contentType.split(';').map(token => token.trim()).filter(Boolean) : [];72 requestHeaders.setContentType([type || 'multipart/form-data', ...tokens].join('; '));73 }74 }75 76 let request = new XMLHttpRequest();77 78 // HTTP basic authentication79 if (config.auth) {80 const username = config.auth.username || '';81 const password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : '';82 requestHeaders.set('Authorization', 'Basic ' + btoa(username + ':' + password));83 }84 85 const fullPath = buildFullPath(config.baseURL, config.url);86 87 request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);88 89 // Set the request timeout in MS90 request.timeout = config.timeout;91 92 function onloadend() {93 if (!request) {94 return;95 }96 // Prepare the response97 const responseHeaders = AxiosHeaders.from(98 'getAllResponseHeaders' in request && request.getAllResponseHeaders()99 );100 const responseData = !responseType || responseType === 'text' || responseType === 'json' ?101 request.responseText : request.response;102 const response = {103 data: responseData,104 status: request.status,105 statusText: request.statusText,106 headers: responseHeaders,107 config,108 request109 };110 111 settle(function _resolve(value) {112 resolve(value);113 done();114 }, function _reject(err) {115 reject(err);116 done();117 }, response);118 119 // Clean up request120 request = null;121 }122 123 if ('onloadend' in request) {124 // Use onloadend if available125 request.onloadend = onloadend;126 } else {127 // Listen for ready state to emulate onloadend128 request.onreadystatechange = function handleLoad() {129 if (!request || request.readyState !== 4) {130 return;131 }132 133 // The request errored out and we didn't get a response, this will be134 // handled by onerror instead135 // With one exception: request that using file: protocol, most browsers136 // will return status as 0 even though it's a successful request137 if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {138 return;139 }140 // readystate handler is calling before onerror or ontimeout handlers,141 // so we should call onloadend on the next 'tick'142 setTimeout(onloadend);143 };144 }145 146 // Handle browser request cancellation (as opposed to a manual cancellation)147 request.onabort = function handleAbort() {148 if (!request) {149 return;150 }151 152 reject(new AxiosError('Request aborted', AxiosError.ECONNABORTED, config, request));153 154 // Clean up request155 request = null;156 };157 158 // Handle low level network errors159 request.onerror = function handleError() {160 // Real errors are hidden from us by the browser161 // onerror should only fire if it's a network error162 reject(new AxiosError('Network Error', AxiosError.ERR_NETWORK, config, request));163 164 // Clean up request165 request = null;166 };167 168 // Handle timeout169 request.ontimeout = function handleTimeout() {170 let timeoutErrorMessage = config.timeout ? 'timeout of ' + config.timeout + 'ms exceeded' : 'timeout exceeded';171 const transitional = config.transitional || transitionalDefaults;172 if (config.timeoutErrorMessage) {173 timeoutErrorMessage = config.timeoutErrorMessage;174 }175 reject(new AxiosError(176 timeoutErrorMessage,177 transitional.clarifyTimeoutError ? AxiosError.ETIMEDOUT : AxiosError.ECONNABORTED,178 config,179 request));180 181 // Clean up request182 request = null;183 };184 185 // Add xsrf header186 // This is only done if running in a standard browser environment.187 // Specifically not if we're in a web worker, or react-native.188 if(platform.hasStandardBrowserEnv) {189 withXSRFToken && utils.isFunction(withXSRFToken) && (withXSRFToken = withXSRFToken(config));190 191 if (withXSRFToken || (withXSRFToken !== false && isURLSameOrigin(fullPath))) {192 // Add xsrf header193 const xsrfValue = config.xsrfHeaderName && config.xsrfCookieName && cookies.read(config.xsrfCookieName);194 195 if (xsrfValue) {196 requestHeaders.set(config.xsrfHeaderName, xsrfValue);197 }198 }199 }200 201 // Remove Content-Type if data is undefined202 requestData === undefined && requestHeaders.setContentType(null);203 204 // Add headers to the request205 if ('setRequestHeader' in request) {206 utils.forEach(requestHeaders.toJSON(), function setRequestHeader(val, key) {207 request.setRequestHeader(key, val);208 });209 }210 211 // Add withCredentials to request if needed212 if (!utils.isUndefined(config.withCredentials)) {213 request.withCredentials = !!config.withCredentials;214 }215 216 // Add responseType to request if needed217 if (responseType && responseType !== 'json') {218 request.responseType = config.responseType;219 }220 221 // Handle progress if needed222 if (typeof config.onDownloadProgress === 'function') {223 request.addEventListener('progress', progressEventReducer(config.onDownloadProgress, true));224 }225 226 // Not all browsers support upload events227 if (typeof config.onUploadProgress === 'function' && request.upload) {228 request.upload.addEventListener('progress', progressEventReducer(config.onUploadProgress));229 }230 231 if (config.cancelToken || config.signal) {232 // Handle cancellation233 // eslint-disable-next-line func-names234 onCanceled = cancel => {235 if (!request) {236 return;237 }238 reject(!cancel || cancel.type ? new CanceledError(null, config, request) : cancel);239 request.abort();240 request = null;241 };242 243 config.cancelToken && config.cancelToken.subscribe(onCanceled);244 if (config.signal) {245 config.signal.aborted ? onCanceled() : config.signal.addEventListener('abort', onCanceled);246 }247 }248 249 const protocol = parseProtocol(fullPath);250 251 if (protocol && platform.protocols.indexOf(protocol) === -1) {252 reject(new AxiosError('Unsupported protocol ' + protocol + ':', AxiosError.ERR_BAD_REQUEST, config));253 return;254 }255 256 257 // Send the request258 request.send(requestData || null);259 });260}261 