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.

186 lines
5.9 KiB

  1. 'use strict';
  2. var utils = require('./../utils');
  3. var settle = require('./../core/settle');
  4. var cookies = require('./../helpers/cookies');
  5. var buildURL = require('./../helpers/buildURL');
  6. var buildFullPath = require('../core/buildFullPath');
  7. var parseHeaders = require('./../helpers/parseHeaders');
  8. var isURLSameOrigin = require('./../helpers/isURLSameOrigin');
  9. var createError = require('../core/createError');
  10. module.exports = function xhrAdapter(config) {
  11. return new Promise(function dispatchXhrRequest(resolve, reject) {
  12. var requestData = config.data;
  13. var requestHeaders = config.headers;
  14. if (utils.isFormData(requestData)) {
  15. delete requestHeaders['Content-Type']; // Let the browser set it
  16. }
  17. if (
  18. (utils.isBlob(requestData) || utils.isFile(requestData)) &&
  19. requestData.type
  20. ) {
  21. delete requestHeaders['Content-Type']; // Let the browser set it
  22. }
  23. var request = new XMLHttpRequest();
  24. // HTTP basic authentication
  25. if (config.auth) {
  26. var username = config.auth.username || '';
  27. var password = unescape(encodeURIComponent(config.auth.password)) || '';
  28. requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password);
  29. }
  30. var fullPath = buildFullPath(config.baseURL, config.url);
  31. request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
  32. // Set the request timeout in MS
  33. request.timeout = config.timeout;
  34. // Listen for ready state
  35. request.onreadystatechange = function handleLoad() {
  36. if (!request || request.readyState !== 4) {
  37. return;
  38. }
  39. // The request errored out and we didn't get a response, this will be
  40. // handled by onerror instead
  41. // With one exception: request that using file: protocol, most browsers
  42. // will return status as 0 even though it's a successful request
  43. if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {
  44. return;
  45. }
  46. // Prepare the response
  47. var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null;
  48. var responseData = !config.responseType || config.responseType === 'text' ? request.responseText : request.response;
  49. var response = {
  50. data: responseData,
  51. status: request.status,
  52. statusText: request.statusText,
  53. headers: responseHeaders,
  54. config: config,
  55. request: request
  56. };
  57. settle(resolve, reject, response);
  58. // Clean up request
  59. request = null;
  60. };
  61. // Handle browser request cancellation (as opposed to a manual cancellation)
  62. request.onabort = function handleAbort() {
  63. if (!request) {
  64. return;
  65. }
  66. reject(createError('Request aborted', config, 'ECONNABORTED', request));
  67. // Clean up request
  68. request = null;
  69. };
  70. // Handle low level network errors
  71. request.onerror = function handleError() {
  72. // Real errors are hidden from us by the browser
  73. // onerror should only fire if it's a network error
  74. reject(createError('Network Error', config, null, request));
  75. // Clean up request
  76. request = null;
  77. };
  78. // Handle timeout
  79. request.ontimeout = function handleTimeout() {
  80. var timeoutErrorMessage = 'timeout of ' + config.timeout + 'ms exceeded';
  81. if (config.timeoutErrorMessage) {
  82. timeoutErrorMessage = config.timeoutErrorMessage;
  83. }
  84. reject(createError(timeoutErrorMessage, config, 'ECONNABORTED',
  85. request));
  86. // Clean up request
  87. request = null;
  88. };
  89. // Add xsrf header
  90. // This is only done if running in a standard browser environment.
  91. // Specifically not if we're in a web worker, or react-native.
  92. if (utils.isStandardBrowserEnv()) {
  93. // Add xsrf header
  94. var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ?
  95. cookies.read(config.xsrfCookieName) :
  96. undefined;
  97. if (xsrfValue) {
  98. requestHeaders[config.xsrfHeaderName] = xsrfValue;
  99. }
  100. }
  101. // Add headers to the request
  102. if ('setRequestHeader' in request) {
  103. utils.forEach(requestHeaders, function setRequestHeader(val, key) {
  104. if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') {
  105. // Remove Content-Type if data is undefined
  106. delete requestHeaders[key];
  107. } else {
  108. // Otherwise add header to the request
  109. request.setRequestHeader(key, val);
  110. }
  111. });
  112. }
  113. // Add withCredentials to request if needed
  114. if (!utils.isUndefined(config.withCredentials)) {
  115. request.withCredentials = !!config.withCredentials;
  116. }
  117. // Add responseType to request if needed
  118. if (config.responseType) {
  119. try {
  120. request.responseType = config.responseType;
  121. } catch (e) {
  122. // Expected DOMException thrown by browsers not compatible XMLHttpRequest Level 2.
  123. // But, this can be suppressed for 'json' type as it can be parsed by default 'transformResponse' function.
  124. if (config.responseType !== 'json') {
  125. throw e;
  126. }
  127. }
  128. }
  129. // Handle progress if needed
  130. if (typeof config.onDownloadProgress === 'function') {
  131. request.addEventListener('progress', config.onDownloadProgress);
  132. }
  133. // Not all browsers support upload events
  134. if (typeof config.onUploadProgress === 'function' && request.upload) {
  135. request.upload.addEventListener('progress', config.onUploadProgress);
  136. }
  137. if (config.cancelToken) {
  138. // Handle cancellation
  139. config.cancelToken.promise.then(function onCanceled(cancel) {
  140. if (!request) {
  141. return;
  142. }
  143. request.abort();
  144. reject(cancel);
  145. // Clean up request
  146. request = null;
  147. });
  148. }
  149. if (!requestData) {
  150. requestData = null;
  151. }
  152. // Send the request
  153. request.send(requestData);
  154. });
  155. };