resolveConfig.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import platform from '../platform/index.js';
  2. import utils from '../utils.js';
  3. import AxiosError from '../core/AxiosError.js';
  4. import isURLSameOrigin from './isURLSameOrigin.js';
  5. import cookies from './cookies.js';
  6. import buildFullPath from '../core/buildFullPath.js';
  7. import mergeConfig from '../core/mergeConfig.js';
  8. import AxiosHeaders from '../core/AxiosHeaders.js';
  9. import setFormDataHeaders from '../core/setFormDataHeaders.js';
  10. import buildURL from './buildURL.js';
  11. /**
  12. * Encode a UTF-8 string to a Latin-1 byte string for use with btoa().
  13. * This is a modern replacement for the deprecated unescape(encodeURIComponent(str)) pattern.
  14. *
  15. * @param {string} str The string to encode
  16. *
  17. * @returns {string} UTF-8 bytes as a Latin-1 string
  18. */
  19. const encodeUTF8 = (str) =>
  20. encodeURIComponent(str).replace(/%([0-9A-F]{2})/gi, (_, hex) =>
  21. String.fromCharCode(parseInt(hex, 16))
  22. );
  23. function resolveConfig(config) {
  24. const newConfig = mergeConfig({}, config);
  25. // Read only own properties to prevent prototype pollution gadgets
  26. // (e.g. Object.prototype.baseURL = 'https://evil.com').
  27. const own = (key) => (utils.hasOwnProp(newConfig, key) ? newConfig[key] : undefined);
  28. const data = own('data');
  29. let withXSRFToken = own('withXSRFToken');
  30. const xsrfHeaderName = own('xsrfHeaderName');
  31. const xsrfCookieName = own('xsrfCookieName');
  32. let headers = own('headers');
  33. const auth = own('auth');
  34. const baseURL = own('baseURL');
  35. const allowAbsoluteUrls = own('allowAbsoluteUrls');
  36. const url = own('url');
  37. newConfig.headers = headers = AxiosHeaders.from(headers);
  38. newConfig.url = buildURL(
  39. buildFullPath(baseURL, url, allowAbsoluteUrls, newConfig),
  40. own('params'),
  41. own('paramsSerializer')
  42. );
  43. // HTTP basic authentication
  44. if (auth) {
  45. const username = utils.getSafeProp(auth, 'username') || '';
  46. const password = utils.getSafeProp(auth, 'password') || '';
  47. try {
  48. headers.set(
  49. 'Authorization',
  50. 'Basic ' + btoa(username + ':' + (password ? encodeUTF8(password) : ''))
  51. );
  52. } catch (e) {
  53. throw AxiosError.from(e, AxiosError.ERR_BAD_OPTION_VALUE, config);
  54. }
  55. }
  56. if (utils.isFormData(data)) {
  57. if (
  58. platform.hasStandardBrowserEnv ||
  59. platform.hasStandardBrowserWebWorkerEnv ||
  60. utils.isReactNative(data)
  61. ) {
  62. headers.setContentType(undefined); // browser/web worker/RN handles it
  63. } else if (utils.isFunction(data.getHeaders)) {
  64. // Node.js FormData (like form-data package)
  65. setFormDataHeaders(headers, data.getHeaders(), own('formDataHeaderPolicy'));
  66. }
  67. }
  68. // Add xsrf header
  69. // This is only done if running in a standard browser environment.
  70. // Specifically not if we're in a web worker, or react-native.
  71. if (platform.hasStandardBrowserEnv) {
  72. if (utils.isFunction(withXSRFToken)) {
  73. withXSRFToken = withXSRFToken(newConfig);
  74. }
  75. // Strict boolean check — prevents proto-pollution gadgets (e.g. Object.prototype.withXSRFToken = 1)
  76. // and misconfigurations (e.g. "false") from short-circuiting the same-origin check and leaking
  77. // the XSRF token cross-origin.
  78. const shouldSendXSRF =
  79. withXSRFToken === true || (withXSRFToken == null && isURLSameOrigin(newConfig.url));
  80. if (shouldSendXSRF) {
  81. const xsrfValue = xsrfHeaderName && xsrfCookieName && cookies.read(xsrfCookieName);
  82. if (xsrfValue) {
  83. headers.set(xsrfHeaderName, xsrfValue);
  84. }
  85. }
  86. }
  87. return newConfig;
  88. }
  89. export default resolveConfig;