You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
189 lines
6.0 KiB
189 lines
6.0 KiB
'use strict'; |
|
|
|
var utils = require('./../utils'); |
|
var settle = require('./../core/settle'); |
|
var cookies = require('./../helpers/cookies'); |
|
var buildURL = require('./../helpers/buildURL'); |
|
var buildFullPath = require('../core/buildFullPath'); |
|
var parseHeaders = require('./../helpers/parseHeaders'); |
|
var isURLSameOrigin = require('./../helpers/isURLSameOrigin'); |
|
var createError = require('../core/createError'); |
|
|
|
module.exports = function xhrAdapter(config) { |
|
return new Promise(function dispatchXhrRequest(resolve, reject) { |
|
var requestData = config.data; |
|
var requestHeaders = config.headers; |
|
var responseType = config.responseType; |
|
|
|
if (utils.isFormData(requestData)) { |
|
delete requestHeaders['Content-Type']; // Let the browser set it |
|
} |
|
|
|
var request = new XMLHttpRequest(); |
|
|
|
// HTTP basic authentication |
|
if (config.auth) { |
|
var username = config.auth.username || ''; |
|
var password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : ''; |
|
requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password); |
|
} |
|
|
|
var fullPath = buildFullPath(config.baseURL, config.url); |
|
request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true); |
|
|
|
// Set the request timeout in MS |
|
request.timeout = config.timeout; |
|
|
|
function onloadend() { |
|
if (!request) { |
|
return; |
|
} |
|
// Prepare the response |
|
var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null; |
|
var responseData = !responseType || responseType === 'text' || responseType === 'json' ? |
|
request.responseText : request.response; |
|
var response = { |
|
data: responseData, |
|
status: request.status, |
|
statusText: request.statusText, |
|
headers: responseHeaders, |
|
config: config, |
|
request: request |
|
}; |
|
|
|
settle(resolve, reject, 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.indexOf('file:') === 0)) { |
|
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(createError('Request aborted', config, 'ECONNABORTED', request)); |
|
|
|
// 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, null, request)); |
|
|
|
// Clean up request |
|
request = null; |
|
}; |
|
|
|
// Handle timeout |
|
request.ontimeout = function handleTimeout() { |
|
var timeoutErrorMessage = 'timeout of ' + config.timeout + 'ms exceeded'; |
|
if (config.timeoutErrorMessage) { |
|
timeoutErrorMessage = config.timeoutErrorMessage; |
|
} |
|
reject(createError( |
|
timeoutErrorMessage, |
|
config, |
|
config.transitional && config.transitional.clarifyTimeoutError ? 'ETIMEDOUT' : 'ECONNABORTED', |
|
request)); |
|
|
|
// 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()) { |
|
// Add xsrf header |
|
var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && 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 (!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 (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) { |
|
requestData = null; |
|
} |
|
|
|
// Send the request |
|
request.send(requestData); |
|
}); |
|
};
|
|
|