UNPKG

axios

Version:

Promise based HTTP client for the browser and node.js

238 lines (208 loc) • 7.87 kB
'use strict'; import utils from '../utils.js'; import AxiosHeaders from './AxiosHeaders.js'; import assertParamsAcyclic from './assertParamsAcyclic.js'; const headersToObject = (thing) => (thing instanceof AxiosHeaders ? { ...thing } : thing); const ownEnumerableKeys = (thing) => { if (Object.getOwnPropertySymbols && Object.getOwnPropertyDescriptor) { return Object.keys(thing).concat( Object.getOwnPropertySymbols(thing).filter((symbol) => { const descriptor = Object.getOwnPropertyDescriptor(thing, symbol); return descriptor && descriptor.enumerable; }) ); } return Object.keys(thing); }; // Copy params without recursive merges so the serializer remains responsible // for its depth policy. Only visit defaults that contribute to the result. function mergeParams(a, b) { const pending = []; const copies = new WeakMap(); const empty = {}; function copy(target, source) { if (!utils.isPlainObject(source)) { return utils.isArray(source) ? source.slice() : source; } const base = utils.isPlainObject(target) ? target : empty; let bases = copies.get(source); if (!bases) { bases = new WeakMap(); copies.set(source, bases); } if (bases.has(base)) return bases.get(base); const result = {}; bases.set(base, result); pending.push({ base, source, result }); return result; } const result = utils.isUndefined(b) ? copy(undefined, a) : copy(a, b); while (pending.length) { const { base, source, result: target } = pending.pop(); const baseKeys = new Set(ownEnumerableKeys(base)); const sourceKeys = new Set(ownEnumerableKeys(source)); const keys = new Set([...baseKeys, ...sourceKeys]); keys.forEach((key) => { if (key === '__proto__' || key === 'constructor' || key === 'prototype') return; const hasSource = sourceKeys.has(key); const value = hasSource ? source[key] : undefined; const previous = (!hasSource || utils.isPlainObject(value)) && baseKeys.has(key) ? base[key] : undefined; target[key] = hasSource ? copy(previous, value) : copy(undefined, previous); }); } assertParamsAcyclic(result); return result; } function getMergedValue(target, source, prop, caseless) { if (utils.isPlainObject(target) && utils.isPlainObject(source)) { return utils.merge.call({ caseless }, target, source); } else if (utils.isPlainObject(source)) { return utils.merge({}, source); } else if (utils.isArray(source)) { return source.slice(); } return source; } function mergeDeepProperties(a, b, prop, caseless) { if (!utils.isUndefined(b)) { return getMergedValue(a, b, prop, caseless); } else if (!utils.isUndefined(a)) { return getMergedValue(undefined, a, prop, caseless); } } // eslint-disable-next-line consistent-return function valueFromConfig2(a, b) { if (!utils.isUndefined(b)) { return getMergedValue(undefined, b); } } // eslint-disable-next-line consistent-return function defaultToConfig2(a, b) { if (!utils.isUndefined(b)) { return getMergedValue(undefined, b); } else if (!utils.isUndefined(a)) { return getMergedValue(undefined, a); } } function getMergedTransitionalOption(config1, config2, prop) { const transitional2 = utils.hasOwnProp(config2, 'transitional') ? config2.transitional : undefined; if (!utils.isUndefined(transitional2)) { if (utils.isPlainObject(transitional2)) { if (utils.hasOwnProp(transitional2, prop)) { return transitional2[prop]; } } else { return undefined; } } const transitional1 = utils.hasOwnProp(config1, 'transitional') ? config1.transitional : undefined; if (utils.isPlainObject(transitional1) && utils.hasOwnProp(transitional1, prop)) { return transitional1[prop]; } return undefined; } // eslint-disable-next-line consistent-return function mergeDirectKeys(a, b, prop, config1, config2) { if (utils.hasOwnProp(config2, prop)) { return getMergedValue(a, b); } else if (utils.hasOwnProp(config1, prop)) { return getMergedValue(undefined, a); } } function mergeHeaders(a, b, prop) { return mergeDeepProperties(headersToObject(a), headersToObject(b), prop, true); } // Null-proto, frozen descriptor so a polluted Object.prototype.get cannot turn // this data descriptor into an accessor descriptor on the way in. // defineProperty only reads it, so one shared instance serves every call. const hasOwnPropertyDescriptor = Object.freeze({ __proto__: null, value: Object.prototype.hasOwnProperty, enumerable: false, writable: true, configurable: true, }); // The strategy table and the strategies above are stateless, so they are // built once at module load instead of on every call: mergeConfig runs at // most twice per request (once from a method alias, once from `_request`). const mergeMap = { url: valueFromConfig2, method: valueFromConfig2, data: valueFromConfig2, baseURL: defaultToConfig2, transformRequest: defaultToConfig2, transformResponse: defaultToConfig2, params: mergeParams, paramsSerializer: defaultToConfig2, timeout: defaultToConfig2, timeoutErrorMessage: defaultToConfig2, withCredentials: defaultToConfig2, withXSRFToken: defaultToConfig2, adapter: defaultToConfig2, responseType: defaultToConfig2, xsrfCookieName: defaultToConfig2, xsrfHeaderName: defaultToConfig2, onUploadProgress: defaultToConfig2, onDownloadProgress: defaultToConfig2, decompress: defaultToConfig2, maxContentLength: defaultToConfig2, maxBodyLength: defaultToConfig2, beforeRedirect: defaultToConfig2, transport: defaultToConfig2, httpAgent: defaultToConfig2, httpsAgent: defaultToConfig2, cancelToken: defaultToConfig2, socketPath: defaultToConfig2, allowedSocketPaths: defaultToConfig2, responseEncoding: defaultToConfig2, validateStatus: mergeDirectKeys, headers: mergeHeaders, }; /** * Config-specific merge-function which creates a new config-object * by merging two configuration objects together. * * @param {Object} config1 * @param {Object} config2 * * @returns {Object} New object resulting from merging config2 to config1 */ export default function mergeConfig(config1, config2) { // eslint-disable-next-line no-param-reassign config1 = config1 || {}; config2 = config2 || {}; // Use a null-prototype object so that downstream reads such as `config.auth` // or `config.baseURL` cannot inherit polluted values from Object.prototype. // `hasOwnProperty` is restored as a non-enumerable own slot to preserve // ergonomics for user code that relies on it. const config = Object.create(null); Object.defineProperty(config, 'hasOwnProperty', hasOwnPropertyDescriptor); const keys = ownEnumerableKeys({ ...config1, ...config2 }); for (let i = 0, len = keys.length; i < len; i++) { const prop = keys[i]; if (prop === '__proto__' || prop === 'constructor' || prop === 'prototype') continue; const merge = utils.hasOwnProp(mergeMap, prop) ? mergeMap[prop] : mergeDeepProperties; const a = utils.hasOwnProp(config1, prop) ? config1[prop] : undefined; const b = utils.hasOwnProp(config2, prop) ? config2[prop] : undefined; const configValue = merge === mergeDirectKeys ? merge(a, b, prop, config1, config2) : merge(a, b, prop); (utils.isUndefined(configValue) && merge !== mergeDirectKeys) || (config[prop] = configValue); } if ( utils.hasOwnProp(config2, 'validateStatus') && utils.isUndefined(config2.validateStatus) && getMergedTransitionalOption(config1, config2, 'validateStatusUndefinedResolves') === false ) { if (utils.hasOwnProp(config1, 'validateStatus')) { config.validateStatus = getMergedValue(undefined, config1.validateStatus); } else { delete config.validateStatus; } } return config; }