mirror of
https://github.com/axios/axios.git
synced 2026-04-12 02:31:57 +08:00
Compare commits
No commits in common. "v1.x" and "v1.15.0" have entirely different histories.
@ -1,5 +1,5 @@
|
||||
<h3 align="center"> 💎 Platinum sponsors <br> </h3> <table align="center"><tr><td align="center" width="50%"> <a href="https://thanks.dev/?utm_source=axios&utm_medium=sponsorlist&utm_campaign=sponsorship" style="padding: 10px; display: inline-block" target="_blank"> <img width="90px" height="90px" src="https://axios-http.com/assets/sponsors/opencollective/ed51c2ee8f1b70aa3484d6dd678652134079a036.png" alt="THANKS.DEV"/> </a> <p align="center" title="We're passionate about making open source sustainable. Scan your dependancy tree to better understand which open source projects need funding the most. Maintainers can also register their projects to become eligible for funding.">We're passionate about making open source sustainable. Scan your dependancy tree to better understand which open source projects need funding the...</p> <p align="center"> <a href="https://thanks.dev/?utm_source=axios&utm_medium=readme_sponsorlist&utm_campaign=sponsorship" target="_blank"><b>thanks.dev</b></a> </p>
|
||||
</td><td align="center" width="50%"> <a href="https://opencollective.com/hopper-security?utm_source=axios&utm_medium=sponsorlist&utm_campaign=sponsorship" style="padding: 10px; display: inline-block" target="_blank"> <img width="90px" height="90px" src="https://axios-http.com/assets/sponsors/opencollective/180d02a83ee99448f850e39eed6dbb95f56000ba.png" alt="Hopper Security"/> </a> <p align="center">Hopper provides a secure open-source registry where every component is verified against malware and continuously remediated for vulnerabilities across any version. In simple terms, Hopper removes the need to manage software supply chain risk altogether.</p><p align="center"> <a href="https://hopper.security/?utm_source=axios&utm_medium=readme_sponsorlist&utm_campaign=sponsorship" target="_blank"><b>Hopper.Security</b></a> </p>
|
||||
</td><td align="center" width="50%"> <a href="https://opencollective.com/hopper-security?utm_source=axios&utm_medium=sponsorlist&utm_campaign=sponsorship" style="padding: 10px; display: inline-block" target="_blank"> <img width="90px" height="90px" src="https://axios-http.com/assets/sponsors/opencollective/180d02a83ee99448f850e39eed6dbb95f56000ba.png" alt="Hopper Security"/> </a> <p align="center"> </p>
|
||||
</td></tr></table><table align="center"><tr><td align="center" width="50%"> <a href="https://opencollective.com/axios/contribute" target="_blank" >💜 Become a sponsor</a>
|
||||
</td><td align="center" width="50%"> <a href="https://opencollective.com/axios/contribute" target="_blank" >💜 Become a sponsor</a>
|
||||
</td></tr></table>
|
||||
|
||||
41
index.d.cts
41
index.d.cts
@ -20,8 +20,7 @@ type CommonRequestHeadersList =
|
||||
| 'Content-Length'
|
||||
| 'User-Agent'
|
||||
| 'Content-Encoding'
|
||||
| 'Authorization'
|
||||
| 'Location';
|
||||
| 'Authorization';
|
||||
|
||||
type ContentType =
|
||||
| axios.AxiosHeaderValue
|
||||
@ -39,8 +38,6 @@ type CommonResponseHeadersList =
|
||||
| 'Cache-Control'
|
||||
| 'Content-Encoding';
|
||||
|
||||
type CommonResponseHeaderKey = CommonResponseHeadersList | Lowercase<CommonResponseHeadersList>;
|
||||
|
||||
type BrowserProgressEvent = any;
|
||||
|
||||
declare class AxiosHeaders {
|
||||
@ -309,7 +306,7 @@ declare namespace axios {
|
||||
type AxiosHeaderValue = AxiosHeaders | string | string[] | number | boolean | null;
|
||||
|
||||
type RawCommonResponseHeaders = {
|
||||
[Key in CommonResponseHeaderKey]: AxiosHeaderValue;
|
||||
[Key in CommonResponseHeadersList]: AxiosHeaderValue;
|
||||
} & {
|
||||
'set-cookie': string[];
|
||||
};
|
||||
@ -347,38 +344,56 @@ declare namespace axios {
|
||||
protocol?: string;
|
||||
}
|
||||
|
||||
type UppercaseMethod =
|
||||
type Method =
|
||||
| 'get'
|
||||
| 'GET'
|
||||
| 'delete'
|
||||
| 'DELETE'
|
||||
| 'head'
|
||||
| 'HEAD'
|
||||
| 'options'
|
||||
| 'OPTIONS'
|
||||
| 'post'
|
||||
| 'POST'
|
||||
| 'put'
|
||||
| 'PUT'
|
||||
| 'patch'
|
||||
| 'PATCH'
|
||||
| 'purge'
|
||||
| 'PURGE'
|
||||
| 'link'
|
||||
| 'LINK'
|
||||
| 'unlink'
|
||||
| 'UNLINK';
|
||||
|
||||
type Method = (UppercaseMethod | Lowercase<UppercaseMethod>) & {};
|
||||
|
||||
type ResponseType = 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream' | 'formdata';
|
||||
|
||||
type UppercaseResponseEncoding =
|
||||
type responseEncoding =
|
||||
| 'ascii'
|
||||
| 'ASCII'
|
||||
| 'ansi'
|
||||
| 'ANSI'
|
||||
| 'binary'
|
||||
| 'BINARY'
|
||||
| 'base64'
|
||||
| 'BASE64'
|
||||
| 'base64url'
|
||||
| 'BASE64URL'
|
||||
| 'hex'
|
||||
| 'HEX'
|
||||
| 'latin1'
|
||||
| 'LATIN1'
|
||||
| 'ucs-2'
|
||||
| 'UCS-2'
|
||||
| 'ucs2'
|
||||
| 'UCS2'
|
||||
| 'utf-8'
|
||||
| 'UTF-8'
|
||||
| 'utf8'
|
||||
| 'UTF8'
|
||||
| 'utf16le'
|
||||
| 'UTF16LE';
|
||||
|
||||
type responseEncoding = (UppercaseResponseEncoding | Lowercase<UppercaseResponseEncoding>) & {};
|
||||
|
||||
interface TransitionalOptions {
|
||||
silentJSONParsing?: boolean;
|
||||
forcedJSONParsing?: boolean;
|
||||
@ -613,7 +628,7 @@ declare namespace axios {
|
||||
|
||||
interface AxiosInterceptorOptions {
|
||||
synchronous?: boolean;
|
||||
runWhen?: ((config: InternalAxiosRequestConfig) => boolean) | null;
|
||||
runWhen?: (config: InternalAxiosRequestConfig) => boolean;
|
||||
}
|
||||
|
||||
type AxiosInterceptorFulfilled<T> = (value: T) => T | Promise<T>;
|
||||
@ -634,7 +649,7 @@ declare namespace axios {
|
||||
fulfilled: AxiosInterceptorFulfilled<T>;
|
||||
rejected?: AxiosInterceptorRejected;
|
||||
synchronous: boolean;
|
||||
runWhen?: ((config: InternalAxiosRequestConfig) => boolean) | null;
|
||||
runWhen?: (config: AxiosRequestConfig) => boolean;
|
||||
}
|
||||
|
||||
interface AxiosInterceptorManager<V> {
|
||||
|
||||
355
index.d.ts
vendored
355
index.d.ts
vendored
@ -1,7 +1,13 @@
|
||||
// TypeScript Version: 4.7
|
||||
type StringLiteralsOrString<Literals extends string> = Literals | (string & {});
|
||||
|
||||
export type AxiosHeaderValue = AxiosHeaders | string | string[] | number | boolean | null;
|
||||
export type AxiosHeaderValue =
|
||||
| AxiosHeaders
|
||||
| string
|
||||
| string[]
|
||||
| number
|
||||
| boolean
|
||||
| null;
|
||||
|
||||
interface RawAxiosHeaders {
|
||||
[key: string]: AxiosHeaderValue;
|
||||
@ -18,7 +24,11 @@ type AxiosHeaderMatcher =
|
||||
| RegExp
|
||||
| ((this: AxiosHeaders, value: string, name: string) => boolean);
|
||||
|
||||
type AxiosHeaderParser = (this: AxiosHeaders, value: AxiosHeaderValue, header: string) => any;
|
||||
type AxiosHeaderParser = (
|
||||
this: AxiosHeaders,
|
||||
value: AxiosHeaderValue,
|
||||
header: string,
|
||||
) => any;
|
||||
|
||||
export class AxiosHeaders {
|
||||
constructor(headers?: RawAxiosHeaders | AxiosHeaders | string);
|
||||
@ -28,9 +38,12 @@ export class AxiosHeaders {
|
||||
set(
|
||||
headerName?: string,
|
||||
value?: AxiosHeaderValue,
|
||||
rewrite?: boolean | AxiosHeaderMatcher
|
||||
rewrite?: boolean | AxiosHeaderMatcher,
|
||||
): AxiosHeaders;
|
||||
set(
|
||||
headers?: RawAxiosHeaders | AxiosHeaders | string,
|
||||
rewrite?: boolean,
|
||||
): AxiosHeaders;
|
||||
set(headers?: RawAxiosHeaders | AxiosHeaders | string, rewrite?: boolean): AxiosHeaders;
|
||||
|
||||
get(headerName: string, parser: RegExp): RegExpExecArray | null;
|
||||
get(headerName: string, matcher?: true | AxiosHeaderParser): AxiosHeaderValue;
|
||||
@ -44,7 +57,9 @@ export class AxiosHeaders {
|
||||
normalize(format: boolean): AxiosHeaders;
|
||||
|
||||
concat(
|
||||
...targets: Array<AxiosHeaders | RawAxiosHeaders | string | undefined | null>
|
||||
...targets: Array<
|
||||
AxiosHeaders | RawAxiosHeaders | string | undefined | null
|
||||
>
|
||||
): AxiosHeaders;
|
||||
|
||||
toJSON(asStrings?: boolean): RawAxiosHeaders;
|
||||
@ -54,35 +69,55 @@ export class AxiosHeaders {
|
||||
static accessor(header: string | string[]): AxiosHeaders;
|
||||
|
||||
static concat(
|
||||
...targets: Array<AxiosHeaders | RawAxiosHeaders | string | undefined | null>
|
||||
...targets: Array<
|
||||
AxiosHeaders | RawAxiosHeaders | string | undefined | null
|
||||
>
|
||||
): AxiosHeaders;
|
||||
|
||||
setContentType(value: ContentType, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
|
||||
setContentType(
|
||||
value: ContentType,
|
||||
rewrite?: boolean | AxiosHeaderMatcher,
|
||||
): AxiosHeaders;
|
||||
getContentType(parser?: RegExp): RegExpExecArray | null;
|
||||
getContentType(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
|
||||
hasContentType(matcher?: AxiosHeaderMatcher): boolean;
|
||||
|
||||
setContentLength(value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
|
||||
setContentLength(
|
||||
value: AxiosHeaderValue,
|
||||
rewrite?: boolean | AxiosHeaderMatcher,
|
||||
): AxiosHeaders;
|
||||
getContentLength(parser?: RegExp): RegExpExecArray | null;
|
||||
getContentLength(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
|
||||
hasContentLength(matcher?: AxiosHeaderMatcher): boolean;
|
||||
|
||||
setAccept(value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
|
||||
setAccept(
|
||||
value: AxiosHeaderValue,
|
||||
rewrite?: boolean | AxiosHeaderMatcher,
|
||||
): AxiosHeaders;
|
||||
getAccept(parser?: RegExp): RegExpExecArray | null;
|
||||
getAccept(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
|
||||
hasAccept(matcher?: AxiosHeaderMatcher): boolean;
|
||||
|
||||
setUserAgent(value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
|
||||
setUserAgent(
|
||||
value: AxiosHeaderValue,
|
||||
rewrite?: boolean | AxiosHeaderMatcher,
|
||||
): AxiosHeaders;
|
||||
getUserAgent(parser?: RegExp): RegExpExecArray | null;
|
||||
getUserAgent(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
|
||||
hasUserAgent(matcher?: AxiosHeaderMatcher): boolean;
|
||||
|
||||
setContentEncoding(value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
|
||||
setContentEncoding(
|
||||
value: AxiosHeaderValue,
|
||||
rewrite?: boolean | AxiosHeaderMatcher,
|
||||
): AxiosHeaders;
|
||||
getContentEncoding(parser?: RegExp): RegExpExecArray | null;
|
||||
getContentEncoding(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
|
||||
hasContentEncoding(matcher?: AxiosHeaderMatcher): boolean;
|
||||
|
||||
setAuthorization(value: AxiosHeaderValue, rewrite?: boolean | AxiosHeaderMatcher): AxiosHeaders;
|
||||
setAuthorization(
|
||||
value: AxiosHeaderValue,
|
||||
rewrite?: boolean | AxiosHeaderMatcher,
|
||||
): AxiosHeaders;
|
||||
getAuthorization(parser?: RegExp): RegExpExecArray | null;
|
||||
getAuthorization(matcher?: AxiosHeaderMatcher): AxiosHeaderValue;
|
||||
hasAuthorization(matcher?: AxiosHeaderMatcher): boolean;
|
||||
@ -93,53 +128,56 @@ export class AxiosHeaders {
|
||||
}
|
||||
|
||||
type CommonRequestHeadersList =
|
||||
| 'Accept'
|
||||
| 'Content-Length'
|
||||
| 'User-Agent'
|
||||
| 'Content-Encoding'
|
||||
| 'Authorization'
|
||||
| 'Location';
|
||||
| "Accept"
|
||||
| "Content-Length"
|
||||
| "User-Agent"
|
||||
| "Content-Encoding"
|
||||
| "Authorization";
|
||||
|
||||
type ContentType =
|
||||
| AxiosHeaderValue
|
||||
| 'text/html'
|
||||
| 'text/plain'
|
||||
| 'multipart/form-data'
|
||||
| 'application/json'
|
||||
| 'application/x-www-form-urlencoded'
|
||||
| 'application/octet-stream';
|
||||
| "text/html"
|
||||
| "text/plain"
|
||||
| "multipart/form-data"
|
||||
| "application/json"
|
||||
| "application/x-www-form-urlencoded"
|
||||
| "application/octet-stream";
|
||||
|
||||
export type RawAxiosRequestHeaders = Partial<
|
||||
RawAxiosHeaders & {
|
||||
[Key in CommonRequestHeadersList]: AxiosHeaderValue;
|
||||
} & {
|
||||
'Content-Type': ContentType;
|
||||
"Content-Type": ContentType;
|
||||
}
|
||||
>;
|
||||
|
||||
export type AxiosRequestHeaders = RawAxiosRequestHeaders & AxiosHeaders;
|
||||
|
||||
type CommonResponseHeadersList =
|
||||
| 'Server'
|
||||
| 'Content-Type'
|
||||
| 'Content-Length'
|
||||
| 'Cache-Control'
|
||||
| 'Content-Encoding';
|
||||
|
||||
type CommonResponseHeaderKey = CommonResponseHeadersList | Lowercase<CommonResponseHeadersList>;
|
||||
| "Server"
|
||||
| "Content-Type"
|
||||
| "Content-Length"
|
||||
| "Cache-Control"
|
||||
| "Content-Encoding";
|
||||
|
||||
type RawCommonResponseHeaders = {
|
||||
[Key in CommonResponseHeaderKey]: AxiosHeaderValue;
|
||||
[Key in CommonResponseHeadersList]: AxiosHeaderValue;
|
||||
} & {
|
||||
'set-cookie': string[];
|
||||
"set-cookie": string[];
|
||||
};
|
||||
|
||||
export type RawAxiosResponseHeaders = Partial<RawAxiosHeaders & RawCommonResponseHeaders>;
|
||||
export type RawAxiosResponseHeaders = Partial<
|
||||
RawAxiosHeaders & RawCommonResponseHeaders
|
||||
>;
|
||||
|
||||
export type AxiosResponseHeaders = RawAxiosResponseHeaders & AxiosHeaders;
|
||||
|
||||
export interface AxiosRequestTransformer {
|
||||
(this: InternalAxiosRequestConfig, data: any, headers: AxiosRequestHeaders): any;
|
||||
(
|
||||
this: InternalAxiosRequestConfig,
|
||||
data: any,
|
||||
headers: AxiosRequestHeaders,
|
||||
): any;
|
||||
}
|
||||
|
||||
export interface AxiosResponseTransformer {
|
||||
@ -147,7 +185,7 @@ export interface AxiosResponseTransformer {
|
||||
this: InternalAxiosRequestConfig,
|
||||
data: any,
|
||||
headers: AxiosResponseHeaders,
|
||||
status?: number
|
||||
status?: number,
|
||||
): any;
|
||||
}
|
||||
|
||||
@ -233,47 +271,62 @@ export enum HttpStatusCode {
|
||||
NetworkAuthenticationRequired = 511,
|
||||
}
|
||||
|
||||
type UppercaseMethod =
|
||||
| 'GET'
|
||||
| 'DELETE'
|
||||
| 'HEAD'
|
||||
| 'OPTIONS'
|
||||
| 'POST'
|
||||
| 'PUT'
|
||||
| 'PATCH'
|
||||
| 'PURGE'
|
||||
| 'LINK'
|
||||
| 'UNLINK';
|
||||
|
||||
export type Method = (UppercaseMethod | Lowercase<UppercaseMethod>) & {};
|
||||
export type Method =
|
||||
| "get"
|
||||
| "GET"
|
||||
| "delete"
|
||||
| "DELETE"
|
||||
| "head"
|
||||
| "HEAD"
|
||||
| "options"
|
||||
| "OPTIONS"
|
||||
| "post"
|
||||
| "POST"
|
||||
| "put"
|
||||
| "PUT"
|
||||
| "patch"
|
||||
| "PATCH"
|
||||
| "purge"
|
||||
| "PURGE"
|
||||
| "link"
|
||||
| "LINK"
|
||||
| "unlink"
|
||||
| "UNLINK";
|
||||
|
||||
export type ResponseType =
|
||||
| 'arraybuffer'
|
||||
| 'blob'
|
||||
| 'document'
|
||||
| 'json'
|
||||
| 'text'
|
||||
| 'stream'
|
||||
| 'formdata';
|
||||
| "arraybuffer"
|
||||
| "blob"
|
||||
| "document"
|
||||
| "json"
|
||||
| "text"
|
||||
| "stream"
|
||||
| "formdata";
|
||||
|
||||
type UppercaseResponseEncoding =
|
||||
| 'ASCII'
|
||||
| 'ANSI'
|
||||
| 'BINARY'
|
||||
| 'BASE64'
|
||||
| 'BASE64URL'
|
||||
| 'HEX'
|
||||
| 'LATIN1'
|
||||
| 'UCS-2'
|
||||
| 'UCS2'
|
||||
| 'UTF-8'
|
||||
| 'UTF8'
|
||||
| 'UTF16LE';
|
||||
|
||||
export type responseEncoding = (
|
||||
| UppercaseResponseEncoding
|
||||
| Lowercase<UppercaseResponseEncoding>
|
||||
) & {};
|
||||
export type responseEncoding =
|
||||
| "ascii"
|
||||
| "ASCII"
|
||||
| "ansi"
|
||||
| "ANSI"
|
||||
| "binary"
|
||||
| "BINARY"
|
||||
| "base64"
|
||||
| "BASE64"
|
||||
| "base64url"
|
||||
| "BASE64URL"
|
||||
| "hex"
|
||||
| "HEX"
|
||||
| "latin1"
|
||||
| "LATIN1"
|
||||
| "ucs-2"
|
||||
| "UCS-2"
|
||||
| "ucs2"
|
||||
| "UCS2"
|
||||
| "utf-8"
|
||||
| "UTF-8"
|
||||
| "utf8"
|
||||
| "UTF8"
|
||||
| "utf16le"
|
||||
| "UTF16LE";
|
||||
|
||||
export interface TransitionalOptions {
|
||||
silentJSONParsing?: boolean;
|
||||
@ -301,7 +354,7 @@ export interface SerializerVisitor {
|
||||
value: any,
|
||||
key: string | number,
|
||||
path: null | Array<string | number>,
|
||||
helpers: FormDataVisitorHelpers
|
||||
helpers: FormDataVisitorHelpers,
|
||||
): boolean;
|
||||
}
|
||||
|
||||
@ -349,7 +402,7 @@ export interface AxiosProgressEvent {
|
||||
|
||||
type Milliseconds = number;
|
||||
|
||||
type AxiosAdapterName = StringLiteralsOrString<'xhr' | 'http' | 'fetch'>;
|
||||
type AxiosAdapterName = StringLiteralsOrString<"xhr" | "http" | "fetch">;
|
||||
|
||||
type AxiosAdapterConfig = AxiosAdapter | AxiosAdapterName;
|
||||
|
||||
@ -394,7 +447,7 @@ export interface AxiosRequestConfig<D = any> {
|
||||
responseDetails: {
|
||||
headers: Record<string, string>;
|
||||
statusCode: HttpStatusCode;
|
||||
}
|
||||
},
|
||||
) => void;
|
||||
socketPath?: string | null;
|
||||
transport?: any;
|
||||
@ -408,11 +461,24 @@ export interface AxiosRequestConfig<D = any> {
|
||||
insecureHTTPParser?: boolean;
|
||||
env?: {
|
||||
FormData?: new (...args: any[]) => object;
|
||||
fetch?: (input: URL | Request | string, init?: RequestInit) => Promise<Response>;
|
||||
Request?: new (input: URL | Request | string, init?: RequestInit) => Request;
|
||||
fetch?: (
|
||||
input: URL | Request | string,
|
||||
init?: RequestInit,
|
||||
) => Promise<Response>;
|
||||
Request?: new (
|
||||
input: URL | Request | string,
|
||||
init?: RequestInit,
|
||||
) => Request;
|
||||
Response?: new (
|
||||
body?: ArrayBuffer | ArrayBufferView | Blob | FormData | URLSearchParams | string | null,
|
||||
init?: ResponseInit
|
||||
body?:
|
||||
| ArrayBuffer
|
||||
| ArrayBufferView
|
||||
| Blob
|
||||
| FormData
|
||||
| URLSearchParams
|
||||
| string
|
||||
| null,
|
||||
init?: ResponseInit,
|
||||
) => Response;
|
||||
};
|
||||
formSerializer?: FormSerializerOptions;
|
||||
@ -424,18 +490,26 @@ export interface AxiosRequestConfig<D = any> {
|
||||
cb: (
|
||||
err: Error | null,
|
||||
address: LookupAddress | LookupAddress[],
|
||||
family?: AddressFamily
|
||||
) => void
|
||||
family?: AddressFamily,
|
||||
) => void,
|
||||
) => void)
|
||||
| ((
|
||||
hostname: string,
|
||||
options: object
|
||||
options: object,
|
||||
) => Promise<
|
||||
[address: LookupAddressEntry | LookupAddressEntry[], family?: AddressFamily] | LookupAddress
|
||||
| [
|
||||
address: LookupAddressEntry | LookupAddressEntry[],
|
||||
family?: AddressFamily,
|
||||
]
|
||||
| LookupAddress
|
||||
>);
|
||||
withXSRFToken?: boolean | ((config: InternalAxiosRequestConfig) => boolean | undefined);
|
||||
withXSRFToken?:
|
||||
| boolean
|
||||
| ((config: InternalAxiosRequestConfig) => boolean | undefined);
|
||||
parseReviver?: (this: any, key: string, value: any) => any;
|
||||
fetchOptions?: Omit<RequestInit, 'body' | 'headers' | 'method' | 'signal'> | Record<string, any>;
|
||||
fetchOptions?:
|
||||
| Omit<RequestInit, "body" | "headers" | "method" | "signal">
|
||||
| Record<string, any>;
|
||||
httpVersion?: 1 | 2;
|
||||
http2Options?: Record<string, any> & {
|
||||
sessionTimeout?: number;
|
||||
@ -445,7 +519,9 @@ export interface AxiosRequestConfig<D = any> {
|
||||
// Alias
|
||||
export type RawAxiosRequestConfig<D = any> = AxiosRequestConfig<D>;
|
||||
|
||||
export interface InternalAxiosRequestConfig<D = any> extends AxiosRequestConfig<D> {
|
||||
export interface InternalAxiosRequestConfig<
|
||||
D = any,
|
||||
> extends AxiosRequestConfig<D> {
|
||||
headers: AxiosRequestHeaders;
|
||||
}
|
||||
|
||||
@ -463,11 +539,17 @@ export interface HeadersDefaults {
|
||||
unlink?: RawAxiosRequestHeaders;
|
||||
}
|
||||
|
||||
export interface AxiosDefaults<D = any> extends Omit<AxiosRequestConfig<D>, 'headers'> {
|
||||
export interface AxiosDefaults<D = any> extends Omit<
|
||||
AxiosRequestConfig<D>,
|
||||
"headers"
|
||||
> {
|
||||
headers: HeadersDefaults;
|
||||
}
|
||||
|
||||
export interface CreateAxiosDefaults<D = any> extends Omit<AxiosRequestConfig<D>, 'headers'> {
|
||||
export interface CreateAxiosDefaults<D = any> extends Omit<
|
||||
AxiosRequestConfig<D>,
|
||||
"headers"
|
||||
> {
|
||||
headers?: RawAxiosRequestHeaders | AxiosHeaders | Partial<HeadersDefaults>;
|
||||
}
|
||||
|
||||
@ -486,7 +568,7 @@ export class AxiosError<T = unknown, D = any> extends Error {
|
||||
code?: string,
|
||||
config?: InternalAxiosRequestConfig<D>,
|
||||
request?: any,
|
||||
response?: AxiosResponse<T, D>
|
||||
response?: AxiosResponse<T, D>,
|
||||
);
|
||||
|
||||
config?: InternalAxiosRequestConfig<D>;
|
||||
@ -504,24 +586,24 @@ export class AxiosError<T = unknown, D = any> extends Error {
|
||||
config?: InternalAxiosRequestConfig<D>,
|
||||
request?: any,
|
||||
response?: AxiosResponse<T, D>,
|
||||
customProps?: object
|
||||
customProps?: object,
|
||||
): AxiosError<T, D>;
|
||||
static readonly ERR_FR_TOO_MANY_REDIRECTS = 'ERR_FR_TOO_MANY_REDIRECTS';
|
||||
static readonly ERR_BAD_OPTION_VALUE = 'ERR_BAD_OPTION_VALUE';
|
||||
static readonly ERR_BAD_OPTION = 'ERR_BAD_OPTION';
|
||||
static readonly ERR_NETWORK = 'ERR_NETWORK';
|
||||
static readonly ERR_DEPRECATED = 'ERR_DEPRECATED';
|
||||
static readonly ERR_BAD_RESPONSE = 'ERR_BAD_RESPONSE';
|
||||
static readonly ERR_BAD_REQUEST = 'ERR_BAD_REQUEST';
|
||||
static readonly ERR_NOT_SUPPORT = 'ERR_NOT_SUPPORT';
|
||||
static readonly ERR_INVALID_URL = 'ERR_INVALID_URL';
|
||||
static readonly ERR_CANCELED = 'ERR_CANCELED';
|
||||
static readonly ECONNABORTED = 'ECONNABORTED';
|
||||
static readonly ETIMEDOUT = 'ETIMEDOUT';
|
||||
static readonly ERR_FR_TOO_MANY_REDIRECTS = "ERR_FR_TOO_MANY_REDIRECTS";
|
||||
static readonly ERR_BAD_OPTION_VALUE = "ERR_BAD_OPTION_VALUE";
|
||||
static readonly ERR_BAD_OPTION = "ERR_BAD_OPTION";
|
||||
static readonly ERR_NETWORK = "ERR_NETWORK";
|
||||
static readonly ERR_DEPRECATED = "ERR_DEPRECATED";
|
||||
static readonly ERR_BAD_RESPONSE = "ERR_BAD_RESPONSE";
|
||||
static readonly ERR_BAD_REQUEST = "ERR_BAD_REQUEST";
|
||||
static readonly ERR_NOT_SUPPORT = "ERR_NOT_SUPPORT";
|
||||
static readonly ERR_INVALID_URL = "ERR_INVALID_URL";
|
||||
static readonly ERR_CANCELED = "ERR_CANCELED";
|
||||
static readonly ECONNABORTED = "ECONNABORTED";
|
||||
static readonly ETIMEDOUT = "ETIMEDOUT";
|
||||
}
|
||||
|
||||
export class CanceledError<T> extends AxiosError<T> {
|
||||
readonly name: 'CanceledError';
|
||||
readonly name: "CanceledError";
|
||||
}
|
||||
|
||||
export type AxiosPromise<T = any> = Promise<AxiosResponse<T>>;
|
||||
@ -556,7 +638,7 @@ export interface CancelTokenSource {
|
||||
|
||||
export interface AxiosInterceptorOptions {
|
||||
synchronous?: boolean;
|
||||
runWhen?: ((config: InternalAxiosRequestConfig) => boolean) | null;
|
||||
runWhen?: (config: InternalAxiosRequestConfig) => boolean;
|
||||
}
|
||||
|
||||
type AxiosInterceptorFulfilled<T> = (value: T) => T | Promise<T>;
|
||||
@ -565,23 +647,25 @@ type AxiosInterceptorRejected = (error: any) => any;
|
||||
type AxiosRequestInterceptorUse<T> = (
|
||||
onFulfilled?: AxiosInterceptorFulfilled<T> | null,
|
||||
onRejected?: AxiosInterceptorRejected | null,
|
||||
options?: AxiosInterceptorOptions
|
||||
options?: AxiosInterceptorOptions,
|
||||
) => number;
|
||||
|
||||
type AxiosResponseInterceptorUse<T> = (
|
||||
onFulfilled?: AxiosInterceptorFulfilled<T> | null,
|
||||
onRejected?: AxiosInterceptorRejected | null
|
||||
onRejected?: AxiosInterceptorRejected | null,
|
||||
) => number;
|
||||
|
||||
interface AxiosInterceptorHandler<T> {
|
||||
fulfilled: AxiosInterceptorFulfilled<T>;
|
||||
rejected?: AxiosInterceptorRejected;
|
||||
synchronous: boolean;
|
||||
runWhen?: ((config: InternalAxiosRequestConfig) => boolean) | null;
|
||||
runWhen: (config: AxiosRequestConfig) => boolean | null;
|
||||
}
|
||||
|
||||
export interface AxiosInterceptorManager<V> {
|
||||
use: V extends AxiosResponse ? AxiosResponseInterceptorUse<V> : AxiosRequestInterceptorUse<V>;
|
||||
use: V extends AxiosResponse
|
||||
? AxiosResponseInterceptorUse<V>
|
||||
: AxiosRequestInterceptorUse<V>;
|
||||
eject(id: number): void;
|
||||
clear(): void;
|
||||
handlers?: Array<AxiosInterceptorHandler<V>>;
|
||||
@ -595,61 +679,68 @@ export class Axios {
|
||||
response: AxiosInterceptorManager<AxiosResponse>;
|
||||
};
|
||||
getUri(config?: AxiosRequestConfig): string;
|
||||
request<T = any, R = AxiosResponse<T>, D = any>(config: AxiosRequestConfig<D>): Promise<R>;
|
||||
request<T = any, R = AxiosResponse<T>, D = any>(
|
||||
config: AxiosRequestConfig<D>,
|
||||
): Promise<R>;
|
||||
get<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
config?: AxiosRequestConfig<D>
|
||||
config?: AxiosRequestConfig<D>,
|
||||
): Promise<R>;
|
||||
delete<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
config?: AxiosRequestConfig<D>
|
||||
config?: AxiosRequestConfig<D>,
|
||||
): Promise<R>;
|
||||
head<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
config?: AxiosRequestConfig<D>
|
||||
config?: AxiosRequestConfig<D>,
|
||||
): Promise<R>;
|
||||
options<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
config?: AxiosRequestConfig<D>
|
||||
config?: AxiosRequestConfig<D>,
|
||||
): Promise<R>;
|
||||
post<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
data?: D,
|
||||
config?: AxiosRequestConfig<D>
|
||||
config?: AxiosRequestConfig<D>,
|
||||
): Promise<R>;
|
||||
put<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
data?: D,
|
||||
config?: AxiosRequestConfig<D>
|
||||
config?: AxiosRequestConfig<D>,
|
||||
): Promise<R>;
|
||||
patch<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
data?: D,
|
||||
config?: AxiosRequestConfig<D>
|
||||
config?: AxiosRequestConfig<D>,
|
||||
): Promise<R>;
|
||||
postForm<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
data?: D,
|
||||
config?: AxiosRequestConfig<D>
|
||||
config?: AxiosRequestConfig<D>,
|
||||
): Promise<R>;
|
||||
putForm<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
data?: D,
|
||||
config?: AxiosRequestConfig<D>
|
||||
config?: AxiosRequestConfig<D>,
|
||||
): Promise<R>;
|
||||
patchForm<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
data?: D,
|
||||
config?: AxiosRequestConfig<D>
|
||||
config?: AxiosRequestConfig<D>,
|
||||
): Promise<R>;
|
||||
}
|
||||
|
||||
export interface AxiosInstance extends Axios {
|
||||
<T = any, R = AxiosResponse<T>, D = any>(config: AxiosRequestConfig<D>): Promise<R>;
|
||||
<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
|
||||
<T = any, R = AxiosResponse<T>, D = any>(
|
||||
config: AxiosRequestConfig<D>,
|
||||
): Promise<R>;
|
||||
<T = any, R = AxiosResponse<T>, D = any>(
|
||||
url: string,
|
||||
config?: AxiosRequestConfig<D>,
|
||||
): Promise<R>;
|
||||
|
||||
create(config?: CreateAxiosDefaults): AxiosInstance;
|
||||
defaults: Omit<AxiosDefaults, 'headers'> & {
|
||||
defaults: Omit<AxiosDefaults, "headers"> & {
|
||||
headers: HeadersDefaults & {
|
||||
[key: string]: AxiosHeaderValue;
|
||||
};
|
||||
@ -667,18 +758,22 @@ export interface GenericHTMLFormElement {
|
||||
}
|
||||
|
||||
export function getAdapter(
|
||||
adapters: AxiosAdapterConfig | AxiosAdapterConfig[] | undefined
|
||||
adapters: AxiosAdapterConfig | AxiosAdapterConfig[] | undefined,
|
||||
): AxiosAdapter;
|
||||
|
||||
export function toFormData(
|
||||
sourceObj: object,
|
||||
targetFormData?: GenericFormData,
|
||||
options?: FormSerializerOptions
|
||||
options?: FormSerializerOptions,
|
||||
): GenericFormData;
|
||||
|
||||
export function formToJSON(form: GenericFormData | GenericHTMLFormElement): object;
|
||||
export function formToJSON(
|
||||
form: GenericFormData | GenericHTMLFormElement,
|
||||
): object;
|
||||
|
||||
export function isAxiosError<T = any, D = any>(payload: any): payload is AxiosError<T, D>;
|
||||
export function isAxiosError<T = any, D = any>(
|
||||
payload: any,
|
||||
): payload is AxiosError<T, D>;
|
||||
|
||||
export function spread<T, R>(callback: (...args: T[]) => R): (array: T[]) => R;
|
||||
|
||||
@ -688,7 +783,7 @@ export function all<T>(values: Array<T | Promise<T>>): Promise<T[]>;
|
||||
|
||||
export function mergeConfig<D = any>(
|
||||
config1: AxiosRequestConfig<D>,
|
||||
config2: AxiosRequestConfig<D>
|
||||
config2: AxiosRequestConfig<D>,
|
||||
): AxiosRequestConfig<D>;
|
||||
|
||||
export interface AxiosStatic extends AxiosInstance {
|
||||
|
||||
@ -221,19 +221,6 @@ const factory = (env) => {
|
||||
// see https://github.com/cloudflare/workerd/issues/902
|
||||
const isCredentialsSupported = isRequestSupported && 'credentials' in Request.prototype;
|
||||
|
||||
// If data is FormData and Content-Type is multipart/form-data without boundary,
|
||||
// delete it so fetch can set it correctly with the boundary
|
||||
if (utils.isFormData(data)) {
|
||||
const contentType = headers.getContentType();
|
||||
if (
|
||||
contentType &&
|
||||
/^multipart\/form-data/i.test(contentType) &&
|
||||
!/boundary=/i.test(contentType)
|
||||
) {
|
||||
headers.delete('content-type');
|
||||
}
|
||||
}
|
||||
|
||||
const resolvedOptions = {
|
||||
...fetchOptions,
|
||||
signal: composedSignal,
|
||||
|
||||
@ -875,21 +875,6 @@ export default isHttpAdapterSupported &&
|
||||
req.on('socket', function handleRequestSocket(socket) {
|
||||
// default interval of sending ack packet is 1 minute
|
||||
socket.setKeepAlive(true, 1000 * 60);
|
||||
|
||||
const removeSocketErrorListener = () => {
|
||||
socket.removeListener('error', handleRequestSocketError);
|
||||
};
|
||||
|
||||
function handleRequestSocketError(err) {
|
||||
removeSocketErrorListener();
|
||||
|
||||
if (!req.destroyed) {
|
||||
req.destroy(err);
|
||||
}
|
||||
}
|
||||
|
||||
socket.on('error', handleRequestSocketError);
|
||||
req.once('close', removeSocketErrorListener);
|
||||
});
|
||||
|
||||
// Handle request timeout
|
||||
|
||||
@ -5,41 +5,41 @@ import parseHeaders from '../helpers/parseHeaders.js';
|
||||
|
||||
const $internals = Symbol('internals');
|
||||
|
||||
const INVALID_HEADER_VALUE_CHARS_RE = /[^\x09\x20-\x7E\x80-\xFF]/g;
|
||||
const isValidHeaderValue = (value) => !/[\r\n]/.test(value);
|
||||
|
||||
function trimSPorHTAB(str) {
|
||||
let start = 0;
|
||||
let end = str.length;
|
||||
|
||||
while (start < end) {
|
||||
const code = str.charCodeAt(start);
|
||||
|
||||
if (code !== 0x09 && code !== 0x20) {
|
||||
break;
|
||||
}
|
||||
|
||||
start += 1;
|
||||
function assertValidHeaderValue(value, header) {
|
||||
if (value === false || value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (end > start) {
|
||||
const code = str.charCodeAt(end - 1);
|
||||
|
||||
if (code !== 0x09 && code !== 0x20) {
|
||||
break;
|
||||
}
|
||||
|
||||
end -= 1;
|
||||
if (utils.isArray(value)) {
|
||||
value.forEach((v) => assertValidHeaderValue(v, header));
|
||||
return;
|
||||
}
|
||||
|
||||
return start === 0 && end === str.length ? str : str.slice(start, end);
|
||||
if (!isValidHeaderValue(String(value))) {
|
||||
throw new Error(`Invalid character in header content ["${header}"]`);
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeHeader(header) {
|
||||
return header && String(header).trim().toLowerCase();
|
||||
}
|
||||
|
||||
function sanitizeHeaderValue(str) {
|
||||
return trimSPorHTAB(str.replace(INVALID_HEADER_VALUE_CHARS_RE, ''));
|
||||
function stripTrailingCRLF(str) {
|
||||
let end = str.length;
|
||||
|
||||
while (end > 0) {
|
||||
const charCode = str.charCodeAt(end - 1);
|
||||
|
||||
if (charCode !== 10 && charCode !== 13) {
|
||||
break;
|
||||
}
|
||||
|
||||
end -= 1;
|
||||
}
|
||||
|
||||
return end === str.length ? str : str.slice(0, end);
|
||||
}
|
||||
|
||||
function normalizeValue(value) {
|
||||
@ -47,7 +47,7 @@ function normalizeValue(value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return utils.isArray(value) ? value.map(normalizeValue) : sanitizeHeaderValue(String(value));
|
||||
return utils.isArray(value) ? value.map(normalizeValue) : stripTrailingCRLF(String(value));
|
||||
}
|
||||
|
||||
function parseTokens(str) {
|
||||
@ -129,6 +129,7 @@ class AxiosHeaders {
|
||||
_rewrite === true ||
|
||||
(_rewrite === undefined && self[key] !== false)
|
||||
) {
|
||||
assertValidHeaderValue(_value, _header);
|
||||
self[key || _header] = normalizeValue(_value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ import combineURLs from '../helpers/combineURLs.js';
|
||||
*/
|
||||
export default function buildFullPath(baseURL, requestedURL, allowAbsoluteUrls) {
|
||||
let isRelativeUrl = !isAbsoluteURL(requestedURL);
|
||||
if (baseURL && (isRelativeUrl || allowAbsoluteUrls === false)) {
|
||||
if (baseURL && (isRelativeUrl || allowAbsoluteUrls == false)) {
|
||||
return combineURLs(baseURL, requestedURL);
|
||||
}
|
||||
return requestedURL;
|
||||
|
||||
@ -58,9 +58,7 @@ function formDataToJSON(formData) {
|
||||
|
||||
if (isLast) {
|
||||
if (utils.hasOwnProp(target, name)) {
|
||||
target[name] = utils.isArray(target[name])
|
||||
? target[name].concat(value)
|
||||
: [target[name], value];
|
||||
target[name] = [target[name], value];
|
||||
} else {
|
||||
target[name] = value;
|
||||
}
|
||||
|
||||
@ -7,13 +7,13 @@ export const progressEventReducer = (listener, isDownloadStream, freq = 3) => {
|
||||
const _speedometer = speedometer(50, 250);
|
||||
|
||||
return throttle((e) => {
|
||||
const rawLoaded = e.loaded;
|
||||
const loaded = e.loaded;
|
||||
const total = e.lengthComputable ? e.total : undefined;
|
||||
const loaded = total != null ? Math.min(rawLoaded, total) : rawLoaded;
|
||||
const progressBytes = Math.max(0, loaded - bytesNotified);
|
||||
const progressBytes = loaded - bytesNotified;
|
||||
const rate = _speedometer(progressBytes);
|
||||
const inRange = loaded <= total;
|
||||
|
||||
bytesNotified = Math.max(bytesNotified, loaded);
|
||||
bytesNotified = loaded;
|
||||
|
||||
const data = {
|
||||
loaded,
|
||||
@ -21,7 +21,7 @@ export const progressEventReducer = (listener, isDownloadStream, freq = 3) => {
|
||||
progress: total ? loaded / total : undefined,
|
||||
bytes: progressBytes,
|
||||
rate: rate ? rate : undefined,
|
||||
estimated: rate && total ? (total - loaded) / rate : undefined,
|
||||
estimated: rate && total && inRange ? (total - loaded) / rate : undefined,
|
||||
event: e,
|
||||
lengthComputable: total != null,
|
||||
[isDownloadStream ? 'download' : 'upload']: true,
|
||||
|
||||
@ -1,7 +1,3 @@
|
||||
const LOOPBACK_ADDRESSES = new Set(['localhost', '127.0.0.1', '::1']);
|
||||
|
||||
const isLoopback = (host) => LOOPBACK_ADDRESSES.has(host);
|
||||
|
||||
const DEFAULT_PORTS = {
|
||||
http: 80,
|
||||
https: 443,
|
||||
@ -105,6 +101,6 @@ export default function shouldBypassProxy(location) {
|
||||
return hostname.endsWith(entryHost);
|
||||
}
|
||||
|
||||
return hostname === entryHost || (isLoopback(hostname) && isLoopback(entryHost));
|
||||
return hostname === entryHost;
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
import assert from 'assert';
|
||||
import { progressEventReducer } from '../../../lib/helpers/progressEventReducer.js';
|
||||
|
||||
describe('helpers::progressEventReducer', () => {
|
||||
it('should clamp loaded/progress and avoid negative bytes for out-of-order events', () => {
|
||||
const events = [];
|
||||
const [onProgress, flush] = progressEventReducer((data) => {
|
||||
events.push(data);
|
||||
}, false, Number.POSITIVE_INFINITY);
|
||||
|
||||
onProgress({ lengthComputable: true, loaded: 80, total: 100 });
|
||||
onProgress({ lengthComputable: true, loaded: 60, total: 100 });
|
||||
onProgress({ lengthComputable: true, loaded: 180, total: 100 });
|
||||
flush();
|
||||
|
||||
assert.strictEqual(events.length, 3);
|
||||
assert.strictEqual(events[0].bytes, 80);
|
||||
assert.strictEqual(events[1].bytes, 0);
|
||||
|
||||
const last = events[events.length - 1];
|
||||
assert.strictEqual(last.loaded, 100);
|
||||
assert.strictEqual(last.total, 100);
|
||||
assert.strictEqual(last.progress, 1);
|
||||
assert.strictEqual(last.upload, true);
|
||||
assert.strictEqual(last.bytes, 20);
|
||||
});
|
||||
});
|
||||
@ -179,19 +179,15 @@ describe('adapter (vitest browser)', () => {
|
||||
await responsePromise;
|
||||
});
|
||||
|
||||
it('should sanitize request headers containing CRLF characters', async () => {
|
||||
const responsePromise = axios('/foo', {
|
||||
headers: {
|
||||
'x-test': '\tok\r\nInjected: yes ',
|
||||
},
|
||||
});
|
||||
it('should reject request headers containing CRLF characters', async () => {
|
||||
await expect(
|
||||
axios('/foo', {
|
||||
headers: {
|
||||
'x-test': 'ok\r\nInjected: yes',
|
||||
},
|
||||
})
|
||||
).rejects.toThrow(/Invalid character in header content/);
|
||||
|
||||
const request = await waitForRequest();
|
||||
|
||||
expect(request.requestHeaders['x-test']).toBe('okInjected: yes');
|
||||
expect(request.requestHeaders.Injected).toBeUndefined();
|
||||
|
||||
request.respondWith();
|
||||
await responsePromise;
|
||||
expect(requests.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@ -26,34 +26,15 @@ const fetchAxios = axios.create({
|
||||
});
|
||||
|
||||
describe.runIf(typeof fetch === 'function')('supports fetch with nodejs', () => {
|
||||
it('should sanitize request headers containing CRLF characters', async () => {
|
||||
const server = await startHTTPServer(
|
||||
(req, res) => {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
res.end(
|
||||
JSON.stringify({
|
||||
xTest: req.headers['x-test'],
|
||||
injected: req.headers.injected ?? null,
|
||||
})
|
||||
);
|
||||
},
|
||||
{
|
||||
port: SERVER_PORT,
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
const { data } = await fetchAxios.get(`${LOCAL_SERVER_URL}/`, {
|
||||
it('should reject request headers containing CRLF characters', async () => {
|
||||
await assert.rejects(
|
||||
fetchAxios.get(`${LOCAL_SERVER_URL}/`, {
|
||||
headers: {
|
||||
'x-test': '\tok\r\nInjected: yes ',
|
||||
'x-test': 'ok\r\nInjected: yes',
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(data.xTest, 'okInjected: yes');
|
||||
assert.strictEqual(data.injected, null);
|
||||
} finally {
|
||||
await stopHTTPServer(server);
|
||||
}
|
||||
}),
|
||||
/(invalid.*header|header.*invalid)/i
|
||||
);
|
||||
});
|
||||
|
||||
describe('responses', () => {
|
||||
@ -569,54 +550,6 @@ describe.runIf(typeof fetch === 'function')('supports fetch with nodejs', () =>
|
||||
await stopHTTPServer(server);
|
||||
}
|
||||
});
|
||||
|
||||
it('should remove manually set Content-Type without boundary for FormData', async () => {
|
||||
const form = new FormData();
|
||||
form.append('foo', 'bar');
|
||||
|
||||
const server = await startHTTPServer(
|
||||
(req, res) => {
|
||||
const contentType = req.headers['content-type'];
|
||||
assert.match(contentType, /^multipart\/form-data; boundary=/i);
|
||||
res.end('OK');
|
||||
},
|
||||
{ port: SERVER_PORT }
|
||||
);
|
||||
|
||||
try {
|
||||
await fetchAxios.post(`http://localhost:${server.address().port}/form`, form, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
});
|
||||
} finally {
|
||||
await stopHTTPServer(server);
|
||||
}
|
||||
});
|
||||
|
||||
it('should preserve Content-Type if it already has boundary', async () => {
|
||||
const form = new FormData();
|
||||
form.append('foo', 'bar');
|
||||
|
||||
const customBoundary = '----CustomBoundary123';
|
||||
|
||||
const server = await startHTTPServer(
|
||||
(req, res) => {
|
||||
const contentType = req.headers['content-type'];
|
||||
assert.ok(contentType.includes(customBoundary));
|
||||
res.end('OK');
|
||||
},
|
||||
{ port: SERVER_PORT }
|
||||
);
|
||||
|
||||
try {
|
||||
await fetchAxios.post(`http://localhost:${server.address().port}/form`, form, {
|
||||
headers: {
|
||||
'Content-Type': `multipart/form-data; boundary=${customBoundary}`,
|
||||
},
|
||||
});
|
||||
} finally {
|
||||
await stopHTTPServer(server);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('env config', () => {
|
||||
|
||||
@ -29,7 +29,6 @@ import getStream from 'get-stream';
|
||||
import bodyParser from 'body-parser';
|
||||
import { AbortController } from 'abortcontroller-polyfill/dist/cjs-ponyfill.js';
|
||||
import { lookup } from 'dns';
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
const OPEN_WEB_PORT = 80;
|
||||
const SERVER_PORT = 8020;
|
||||
@ -126,32 +125,15 @@ describe('supports http with nodejs', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('should sanitize request headers containing CRLF characters', async () => {
|
||||
const server = await startHTTPServer(
|
||||
(req, res) => {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
res.end(
|
||||
JSON.stringify({
|
||||
xTest: req.headers['x-test'],
|
||||
injected: req.headers.injected ?? null,
|
||||
})
|
||||
);
|
||||
},
|
||||
{ port: SERVER_PORT }
|
||||
);
|
||||
|
||||
try {
|
||||
const { data } = await axios.get(`http://localhost:${server.address().port}/`, {
|
||||
it('should reject request headers containing CRLF characters', async () => {
|
||||
await assert.rejects(
|
||||
axios.get('http://localhost:1/', {
|
||||
headers: {
|
||||
'x-test': '\tok\r\nInjected: yes ',
|
||||
'x-test': 'ok\r\nInjected: yes',
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(data.xTest, 'okInjected: yes');
|
||||
assert.strictEqual(data.injected, null);
|
||||
} finally {
|
||||
await stopHTTPServer(server);
|
||||
}
|
||||
}),
|
||||
/Invalid character in header content/
|
||||
);
|
||||
});
|
||||
|
||||
it('should parse the timeout property', async () => {
|
||||
@ -3835,60 +3817,6 @@ describe('supports http with nodejs', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('should reject when only the request socket emits an error', async () => {
|
||||
const noop = () => {};
|
||||
const socket = new EventEmitter();
|
||||
socket.setKeepAlive = noop;
|
||||
socket.on('error', noop);
|
||||
|
||||
const transport = {
|
||||
request() {
|
||||
return new (class MockRequest extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this.destroyed = false;
|
||||
}
|
||||
|
||||
setTimeout() {}
|
||||
|
||||
write() {}
|
||||
|
||||
end() {
|
||||
this.emit('socket', socket);
|
||||
|
||||
setImmediate(() => {
|
||||
socket.emit('error', Object.assign(new Error('write EPIPE'), { code: 'EPIPE' }));
|
||||
});
|
||||
}
|
||||
|
||||
destroy(err) {
|
||||
if (this.destroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.destroyed = true;
|
||||
err && this.emit('error', err);
|
||||
this.emit('close');
|
||||
}
|
||||
})();
|
||||
},
|
||||
};
|
||||
|
||||
const error = await Promise.race([
|
||||
axios.post('http://example.com/', 'test', {
|
||||
transport,
|
||||
maxRedirects: 0,
|
||||
}),
|
||||
setTimeoutAsync(200).then(() => {
|
||||
throw new Error('socket error did not reject the request');
|
||||
}),
|
||||
]).catch((err) => err);
|
||||
|
||||
assert.ok(error instanceof AxiosError);
|
||||
assert.strictEqual(error.code, 'EPIPE');
|
||||
assert.strictEqual(error.message, 'write EPIPE');
|
||||
});
|
||||
|
||||
describe('keep-alive', () => {
|
||||
it('should not fail with "socket hang up" when using timeouts', async () => {
|
||||
const server = await startHTTPServer(
|
||||
@ -3910,66 +3838,5 @@ describe('supports http with nodejs', () => {
|
||||
await stopHTTPServer(server);
|
||||
}
|
||||
}, 15000);
|
||||
|
||||
it('should remove request socket error listeners after keep-alive requests close', async () => {
|
||||
const noop = () => {};
|
||||
const socket = new EventEmitter();
|
||||
socket.setKeepAlive = noop;
|
||||
socket.on('error', noop);
|
||||
|
||||
const baseErrorListenerCount = socket.listenerCount('error');
|
||||
|
||||
const transport = {
|
||||
request(_, cb) {
|
||||
return new (class MockRequest extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this.destroyed = false;
|
||||
}
|
||||
|
||||
setTimeout() {}
|
||||
|
||||
write() {}
|
||||
|
||||
end() {
|
||||
this.emit('socket', socket);
|
||||
|
||||
setImmediate(() => {
|
||||
const response = stream.Readable.from(['ok']);
|
||||
response.statusCode = 200;
|
||||
response.headers = {};
|
||||
|
||||
cb(response);
|
||||
this.emit('close');
|
||||
});
|
||||
}
|
||||
|
||||
destroy(err) {
|
||||
if (this.destroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.destroyed = true;
|
||||
err && this.emit('error', err);
|
||||
this.emit('close');
|
||||
}
|
||||
})();
|
||||
},
|
||||
};
|
||||
|
||||
await axios.get('http://example.com/first', {
|
||||
transport,
|
||||
maxRedirects: 0,
|
||||
});
|
||||
await setTimeoutAsync(0);
|
||||
assert.strictEqual(socket.listenerCount('error'), baseErrorListenerCount);
|
||||
|
||||
await axios.get('http://example.com/second', {
|
||||
transport,
|
||||
maxRedirects: 0,
|
||||
});
|
||||
await setTimeoutAsync(0);
|
||||
assert.strictEqual(socket.listenerCount('error'), baseErrorListenerCount);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -103,20 +103,20 @@ describe('AxiosHeaders', () => {
|
||||
}
|
||||
);
|
||||
|
||||
it('should sanitize invalid characters in header value', () => {
|
||||
it('should throw on CRLF in header value', () => {
|
||||
const headers = new AxiosHeaders();
|
||||
|
||||
headers.set('x-test', '\t safe\r\nInjected: true \u0000');
|
||||
|
||||
assert.strictEqual(headers.get('x-test'), 'safeInjected: true');
|
||||
assert.throws(() => {
|
||||
headers.set('x-test', 'safe\r\nInjected: true');
|
||||
}, /Invalid character in header content/);
|
||||
});
|
||||
|
||||
it('should sanitize invalid characters in any array header value', () => {
|
||||
it('should throw on CRLF in any array header value', () => {
|
||||
const headers = new AxiosHeaders();
|
||||
|
||||
headers.set('set-cookie', ['safe=1', ' \tunsafe=1\nInjected: true\r\n ']);
|
||||
|
||||
assert.deepStrictEqual(headers.get('set-cookie'), ['safe=1', 'unsafe=1Injected: true']);
|
||||
assert.throws(() => {
|
||||
headers.set('set-cookie', ['safe=1', 'unsafe=1\nInjected: true']);
|
||||
}, /Invalid character in header content/);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -27,32 +27,6 @@ describe('formDataToJSON', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should keep repeatable values flat for 3+ entries', () => {
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append('select3', '301');
|
||||
formData.append('select3', '302');
|
||||
formData.append('select3', '303');
|
||||
|
||||
expect(formDataToJSON(formData)).toEqual({
|
||||
select3: ['301', '302', '303'],
|
||||
});
|
||||
});
|
||||
|
||||
it('should keep nested repeatable values flat for 3+ entries', () => {
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append('foo[bar]', '1');
|
||||
formData.append('foo[bar]', '2');
|
||||
formData.append('foo[bar]', '3');
|
||||
|
||||
expect(formDataToJSON(formData)).toEqual({
|
||||
foo: {
|
||||
bar: ['1', '2', '3'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert props with empty brackets to arrays', () => {
|
||||
const formData = new FormData();
|
||||
|
||||
|
||||
@ -42,30 +42,6 @@ describe('helpers::shouldBypassProxy', () => {
|
||||
expect(shouldBypassProxy('http://[::1]:8080/')).toBe(true);
|
||||
});
|
||||
|
||||
it('should bypass proxy for 127.0.0.1 when no_proxy contains localhost', () => {
|
||||
setNoProxy('localhost');
|
||||
|
||||
expect(shouldBypassProxy('http://127.0.0.1:7777/')).toBe(true);
|
||||
});
|
||||
|
||||
it('should bypass proxy for [::1] when no_proxy contains localhost', () => {
|
||||
setNoProxy('localhost');
|
||||
|
||||
expect(shouldBypassProxy('http://[::1]:7777/')).toBe(true);
|
||||
});
|
||||
|
||||
it('should bypass proxy for localhost when no_proxy contains 127.0.0.1', () => {
|
||||
setNoProxy('127.0.0.1');
|
||||
|
||||
expect(shouldBypassProxy('http://localhost:7777/')).toBe(true);
|
||||
});
|
||||
|
||||
it('should bypass proxy for localhost when no_proxy contains ::1', () => {
|
||||
setNoProxy('::1');
|
||||
|
||||
expect(shouldBypassProxy('http://localhost:7777/')).toBe(true);
|
||||
});
|
||||
|
||||
it('should match wildcard and explicit ports', () => {
|
||||
setNoProxy('*.example.com,localhost:8080');
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user