...**/!(*.map|*.min.js)Size
Gzip
Dependencies
Publish
Install
Size
Gzip
Dependencies
Publish
Install
@@ -20,7 +20,8 @@ | ||
| 20 | 20 | | 'Content-Length' |
| 21 | 21 | | 'User-Agent' |
| 22 | 22 | | 'Content-Encoding' |
| 23 | | 'Authorization'; | |
| 23 | | 'Authorization' | |
| 24 | | 'Location'; | |
| 24 | 25 | |
| 25 | 26 | type ContentType = |
| 26 | 27 | | axios.AxiosHeaderValue |
@@ -38,6 +39,8 @@ | ||
| 38 | 39 | | 'Cache-Control' |
| 39 | 40 | | 'Content-Encoding'; |
| 40 | 41 | |
| 42 | type CommonResponseHeaderKey = CommonResponseHeadersList | Lowercase<CommonResponseHeadersList>; | |
| 43 | ||
| 41 | 44 | type BrowserProgressEvent = any; |
| 42 | 45 | |
| 43 | 46 | declare class AxiosHeaders { |
@@ -157,6 +160,7 @@ | ||
| 157 | 160 | static readonly ERR_NOT_SUPPORT = 'ERR_NOT_SUPPORT'; |
| 158 | 161 | static readonly ERR_INVALID_URL = 'ERR_INVALID_URL'; |
| 159 | 162 | static readonly ERR_CANCELED = 'ERR_CANCELED'; |
| 163 | static readonly ERR_FORM_DATA_DEPTH_EXCEEDED = 'ERR_FORM_DATA_DEPTH_EXCEEDED'; | |
| 160 | 164 | static readonly ECONNABORTED = 'ECONNABORTED'; |
| 161 | 165 | static readonly ETIMEDOUT = 'ETIMEDOUT'; |
| 162 | 166 | } |
@@ -306,7 +310,7 @@ | ||
| 306 | 310 | type AxiosHeaderValue = AxiosHeaders | string | string[] | number | boolean | null; |
| 307 | 311 | |
| 308 | 312 | type RawCommonResponseHeaders = { |
| 309 | [Key in CommonResponseHeadersList]: AxiosHeaderValue; | |
| 313 | [Key in CommonResponseHeaderKey]: AxiosHeaderValue; | |
| 310 | 314 | } & { |
| 311 | 315 | 'set-cookie': string[]; |
| 312 | 316 | }; |
@@ -344,56 +348,38 @@ | ||
| 344 | 348 | protocol?: string; |
| 345 | 349 | } |
| 346 | 350 | |
| 347 | type Method = | |
| 348 | | 'get' | |
| 351 | type UppercaseMethod = | |
| 349 | 352 | | 'GET' |
| 350 | | 'delete' | |
| 351 | 353 | | 'DELETE' |
| 352 | | 'head' | |
| 353 | 354 | | 'HEAD' |
| 354 | | 'options' | |
| 355 | 355 | | 'OPTIONS' |
| 356 | | 'post' | |
| 357 | 356 | | 'POST' |
| 358 | | 'put' | |
| 359 | 357 | | 'PUT' |
| 360 | | 'patch' | |
| 361 | 358 | | 'PATCH' |
| 362 | | 'purge' | |
| 363 | 359 | | 'PURGE' |
| 364 | | 'link' | |
| 365 | 360 | | 'LINK' |
| 366 | | 'unlink' | |
| 367 | 361 | | 'UNLINK'; |
| 368 | 362 | |
| 363 | type Method = (UppercaseMethod | Lowercase<UppercaseMethod>) & {}; | |
| 364 | ||
| 369 | 365 | type ResponseType = 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream' | 'formdata'; |
| 370 | 366 | |
| 371 | type responseEncoding = | |
| 372 | | 'ascii' | |
| 367 | type UppercaseResponseEncoding = | |
| 373 | 368 | | 'ASCII' |
| 374 | | 'ansi' | |
| 375 | 369 | | 'ANSI' |
| 376 | | 'binary' | |
| 377 | 370 | | 'BINARY' |
| 378 | | 'base64' | |
| 379 | 371 | | 'BASE64' |
| 380 | | 'base64url' | |
| 381 | 372 | | 'BASE64URL' |
| 382 | | 'hex' | |
| 383 | 373 | | 'HEX' |
| 384 | | 'latin1' | |
| 385 | 374 | | 'LATIN1' |
| 386 | | 'ucs-2' | |
| 387 | 375 | | 'UCS-2' |
| 388 | | 'ucs2' | |
| 389 | 376 | | 'UCS2' |
| 390 | | 'utf-8' | |
| 391 | 377 | | 'UTF-8' |
| 392 | | 'utf8' | |
| 393 | 378 | | 'UTF8' |
| 394 | | 'utf16le' | |
| 395 | 379 | | 'UTF16LE'; |
| 396 | 380 | |
| 381 | type responseEncoding = (UppercaseResponseEncoding | Lowercase<UppercaseResponseEncoding>) & {}; | |
| 382 | ||
| 397 | 383 | interface TransitionalOptions { |
| 398 | 384 | silentJSONParsing?: boolean; |
| 399 | 385 | forcedJSONParsing?: boolean; |
@@ -628,7 +614,7 @@ | ||
| 628 | 614 | |
| 629 | 615 | interface AxiosInterceptorOptions { |
| 630 | 616 | synchronous?: boolean; |
| 631 | runWhen?: (config: InternalAxiosRequestConfig) => boolean; | |
| 617 | runWhen?: ((config: InternalAxiosRequestConfig) => boolean) | null; | |
| 632 | 618 | } |
| 633 | 619 | |
| 634 | 620 | type AxiosInterceptorFulfilled<T> = (value: T) => T | Promise<T>; |
@@ -649,7 +635,7 @@ | ||
| 649 | 635 | fulfilled: AxiosInterceptorFulfilled<T>; |
| 650 | 636 | rejected?: AxiosInterceptorRejected; |
| 651 | 637 | synchronous: boolean; |
| 652 | runWhen?: (config: AxiosRequestConfig) => boolean; | |
| 638 | runWhen?: ((config: InternalAxiosRequestConfig) => boolean) | null; | |
| 653 | 639 | } |
| 654 | 640 | |
| 655 | 641 | interface AxiosInterceptorManager<V> { |
@@ -17,40 +17,40 @@ | ||
| 17 | 17 | return axiosError; |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | /** | |
| 21 | * Create an Error with the specified message, config, error code, request and response. | |
| 22 | * | |
| 23 | * @param {string} message The error message. | |
| 24 | * @param {string} [code] The error code (for example, 'ECONNABORTED'). | |
| 25 | * @param {Object} [config] The config. | |
| 26 | * @param {Object} [request] The request. | |
| 27 | * @param {Object} [response] The response. | |
| 28 | * | |
| 29 | * @returns {Error} The created error. | |
| 30 | */ | |
| 31 | constructor(message, code, config, request, response) { | |
| 32 | super(message); | |
| 33 | ||
| 34 | // Make message enumerable to maintain backward compatibility | |
| 35 | // The native Error constructor sets message as non-enumerable, | |
| 36 | // but axios < v1.13.3 had it as enumerable | |
| 37 | Object.defineProperty(this, 'message', { | |
| 38 | value: message, | |
| 39 | enumerable: true, | |
| 40 | writable: true, | |
| 41 | configurable: true | |
| 42 | }); | |
| 43 | ||
| 44 | this.name = 'AxiosError'; | |
| 45 | this.isAxiosError = true; | |
| 46 | code && (this.code = code); | |
| 47 | config && (this.config = config); | |
| 48 | request && (this.request = request); | |
| 49 | if (response) { | |
| 50 | this.response = response; | |
| 51 | this.status = response.status; | |
| 52 | } | |
| 20 | /** | |
| 21 | * Create an Error with the specified message, config, error code, request and response. | |
| 22 | * | |
| 23 | * @param {string} message The error message. | |
| 24 | * @param {string} [code] The error code (for example, 'ECONNABORTED'). | |
| 25 | * @param {Object} [config] The config. | |
| 26 | * @param {Object} [request] The request. | |
| 27 | * @param {Object} [response] The response. | |
| 28 | * | |
| 29 | * @returns {Error} The created error. | |
| 30 | */ | |
| 31 | constructor(message, code, config, request, response) { | |
| 32 | super(message); | |
| 33 | ||
| 34 | // Make message enumerable to maintain backward compatibility | |
| 35 | // The native Error constructor sets message as non-enumerable, | |
| 36 | // but axios < v1.13.3 had it as enumerable | |
| 37 | Object.defineProperty(this, 'message', { | |
| 38 | value: message, | |
| 39 | enumerable: true, | |
| 40 | writable: true, | |
| 41 | configurable: true, | |
| 42 | }); | |
| 43 | ||
| 44 | this.name = 'AxiosError'; | |
| 45 | this.isAxiosError = true; | |
| 46 | code && (this.code = code); | |
| 47 | config && (this.config = config); | |
| 48 | request && (this.request = request); | |
| 49 | if (response) { | |
| 50 | this.response = response; | |
| 51 | this.status = response.status; | |
| 53 | 52 | } |
| 53 | } | |
| 54 | 54 | |
| 55 | 55 | toJSON() { |
| 56 | 56 | return { |
@@ -86,5 +86,6 @@ | ||
| 86 | 86 | AxiosError.ERR_CANCELED = 'ERR_CANCELED'; |
| 87 | 87 | AxiosError.ERR_NOT_SUPPORT = 'ERR_NOT_SUPPORT'; |
| 88 | 88 | AxiosError.ERR_INVALID_URL = 'ERR_INVALID_URL'; |
| 89 | AxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED = 'ERR_FORM_DATA_DEPTH_EXCEEDED'; | |
| 89 | 90 | |
| 90 | 91 | export default AxiosError; |
@@ -5,49 +5,49 @@ | ||
| 5 | 5 | |
| 6 | 6 | const $internals = Symbol('internals'); |
| 7 | 7 | |
| 8 | const isValidHeaderValue = (value) => !/[\r\n]/.test(value); | |
| 8 | const INVALID_HEADER_VALUE_CHARS_RE = /[^\x09\x20-\x7E\x80-\xFF]/g; | |
| 9 | 9 | |
| 10 | function assertValidHeaderValue(value, header) { | |
| 11 | if (value === false || value == null) { | |
| 12 | return; | |
| 13 | } | |
| 10 | function trimSPorHTAB(str) { | |
| 11 | let start = 0; | |
| 12 | let end = str.length; | |
| 14 | 13 | |
| 15 | if (utils.isArray(value)) { | |
| 16 | value.forEach((v) => assertValidHeaderValue(v, header)); | |
| 17 | return; | |
| 18 | } | |
| 14 | while (start < end) { | |
| 15 | const code = str.charCodeAt(start); | |
| 19 | 16 | |
| 20 | if (!isValidHeaderValue(String(value))) { | |
| 21 | throw new Error(`Invalid character in header content ["${header}"]`); | |
| 17 | if (code !== 0x09 && code !== 0x20) { | |
| 18 | break; | |
| 19 | } | |
| 20 | ||
| 21 | start += 1; | |
| 22 | 22 | } |
| 23 | } | |
| 24 | 23 | |
| 25 | function normalizeHeader(header) { | |
| 26 | return header && String(header).trim().toLowerCase(); | |
| 27 | } | |
| 24 | while (end > start) { | |
| 25 | const code = str.charCodeAt(end - 1); | |
| 28 | 26 | |
| 29 | function stripTrailingCRLF(str) { | |
| 30 | let end = str.length; | |
| 31 | ||
| 32 | while (end > 0) { | |
| 33 | const charCode = str.charCodeAt(end - 1); | |
| 34 | ||
| 35 | if (charCode !== 10 && charCode !== 13) { | |
| 27 | if (code !== 0x09 && code !== 0x20) { | |
| 36 | 28 | break; |
| 37 | 29 | } |
| 38 | 30 | |
| 39 | 31 | end -= 1; |
| 40 | 32 | } |
| 41 | 33 | |
| 42 | return end === str.length ? str : str.slice(0, end); | |
| 34 | return start === 0 && end === str.length ? str : str.slice(start, end); | |
| 43 | 35 | } |
| 44 | 36 | |
| 37 | function normalizeHeader(header) { | |
| 38 | return header && String(header).trim().toLowerCase(); | |
| 39 | } | |
| 40 | ||
| 41 | function sanitizeHeaderValue(str) { | |
| 42 | return trimSPorHTAB(str.replace(INVALID_HEADER_VALUE_CHARS_RE, '')); | |
| 43 | } | |
| 44 | ||
| 45 | 45 | function normalizeValue(value) { |
| 46 | 46 | if (value === false || value == null) { |
| 47 | 47 | return value; |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | return utils.isArray(value) ? value.map(normalizeValue) : stripTrailingCRLF(String(value)); | |
| 50 | return utils.isArray(value) ? value.map(normalizeValue) : sanitizeHeaderValue(String(value)); | |
| 51 | 51 | } |
| 52 | 52 | |
| 53 | 53 | function parseTokens(str) { |
@@ -129,7 +129,6 @@ | ||
| 129 | 129 | _rewrite === true || |
| 130 | 130 | (_rewrite === undefined && self[key] !== false) |
| 131 | 131 | ) { |
| 132 | assertValidHeaderValue(_value, _header); | |
| 133 | 132 | self[key || _header] = normalizeValue(_value); |
| 134 | 133 | } |
| 135 | 134 | } |
@@ -18,9 +18,8 @@ | ||
| 18 | 18 | ')': '%29', |
| 19 | 19 | '~': '%7E', |
| 20 | 20 | '%20': '+', |
| 21 | '%00': '\x00', | |
| 22 | 21 | }; |
| 23 | return encodeURIComponent(str).replace(/[!'()~]|%20|%00/g, function replacer(match) { | |
| 22 | return encodeURIComponent(str).replace(/[!'()~]|%20/g, function replacer(match) { | |
| 24 | 23 | return charMap[match]; |
| 25 | 24 | }); |
| 26 | 25 | } |
@@ -15,7 +15,7 @@ | ||
| 15 | 15 | */ |
| 16 | 16 | export default function buildFullPath(baseURL, requestedURL, allowAbsoluteUrls) { |
| 17 | 17 | let isRelativeUrl = !isAbsoluteURL(requestedURL); |
| 18 | if (baseURL && (isRelativeUrl || allowAbsoluteUrls == false)) { | |
| 18 | if (baseURL && (isRelativeUrl || allowAbsoluteUrls === false)) { | |
| 19 | 19 | return combineURLs(baseURL, requestedURL); |
| 20 | 20 | } |
| 21 | 21 | return requestedURL; |
@@ -66,19 +66,21 @@ | ||
| 66 | 66 | test(() => { |
| 67 | 67 | let duplexAccessed = false; |
| 68 | 68 | |
| 69 | const body = new ReadableStream(); | |
| 70 | ||
| 71 | const hasContentType = new Request(platform.origin, { | |
| 72 | body, | |
| 69 | const request = new Request(platform.origin, { | |
| 70 | body: new ReadableStream(), | |
| 73 | 71 | method: 'POST', |
| 74 | 72 | get duplex() { |
| 75 | 73 | duplexAccessed = true; |
| 76 | 74 | return 'half'; |
| 77 | 75 | }, |
| 78 | }).headers.has('Content-Type'); | |
| 76 | }); | |
| 79 | 77 | |
| 80 | body.cancel(); | |
| 78 | const hasContentType = request.headers.has('Content-Type'); | |
| 81 | 79 | |
| 80 | if (request.body != null) { | |
| 81 | request.body.cancel(); | |
| 82 | } | |
| 83 | ||
| 82 | 84 | return duplexAccessed && !hasContentType; |
| 83 | 85 | }); |
| 84 | 86 | |
@@ -221,6 +223,19 @@ | ||
| 221 | 223 | // see https://github.com/cloudflare/workerd/issues/902 |
| 222 | 224 | const isCredentialsSupported = isRequestSupported && 'credentials' in Request.prototype; |
| 223 | 225 | |
| 226 | // If data is FormData and Content-Type is multipart/form-data without boundary, | |
| 227 | // delete it so fetch can set it correctly with the boundary | |
| 228 | if (utils.isFormData(data)) { | |
| 229 | const contentType = headers.getContentType(); | |
| 230 | if ( | |
| 231 | contentType && | |
| 232 | /^multipart\/form-data/i.test(contentType) && | |
| 233 | !/boundary=/i.test(contentType) | |
| 234 | ) { | |
| 235 | headers.delete('content-type'); | |
| 236 | } | |
| 237 | } | |
| 238 | ||
| 224 | 239 | const resolvedOptions = { |
| 225 | 240 | ...fetchOptions, |
| 226 | 241 | signal: composedSignal, |
@@ -24,7 +24,8 @@ | ||
| 24 | 24 | if (isStringValue) { |
| 25 | 25 | value = textEncoder.encode(String(value).replace(/\r?\n|\r\n?/g, CRLF)); |
| 26 | 26 | } else { |
| 27 | headers += `Content-Type: ${value.type || 'application/octet-stream'}${CRLF}`; | |
| 27 | const safeType = String(value.type || 'application/octet-stream').replace(/[\r\n]/g, ''); | |
| 28 | headers += `Content-Type: ${safeType}${CRLF}`; | |
| 28 | 29 | } |
| 29 | 30 | |
| 30 | 31 | this.headers = textEncoder.encode(headers + CRLF); |
@@ -8,6 +8,8 @@ | ||
| 8 | 8 | import platform from '../platform/index.js'; |
| 9 | 9 | import formDataToJSON from '../helpers/formDataToJSON.js'; |
| 10 | 10 | |
| 11 | const own = (obj, key) => (obj != null && utils.hasOwnProp(obj, key) ? obj[key] : undefined); | |
| 12 | ||
| 11 | 13 | /** |
| 12 | 14 | * It takes a string, tries to parse it, and if it fails, it returns the stringified version |
| 13 | 15 | * of the input |
@@ -75,20 +77,22 @@ | ||
| 75 | 77 | let isFileList; |
| 76 | 78 | |
| 77 | 79 | if (isObjectPayload) { |
| 80 | const formSerializer = own(this, 'formSerializer'); | |
| 78 | 81 | if (contentType.indexOf('application/x-www-form-urlencoded') > -1) { |
| 79 | return toURLEncodedForm(data, this.formSerializer).toString(); | |
| 82 | return toURLEncodedForm(data, formSerializer).toString(); | |
| 80 | 83 | } |
| 81 | 84 | |
| 82 | 85 | if ( |
| 83 | 86 | (isFileList = utils.isFileList(data)) || |
| 84 | 87 | contentType.indexOf('multipart/form-data') > -1 |
| 85 | 88 | ) { |
| 86 | const _FormData = this.env && this.env.FormData; | |
| 89 | const env = own(this, 'env'); | |
| 90 | const _FormData = env && env.FormData; | |
| 87 | 91 | |
| 88 | 92 | return toFormData( |
| 89 | 93 | isFileList ? { 'files[]': data } : data, |
| 90 | 94 | _FormData && new _FormData(), |
| 91 | this.formSerializer | |
| 95 | formSerializer | |
| 92 | 96 | ); |
| 93 | 97 | } |
| 94 | 98 | } |
@@ -104,9 +108,10 @@ | ||
| 104 | 108 | |
| 105 | 109 | transformResponse: [ |
| 106 | 110 | function transformResponse(data) { |
| 107 | const transitional = this.transitional || defaults.transitional; | |
| 111 | const transitional = own(this, 'transitional') || defaults.transitional; | |
| 108 | 112 | const forcedJSONParsing = transitional && transitional.forcedJSONParsing; |
| 109 | const JSONRequested = this.responseType === 'json'; | |
| 113 | const responseType = own(this, 'responseType'); | |
| 114 | const JSONRequested = responseType === 'json'; | |
| 110 | 115 | |
| 111 | 116 | if (utils.isResponse(data) || utils.isReadableStream(data)) { |
| 112 | 117 | return data; |
@@ -115,17 +120,17 @@ | ||
| 115 | 120 | if ( |
| 116 | 121 | data && |
| 117 | 122 | utils.isString(data) && |
| 118 | ((forcedJSONParsing && !this.responseType) || JSONRequested) | |
| 123 | ((forcedJSONParsing && !responseType) || JSONRequested) | |
| 119 | 124 | ) { |
| 120 | 125 | const silentJSONParsing = transitional && transitional.silentJSONParsing; |
| 121 | 126 | const strictJSONParsing = !silentJSONParsing && JSONRequested; |
| 122 | 127 | |
| 123 | 128 | try { |
| 124 | return JSON.parse(data, this.parseReviver); | |
| 129 | return JSON.parse(data, own(this, 'parseReviver')); | |
| 125 | 130 | } catch (e) { |
| 126 | 131 | if (strictJSONParsing) { |
| 127 | 132 | if (e.name === 'SyntaxError') { |
| 128 | throw AxiosError.from(e, AxiosError.ERR_BAD_RESPONSE, this, null, this.response); | |
| 133 | throw AxiosError.from(e, AxiosError.ERR_BAD_RESPONSE, this, null, own(this, 'response')); | |
| 129 | 134 | } |
| 130 | 135 | throw e; |
| 131 | 136 | } |
@@ -56,9 +56,9 @@ | ||
| 56 | 56 | |
| 57 | 57 | // eslint-disable-next-line consistent-return |
| 58 | 58 | function mergeDirectKeys(a, b, prop) { |
| 59 | if (prop in config2) { | |
| 59 | if (utils.hasOwnProp(config2, prop)) { | |
| 60 | 60 | return getMergedValue(a, b); |
| 61 | } else if (prop in config1) { | |
| 61 | } else if (utils.hasOwnProp(config1, prop)) { | |
| 62 | 62 | return getMergedValue(undefined, a); |
| 63 | 63 | } |
| 64 | 64 | } |
@@ -99,7 +99,9 @@ | ||
| 99 | 99 | utils.forEach(Object.keys({ ...config1, ...config2 }), function computeConfigValue(prop) { |
| 100 | 100 | if (prop === '__proto__' || prop === 'constructor' || prop === 'prototype') return; |
| 101 | 101 | const merge = utils.hasOwnProp(mergeMap, prop) ? mergeMap[prop] : mergeDeepProperties; |
| 102 | const configValue = merge(config1[prop], config2[prop], prop); | |
| 102 | const a = utils.hasOwnProp(config1, prop) ? config1[prop] : undefined; | |
| 103 | const b = utils.hasOwnProp(config2, prop) ? config2[prop] : undefined; | |
| 104 | const configValue = merge(a, b, prop); | |
| 103 | 105 | (utils.isUndefined(configValue) && merge !== mergeDirectKeys) || (config[prop] = configValue); |
| 104 | 106 | }); |
| 105 | 107 | |
@@ -7,13 +7,13 @@ | ||
| 7 | 7 | const _speedometer = speedometer(50, 250); |
| 8 | 8 | |
| 9 | 9 | return throttle((e) => { |
| 10 | const loaded = e.loaded; | |
| 10 | const rawLoaded = e.loaded; | |
| 11 | 11 | const total = e.lengthComputable ? e.total : undefined; |
| 12 | const progressBytes = loaded - bytesNotified; | |
| 12 | const loaded = total != null ? Math.min(rawLoaded, total) : rawLoaded; | |
| 13 | const progressBytes = Math.max(0, loaded - bytesNotified); | |
| 13 | 14 | const rate = _speedometer(progressBytes); |
| 14 | const inRange = loaded <= total; | |
| 15 | 15 | |
| 16 | bytesNotified = loaded; | |
| 16 | bytesNotified = Math.max(bytesNotified, loaded); | |
| 17 | 17 | |
| 18 | 18 | const data = { |
| 19 | 19 | loaded, |
@@ -21,7 +21,7 @@ | ||
| 21 | 21 | progress: total ? loaded / total : undefined, |
| 22 | 22 | bytes: progressBytes, |
| 23 | 23 | rate: rate ? rate : undefined, |
| 24 | estimated: rate && total && inRange ? (total - loaded) / rate : undefined, | |
| 24 | estimated: rate && total ? (total - loaded) / rate : undefined, | |
| 25 | 25 | event: e, |
| 26 | 26 | lengthComputable: total != null, |
| 27 | 27 | [isDownloadStream ? 'download' : 'upload']: true, |
@@ -54,10 +54,18 @@ | ||
| 54 | 54 | // Specifically not if we're in a web worker, or react-native. |
| 55 | 55 | |
| 56 | 56 | if (platform.hasStandardBrowserEnv) { |
| 57 | withXSRFToken && utils.isFunction(withXSRFToken) && (withXSRFToken = withXSRFToken(newConfig)); | |
| 57 | if (utils.isFunction(withXSRFToken)) { | |
| 58 | withXSRFToken = withXSRFToken(newConfig); | |
| 59 | } | |
| 58 | 60 | |
| 59 | if (withXSRFToken || (withXSRFToken !== false && isURLSameOrigin(newConfig.url))) { | |
| 60 | // Add xsrf header | |
| 61 | // Strict boolean check — prevents proto-pollution gadgets (e.g. Object.prototype.withXSRFToken = 1) | |
| 62 | // and misconfigurations (e.g. "false") from short-circuiting the same-origin check and leaking | |
| 63 | // the XSRF token cross-origin. See GHSA-xx6v-rp6x-q39c. | |
| 64 | const shouldSendXSRF = | |
| 65 | withXSRFToken === true || | |
| 66 | (withXSRFToken == null && isURLSameOrigin(newConfig.url)); | |
| 67 | ||
| 68 | if (shouldSendXSRF) { | |
| 61 | 69 | const xsrfValue = xsrfHeaderName && xsrfCookieName && cookies.read(xsrfCookieName); |
| 62 | 70 | |
| 63 | 71 | if (xsrfValue) { |
@@ -1,3 +1,50 @@ | ||
| 1 | const LOOPBACK_HOSTNAMES = new Set(['localhost']); | |
| 2 | ||
| 3 | const isIPv4Loopback = (host) => { | |
| 4 | const parts = host.split('.'); | |
| 5 | if (parts.length !== 4) return false; | |
| 6 | if (parts[0] !== '127') return false; | |
| 7 | return parts.every((p) => /^\d+$/.test(p) && Number(p) >= 0 && Number(p) <= 255); | |
| 8 | }; | |
| 9 | ||
| 10 | const isIPv6Loopback = (host) => { | |
| 11 | // Collapse all-zero groups: any form of ::1 / 0:0:...:0:1 | |
| 12 | // First, strip any leading "::" by normalising with Set lookup of common forms, | |
| 13 | // then fall back to structural check. | |
| 14 | if (host === '::1') return true; | |
| 15 | ||
| 16 | // Check IPv4-mapped IPv6 loopback: ::ffff:<v4-loopback> or ::ffff:<hex-v4-loopback> | |
| 17 | // Node's URL parser normalises ::ffff:127.0.0.1 → ::ffff:7f00:1 | |
| 18 | const v4MappedDotted = host.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/i); | |
| 19 | if (v4MappedDotted) return isIPv4Loopback(v4MappedDotted[1]); | |
| 20 | ||
| 21 | const v4MappedHex = host.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i); | |
| 22 | if (v4MappedHex) { | |
| 23 | const high = parseInt(v4MappedHex[1], 16); | |
| 24 | // High 16 bits must start with 127 (0x7f) — i.e. 0x7f00..0x7fff | |
| 25 | return high >= 0x7f00 && high <= 0x7fff; | |
| 26 | } | |
| 27 | ||
| 28 | // Full-form ::1 variants: any number of zero groups followed by trailing 1 | |
| 29 | // e.g. 0:0:0:0:0:0:0:1, 0000:...:0001 | |
| 30 | const groups = host.split(':'); | |
| 31 | if (groups.length === 8) { | |
| 32 | for (let i = 0; i < 7; i++) { | |
| 33 | if (!/^0+$/.test(groups[i])) return false; | |
| 34 | } | |
| 35 | return /^0*1$/.test(groups[7]); | |
| 36 | } | |
| 37 | ||
| 38 | return false; | |
| 39 | }; | |
| 40 | ||
| 41 | const isLoopback = (host) => { | |
| 42 | if (!host) return false; | |
| 43 | if (LOOPBACK_HOSTNAMES.has(host)) return true; | |
| 44 | if (isIPv4Loopback(host)) return true; | |
| 45 | return isIPv6Loopback(host); | |
| 46 | }; | |
| 47 | ||
| 1 | 48 | const DEFAULT_PORTS = { |
| 2 | 49 | http: 80, |
| 3 | 50 | https: 443, |
@@ -101,6 +148,6 @@ | ||
| 101 | 148 | return hostname.endsWith(entryHost); |
| 102 | 149 | } |
| 103 | 150 | |
| 104 | return hostname === entryHost; | |
| 151 | return hostname === entryHost || (isLoopback(hostname) && isLoopback(entryHost)); | |
| 105 | 152 | }); |
| 106 | 153 | } |
@@ -115,6 +115,7 @@ | ||
| 115 | 115 | const dots = options.dots; |
| 116 | 116 | const indexes = options.indexes; |
| 117 | 117 | const _Blob = options.Blob || (typeof Blob !== 'undefined' && Blob); |
| 118 | const maxDepth = options.maxDepth === undefined ? 100 : options.maxDepth; | |
| 118 | 119 | const useBlob = _Blob && utils.isSpecCompliantForm(formData); |
| 119 | 120 | |
| 120 | 121 | if (!utils.isFunction(visitor)) { |
@@ -207,9 +208,16 @@ | ||
| 207 | 208 | isVisitable, |
| 208 | 209 | }); |
| 209 | 210 | |
| 210 | function build(value, path) { | |
| 211 | function build(value, path, depth = 0) { | |
| 211 | 212 | if (utils.isUndefined(value)) return; |
| 212 | 213 | |
| 214 | if (depth > maxDepth) { | |
| 215 | throw new AxiosError( | |
| 216 | 'Object is too deeply nested (' + depth + ' levels). Max depth: ' + maxDepth, | |
| 217 | AxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED | |
| 218 | ); | |
| 219 | } | |
| 220 | ||
| 213 | 221 | if (stack.indexOf(value) !== -1) { |
| 214 | 222 | throw Error('Circular reference detected in ' + path.join('.')); |
| 215 | 223 | } |
@@ -222,7 +230,7 @@ | ||
| 222 | 230 | visitor.call(formData, el, utils.isString(key) ? key.trim() : key, path, exposedHelpers); |
| 223 | 231 | |
| 224 | 232 | if (result === true) { |
| 225 | build(el, path ? path.concat(key) : [key]); | |
| 233 | build(el, path ? path.concat(key) : [key], depth + 1); | |
| 226 | 234 | } |
| 227 | 235 | }); |
| 228 | 236 | |
@@ -257,16 +257,16 @@ | ||
| 257 | 257 | const FormDataCtor = typeof G.FormData !== 'undefined' ? G.FormData : undefined; |
| 258 | 258 | |
| 259 | 259 | const isFormData = (thing) => { |
| 260 | let kind; | |
| 261 | return thing && ( | |
| 262 | (FormDataCtor && thing instanceof FormDataCtor) || ( | |
| 263 | isFunction(thing.append) && ( | |
| 264 | (kind = kindOf(thing)) === 'formdata' || | |
| 265 | // detect form-data instance | |
| 266 | (kind === 'object' && isFunction(thing.toString) && thing.toString() === '[object FormData]') | |
| 267 | ) | |
| 268 | ) | |
| 269 | ); | |
| 260 | if (!thing) return false; | |
| 261 | if (FormDataCtor && thing instanceof FormDataCtor) return true; | |
| 262 | // Reject plain objects inheriting directly from Object.prototype so prototype-pollution gadgets can't spoof FormData (GHSA-6chq-wfr3-2hj9). | |
| 263 | const proto = getPrototypeOf(thing); | |
| 264 | if (!proto || proto === Object.prototype) return false; | |
| 265 | if (!isFunction(thing.append)) return false; | |
| 266 | const kind = kindOf(thing); | |
| 267 | return kind === 'formdata' || | |
| 268 | // detect form-data instance | |
| 269 | (kind === 'object' && isFunction(thing.toString) && thing.toString() === '[object FormData]'); | |
| 270 | 270 | }; |
| 271 | 271 | |
| 272 | 272 | /** |
@@ -1,6 +1,6 @@ | ||
| 1 | 1 | { |
| 2 | 2 | "name": "axios", |
| 3 | "version": "1.15.0", | |
| 3 | "version": "1.15.1", | |
| 4 | 4 | "description": "Promise based HTTP client for the browser and node.js", |
| 5 | 5 | "main": "./dist/node/axios.cjs", |
| 6 | 6 | "module": "./index.js", |
@@ -82,14 +82,14 @@ | ||
| 82 | 82 | "Dmitriy Mozgovoy (https://github.com/DigitalBrainJS)", |
| 83 | 83 | "Nick Uraltsev (https://github.com/nickuraltsev)", |
| 84 | 84 | "Emily Morehouse (https://github.com/emilyemorehouse)", |
| 85 | "Justin Beckwith (https://github.com/JustinBeckwith)", | |
| 85 | 86 | "Rubén Norte (https://github.com/rubennorte)", |
| 86 | "Justin Beckwith (https://github.com/JustinBeckwith)", | |
| 87 | 87 | "Martti Laine (https://github.com/codeclown)", |
| 88 | 88 | "Xianming Zhong (https://github.com/chinesedfan)", |
| 89 | 89 | "Remco Haszing (https://github.com/remcohaszing)", |
| 90 | "Shaan Majid (https://github.com/shaanmajid)", | |
| 90 | 91 | "Willian Agostini (https://github.com/WillianAgostini)", |
| 91 | "Rikki Gibson (https://github.com/RikkiGibson)", | |
| 92 | "Ben Carp (https://github.com/carpben)" | |
| 92 | "Rikki Gibson (https://github.com/RikkiGibson)" | |
| 93 | 93 | ], |
| 94 | 94 | "sideEffects": false, |
| 95 | 95 | "license": "MIT", |