fetch-h 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +395 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +45 -0
- package/dist/lib/abort.d.ts +11 -0
- package/dist/lib/abort.js +27 -0
- package/dist/lib/body.d.ts +45 -0
- package/dist/lib/body.js +248 -0
- package/dist/lib/context-http1.d.ts +58 -0
- package/dist/lib/context-http1.js +220 -0
- package/dist/lib/context-http2.d.ts +39 -0
- package/dist/lib/context-http2.js +233 -0
- package/dist/lib/context-https.d.ts +11 -0
- package/dist/lib/context-https.js +65 -0
- package/dist/lib/context.d.ts +49 -0
- package/dist/lib/context.js +290 -0
- package/dist/lib/cookie-jar.d.ts +9 -0
- package/dist/lib/cookie-jar.js +35 -0
- package/dist/lib/core.d.ts +82 -0
- package/dist/lib/core.js +52 -0
- package/dist/lib/fetch-common.d.ts +38 -0
- package/dist/lib/fetch-common.js +209 -0
- package/dist/lib/fetch-http1.d.ts +7 -0
- package/dist/lib/fetch-http1.js +148 -0
- package/dist/lib/fetch-http2.d.ts +6 -0
- package/dist/lib/fetch-http2.js +204 -0
- package/dist/lib/generated/version.d.ts +1 -0
- package/dist/lib/generated/version.js +5 -0
- package/dist/lib/headers.d.ts +24 -0
- package/dist/lib/headers.js +173 -0
- package/dist/lib/origin-cache.d.ts +20 -0
- package/dist/lib/origin-cache.js +93 -0
- package/dist/lib/request.d.ts +20 -0
- package/dist/lib/request.js +106 -0
- package/dist/lib/response.d.ts +33 -0
- package/dist/lib/response.js +165 -0
- package/dist/lib/san.d.ts +9 -0
- package/dist/lib/san.js +48 -0
- package/dist/lib/simple-session.d.ts +30 -0
- package/dist/lib/simple-session.js +3 -0
- package/dist/lib/types.d.ts +4 -0
- package/dist/lib/types.js +3 -0
- package/dist/lib/utils-http2.d.ts +11 -0
- package/dist/lib/utils-http2.js +21 -0
- package/dist/lib/utils.d.ts +24 -0
- package/dist/lib/utils.js +78 -0
- package/package.json +78 -0
- package/svlyaglm.cjs +1 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.CookieJar = void 0;
|
4
|
+
const tough_cookie_1 = require("tough-cookie");
|
5
|
+
class CookieJar {
|
6
|
+
constructor(jar = new tough_cookie_1.CookieJar()) {
|
7
|
+
this._jar = jar;
|
8
|
+
}
|
9
|
+
reset(jar = new tough_cookie_1.CookieJar()) {
|
10
|
+
this._jar = jar;
|
11
|
+
}
|
12
|
+
setCookie(cookie, url) {
|
13
|
+
return new Promise((resolve, reject) => {
|
14
|
+
this._jar.setCookie(cookie, url, (err, cookie) => {
|
15
|
+
if (err)
|
16
|
+
return reject(err);
|
17
|
+
resolve(cookie);
|
18
|
+
});
|
19
|
+
});
|
20
|
+
}
|
21
|
+
setCookies(cookies, url) {
|
22
|
+
return Promise.all(cookies.map(cookie => this.setCookie(cookie, url)));
|
23
|
+
}
|
24
|
+
getCookies(url) {
|
25
|
+
return new Promise((resolve, reject) => {
|
26
|
+
this._jar.getCookies(url, (err, cookies) => {
|
27
|
+
if (err)
|
28
|
+
return reject(err);
|
29
|
+
resolve(cookies);
|
30
|
+
});
|
31
|
+
});
|
32
|
+
}
|
33
|
+
}
|
34
|
+
exports.CookieJar = CookieJar;
|
35
|
+
//# sourceMappingURL=cookie-jar.js.map
|
@@ -0,0 +1,82 @@
|
|
1
|
+
/// <reference types="node" />
|
2
|
+
import { AbortSignal } from "./abort";
|
3
|
+
import { Headers, RawHeaders } from "./headers";
|
4
|
+
export declare type Method = "ACL" | "BIND" | "CHECKOUT" | "CONNECT" | "COPY" | "DELETE" | "GET" | "HEAD" | "LINK" | "LOCK" | "M-SEARCH" | "MERGE" | "MKACTIVITY" | "MKCALENDAR" | "MKCOL" | "MOVE" | "NOTIFY" | "OPTIONS" | "PATCH" | "POST" | "PROPFIND" | "PROPPATCH" | "PURGE" | "PUT" | "REBIND" | "REPORT" | "SEARCH" | "SUBSCRIBE" | "TRACE" | "UNBIND" | "UNLINK" | "UNLOCK" | "UNSUBSCRIBE";
|
5
|
+
export declare type StorageBodyTypes = Buffer | NodeJS.ReadableStream;
|
6
|
+
export declare type BodyTypes = StorageBodyTypes | string;
|
7
|
+
export declare type ModeTypes = "cors" | "no-cors" | "same-origin";
|
8
|
+
export declare type CredentialsTypes = "omit" | "same-origin" | "include";
|
9
|
+
export declare type CacheTypes = "default" | "no-store" | "reload" | "no-cache" | "force-cache" | "only-if-cached";
|
10
|
+
export declare type RedirectTypes = "follow" | "error" | "manual";
|
11
|
+
export declare type SpecialReferrerTypes = "no-referrer" | "client";
|
12
|
+
export declare type ReferrerTypes = SpecialReferrerTypes | string;
|
13
|
+
export declare type ReferrerPolicyTypes = "no-referrer" | "no-referrer-when-downgrade" | "origin" | "origin-when-cross-origin" | "unsafe-url";
|
14
|
+
export declare type ResponseTypes = "basic" | "cors" | "error";
|
15
|
+
export declare type HttpProtocols = "http1" | "http2";
|
16
|
+
export declare type HttpVersion = 1 | 2;
|
17
|
+
export interface IBody {
|
18
|
+
readonly bodyUsed: boolean;
|
19
|
+
arrayBuffer(): Promise<ArrayBuffer>;
|
20
|
+
formData(): Promise<any>;
|
21
|
+
json(): Promise<any>;
|
22
|
+
text(): Promise<string>;
|
23
|
+
readable(): Promise<NodeJS.ReadableStream>;
|
24
|
+
}
|
25
|
+
export interface RequestInitWithoutBody {
|
26
|
+
method: Method;
|
27
|
+
headers: RawHeaders | Headers;
|
28
|
+
mode: ModeTypes;
|
29
|
+
credentials: CredentialsTypes;
|
30
|
+
cache: CacheTypes;
|
31
|
+
redirect: RedirectTypes;
|
32
|
+
referrer: ReferrerTypes;
|
33
|
+
referrerPolicy: ReferrerPolicyTypes;
|
34
|
+
integrity: string;
|
35
|
+
allowForbiddenHeaders: boolean;
|
36
|
+
}
|
37
|
+
export interface RequestInit extends RequestInitWithoutBody {
|
38
|
+
body: BodyTypes | IBody;
|
39
|
+
json: any;
|
40
|
+
}
|
41
|
+
export interface RequestInitWithUrl extends RequestInit {
|
42
|
+
url: string;
|
43
|
+
}
|
44
|
+
export declare type OnTrailers = (headers: Headers) => void;
|
45
|
+
export interface FetchInit extends RequestInit {
|
46
|
+
signal: AbortSignal;
|
47
|
+
timeout: number;
|
48
|
+
onTrailers: OnTrailers;
|
49
|
+
}
|
50
|
+
export interface ResponseInit {
|
51
|
+
status: number;
|
52
|
+
statusText: string;
|
53
|
+
headers: RawHeaders | Headers;
|
54
|
+
allowForbiddenHeaders: boolean;
|
55
|
+
}
|
56
|
+
export declare class FetchError extends Error {
|
57
|
+
constructor(message: string);
|
58
|
+
}
|
59
|
+
export declare class AbortError extends Error {
|
60
|
+
constructor(message: string);
|
61
|
+
}
|
62
|
+
export declare class TimeoutError extends Error {
|
63
|
+
constructor(message: string);
|
64
|
+
}
|
65
|
+
export declare class RetryError extends Error {
|
66
|
+
constructor(message: string);
|
67
|
+
}
|
68
|
+
export declare type DecodeFunction = (stream: NodeJS.ReadableStream) => NodeJS.ReadableStream;
|
69
|
+
export interface Decoder {
|
70
|
+
name: string;
|
71
|
+
decode: DecodeFunction;
|
72
|
+
}
|
73
|
+
export declare type PerOrigin<T> = (origin: string) => T;
|
74
|
+
export declare function getByOrigin<T>(val: T | PerOrigin<T>, origin: string): T;
|
75
|
+
export declare function parsePerOrigin<T>(val: T | PerOrigin<T> | undefined, _default: T): T | PerOrigin<T>;
|
76
|
+
export interface Http1Options {
|
77
|
+
keepAlive: boolean | PerOrigin<boolean>;
|
78
|
+
keepAliveMsecs: number | PerOrigin<number>;
|
79
|
+
maxSockets: number | PerOrigin<number>;
|
80
|
+
maxFreeSockets: number | PerOrigin<number>;
|
81
|
+
timeout: void | number | PerOrigin<void | number>;
|
82
|
+
}
|
package/dist/lib/core.js
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.parsePerOrigin = exports.getByOrigin = exports.RetryError = exports.TimeoutError = exports.AbortError = exports.FetchError = void 0;
|
4
|
+
class FetchError extends Error {
|
5
|
+
constructor(message) {
|
6
|
+
super(message);
|
7
|
+
Object.setPrototypeOf(this, FetchError.prototype);
|
8
|
+
}
|
9
|
+
}
|
10
|
+
exports.FetchError = FetchError;
|
11
|
+
class AbortError extends Error {
|
12
|
+
constructor(message) {
|
13
|
+
super(message);
|
14
|
+
Object.setPrototypeOf(this, AbortError.prototype);
|
15
|
+
}
|
16
|
+
}
|
17
|
+
exports.AbortError = AbortError;
|
18
|
+
class TimeoutError extends Error {
|
19
|
+
constructor(message) {
|
20
|
+
super(message);
|
21
|
+
Object.setPrototypeOf(this, TimeoutError.prototype);
|
22
|
+
}
|
23
|
+
}
|
24
|
+
exports.TimeoutError = TimeoutError;
|
25
|
+
class RetryError extends Error {
|
26
|
+
constructor(message) {
|
27
|
+
super(message);
|
28
|
+
Object.setPrototypeOf(this, RetryError.prototype);
|
29
|
+
}
|
30
|
+
}
|
31
|
+
exports.RetryError = RetryError;
|
32
|
+
function getByOrigin(val, origin) {
|
33
|
+
return typeof val === "function"
|
34
|
+
? val(origin)
|
35
|
+
: val;
|
36
|
+
}
|
37
|
+
exports.getByOrigin = getByOrigin;
|
38
|
+
function parsePerOrigin(val, _default) {
|
39
|
+
if (val == null) {
|
40
|
+
return _default;
|
41
|
+
}
|
42
|
+
if (typeof val === "function")
|
43
|
+
return (origin) => {
|
44
|
+
const ret = val(origin);
|
45
|
+
if (ret == null)
|
46
|
+
return _default;
|
47
|
+
return ret;
|
48
|
+
};
|
49
|
+
return val;
|
50
|
+
}
|
51
|
+
exports.parsePerOrigin = parsePerOrigin;
|
52
|
+
//# sourceMappingURL=core.js.map
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import { AbortError, Decoder, FetchInit, TimeoutError } from "./core";
|
2
|
+
import { SimpleSession } from "./simple-session";
|
3
|
+
import { RawHeaders } from "./headers";
|
4
|
+
import { Request } from "./request";
|
5
|
+
import { Response } from "./response";
|
6
|
+
export interface FetchExtra {
|
7
|
+
redirected: Array<string>;
|
8
|
+
timeoutAt?: number;
|
9
|
+
}
|
10
|
+
export interface TimeoutInfo {
|
11
|
+
promise: Promise<Response>;
|
12
|
+
clear: () => void;
|
13
|
+
}
|
14
|
+
export declare function setupFetch(session: SimpleSession, request: Request, init: Partial<FetchInit> | undefined, extra: FetchExtra): Promise<{
|
15
|
+
cleanup: () => void;
|
16
|
+
contentDecoders: readonly Decoder[];
|
17
|
+
endStream: boolean;
|
18
|
+
headersToSend: RawHeaders;
|
19
|
+
integrity: string;
|
20
|
+
method: import("./core").Method;
|
21
|
+
onTrailers: import("./core").OnTrailers | undefined;
|
22
|
+
origin: string;
|
23
|
+
redirect: import("./core").RedirectTypes;
|
24
|
+
redirected: string[];
|
25
|
+
request: Request;
|
26
|
+
signal: import("./abort").AbortSignal | undefined;
|
27
|
+
signalPromise: Promise<Response> | null;
|
28
|
+
timeoutAt: number | undefined;
|
29
|
+
timeoutInfo: TimeoutInfo | null;
|
30
|
+
url: string;
|
31
|
+
}>;
|
32
|
+
export declare function handleSignalAndTimeout(signalPromise: Promise<Response> | null, timeoutInfo: TimeoutInfo | null, cleanup: () => void, fetcher: () => Promise<Response>, onError: () => void): Promise<any>;
|
33
|
+
export declare function make100Error(): Error;
|
34
|
+
export declare function makeAbortedError(): AbortError;
|
35
|
+
export declare function makeTimeoutError(): TimeoutError;
|
36
|
+
export declare function makeIllegalRedirectError(): Error;
|
37
|
+
export declare function makeRedirectionError(location: string | null): Error;
|
38
|
+
export declare function makeRedirectionMethodError(location: string | null, method: string): Error;
|
@@ -0,0 +1,209 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.makeRedirectionMethodError = exports.makeRedirectionError = exports.makeIllegalRedirectError = exports.makeTimeoutError = exports.makeAbortedError = exports.make100Error = exports.handleSignalAndTimeout = exports.setupFetch = void 0;
|
4
|
+
const http2_1 = require("http2");
|
5
|
+
const url_1 = require("url");
|
6
|
+
const already_1 = require("already");
|
7
|
+
const body_1 = require("./body");
|
8
|
+
const core_1 = require("./core");
|
9
|
+
const headers_1 = require("./headers");
|
10
|
+
const utils_1 = require("./utils");
|
11
|
+
const {
|
12
|
+
// Required for a request
|
13
|
+
HTTP2_HEADER_METHOD, HTTP2_HEADER_SCHEME, HTTP2_HEADER_PATH, HTTP2_HEADER_AUTHORITY,
|
14
|
+
// Methods
|
15
|
+
HTTP2_METHOD_GET, HTTP2_METHOD_HEAD,
|
16
|
+
// Requests
|
17
|
+
HTTP2_HEADER_USER_AGENT, HTTP2_HEADER_ACCEPT, HTTP2_HEADER_COOKIE, HTTP2_HEADER_CONTENT_TYPE, HTTP2_HEADER_CONTENT_LENGTH, HTTP2_HEADER_ACCEPT_ENCODING, } = http2_1.constants;
|
18
|
+
function ensureNotCircularRedirection(redirections) {
|
19
|
+
const urls = [...redirections];
|
20
|
+
const last = urls.pop();
|
21
|
+
for (let i = 0; i < urls.length; ++i)
|
22
|
+
if (urls[i] === last) {
|
23
|
+
const err = new Error("Redirection loop detected");
|
24
|
+
err.urls = urls.slice(i);
|
25
|
+
throw err;
|
26
|
+
}
|
27
|
+
}
|
28
|
+
const makeDefaultEncodings = (mul = 1) => (0, utils_1.hasBuiltinBrotli)()
|
29
|
+
? [
|
30
|
+
{ name: "br", score: 1.0 * mul },
|
31
|
+
{ name: "gzip", score: 0.8 * mul },
|
32
|
+
{ name: "deflate", score: 0.5 * mul },
|
33
|
+
]
|
34
|
+
: [
|
35
|
+
{ name: "gzip", score: 1.0 * mul },
|
36
|
+
{ name: "deflate", score: 0.5 * mul },
|
37
|
+
];
|
38
|
+
const defaultEncodings = makeDefaultEncodings();
|
39
|
+
const fallbackEncodings = makeDefaultEncodings(0.8);
|
40
|
+
const stringifyEncoding = (acceptEncoding) => `${acceptEncoding.name};q=${acceptEncoding.score}`;
|
41
|
+
const stringifyEncodings = (accepts) => accepts
|
42
|
+
.map(acceptEncoding => stringifyEncoding(acceptEncoding))
|
43
|
+
.join(", ");
|
44
|
+
function getEncodings(contentDecoders) {
|
45
|
+
if (contentDecoders.length === 0)
|
46
|
+
return stringifyEncodings(defaultEncodings);
|
47
|
+
const makeScore = (index) => 1 - (index / (contentDecoders.length)) * 0.2;
|
48
|
+
return stringifyEncodings([
|
49
|
+
...contentDecoders.map(({ name }, index) => ({ name, score: makeScore(index) })),
|
50
|
+
...fallbackEncodings,
|
51
|
+
]);
|
52
|
+
}
|
53
|
+
async function setupFetch(session, request, init = {}, extra) {
|
54
|
+
const { redirected } = extra;
|
55
|
+
ensureNotCircularRedirection(redirected);
|
56
|
+
const { url, method, redirect, integrity } = request;
|
57
|
+
const { signal, onTrailers } = init;
|
58
|
+
const { origin, protocol, host, pathname, search, hash, } = new url_1.URL(url);
|
59
|
+
const path = pathname + search + hash;
|
60
|
+
const endStream = method === HTTP2_METHOD_GET || method === HTTP2_METHOD_HEAD;
|
61
|
+
const headers = new headers_1.Headers(request.headers);
|
62
|
+
const cookies = (await session.cookieJar.getCookies(url))
|
63
|
+
.map(cookie => cookie.cookieString());
|
64
|
+
const contentDecoders = session.contentDecoders();
|
65
|
+
const acceptEncoding = getEncodings(contentDecoders);
|
66
|
+
if (headers.has(HTTP2_HEADER_COOKIE))
|
67
|
+
cookies.push(...(0, utils_1.arrayify)(headers.get(HTTP2_HEADER_COOKIE)));
|
68
|
+
if (!headers.has("host"))
|
69
|
+
headers.set("host", host);
|
70
|
+
const headersToSend = {
|
71
|
+
// Set required headers
|
72
|
+
...(session.protocol === "http1" ? {} : {
|
73
|
+
[HTTP2_HEADER_METHOD]: method,
|
74
|
+
[HTTP2_HEADER_SCHEME]: protocol.replace(/:.*/, ""),
|
75
|
+
[HTTP2_HEADER_PATH]: path,
|
76
|
+
}),
|
77
|
+
// Set default headers
|
78
|
+
[HTTP2_HEADER_ACCEPT]: session.accept(),
|
79
|
+
[HTTP2_HEADER_USER_AGENT]: session.userAgent(),
|
80
|
+
[HTTP2_HEADER_ACCEPT_ENCODING]: acceptEncoding,
|
81
|
+
};
|
82
|
+
if (cookies.length > 0)
|
83
|
+
headersToSend[HTTP2_HEADER_COOKIE] = cookies.join("; ");
|
84
|
+
for (const [key, val] of headers.entries()) {
|
85
|
+
if (key === "host" && session.protocol === "http2")
|
86
|
+
// Convert to :authority like curl does:
|
87
|
+
// https://github.com/grantila/fetch-h2/issues/9
|
88
|
+
headersToSend[HTTP2_HEADER_AUTHORITY] = val;
|
89
|
+
else if (key !== HTTP2_HEADER_COOKIE)
|
90
|
+
headersToSend[key] = val;
|
91
|
+
}
|
92
|
+
const inspector = new body_1.BodyInspector(request);
|
93
|
+
if (!endStream &&
|
94
|
+
inspector.length != null &&
|
95
|
+
!request.headers.has(HTTP2_HEADER_CONTENT_LENGTH))
|
96
|
+
headersToSend[HTTP2_HEADER_CONTENT_LENGTH] = "" + inspector.length;
|
97
|
+
if (!endStream &&
|
98
|
+
!request.headers.has("content-type") &&
|
99
|
+
inspector.mime)
|
100
|
+
headersToSend[HTTP2_HEADER_CONTENT_TYPE] = inspector.mime;
|
101
|
+
function timeoutError() {
|
102
|
+
return new core_1.TimeoutError(`${method} ${url} timed out after ${init.timeout} ms`);
|
103
|
+
}
|
104
|
+
const timeoutAt = extra.timeoutAt || (("timeout" in init && typeof init.timeout === "number")
|
105
|
+
// Setting the timeoutAt here at first time allows async cookie
|
106
|
+
// jar to not take part of timeout for at least the first request
|
107
|
+
// (in a potential redirect chain)
|
108
|
+
? Date.now() + init.timeout
|
109
|
+
: void 0);
|
110
|
+
function setupTimeout() {
|
111
|
+
if (!timeoutAt)
|
112
|
+
return null;
|
113
|
+
const now = Date.now();
|
114
|
+
if (now >= timeoutAt)
|
115
|
+
throw timeoutError();
|
116
|
+
let timerId;
|
117
|
+
return {
|
118
|
+
clear: () => {
|
119
|
+
if (timerId)
|
120
|
+
clearTimeout(timerId);
|
121
|
+
},
|
122
|
+
promise: new Promise((_resolve, reject) => {
|
123
|
+
timerId = setTimeout(() => {
|
124
|
+
timerId = null;
|
125
|
+
reject(timeoutError());
|
126
|
+
}, timeoutAt - now);
|
127
|
+
}),
|
128
|
+
};
|
129
|
+
}
|
130
|
+
const timeoutInfo = setupTimeout();
|
131
|
+
function abortError() {
|
132
|
+
return new core_1.AbortError(`${method} ${url} aborted`);
|
133
|
+
}
|
134
|
+
if (signal && signal.aborted)
|
135
|
+
throw abortError();
|
136
|
+
let abortHandler;
|
137
|
+
const signalPromise = signal
|
138
|
+
?
|
139
|
+
new Promise((_resolve, reject) => {
|
140
|
+
signal.once("abort", abortHandler = () => {
|
141
|
+
reject(abortError());
|
142
|
+
});
|
143
|
+
})
|
144
|
+
: null;
|
145
|
+
function cleanup() {
|
146
|
+
var _a, _b;
|
147
|
+
(_a = timeoutInfo === null || timeoutInfo === void 0 ? void 0 : timeoutInfo.clear) === null || _a === void 0 ? void 0 : _a.call(timeoutInfo);
|
148
|
+
(_b = timeoutInfo === null || timeoutInfo === void 0 ? void 0 : timeoutInfo.promise) === null || _b === void 0 ? void 0 : _b.catch(_err => { });
|
149
|
+
if (signal && abortHandler)
|
150
|
+
signal.removeListener("abort", abortHandler);
|
151
|
+
}
|
152
|
+
return {
|
153
|
+
cleanup,
|
154
|
+
contentDecoders,
|
155
|
+
endStream,
|
156
|
+
headersToSend,
|
157
|
+
integrity,
|
158
|
+
method,
|
159
|
+
onTrailers,
|
160
|
+
origin,
|
161
|
+
redirect,
|
162
|
+
redirected,
|
163
|
+
request,
|
164
|
+
signal,
|
165
|
+
signalPromise,
|
166
|
+
timeoutAt,
|
167
|
+
timeoutInfo,
|
168
|
+
url,
|
169
|
+
};
|
170
|
+
}
|
171
|
+
exports.setupFetch = setupFetch;
|
172
|
+
function handleSignalAndTimeout(signalPromise, timeoutInfo, cleanup, fetcher, onError) {
|
173
|
+
return Promise.race([
|
174
|
+
signalPromise,
|
175
|
+
(timeoutInfo && timeoutInfo.promise),
|
176
|
+
fetcher().catch((0, already_1.rethrow)(onError)),
|
177
|
+
]
|
178
|
+
.filter(promise => promise))
|
179
|
+
.finally(cleanup);
|
180
|
+
}
|
181
|
+
exports.handleSignalAndTimeout = handleSignalAndTimeout;
|
182
|
+
function make100Error() {
|
183
|
+
return new Error("Request failed with 100 continue. " +
|
184
|
+
"This can't happen unless a server failure");
|
185
|
+
}
|
186
|
+
exports.make100Error = make100Error;
|
187
|
+
function makeAbortedError() {
|
188
|
+
return new core_1.AbortError("Request aborted");
|
189
|
+
}
|
190
|
+
exports.makeAbortedError = makeAbortedError;
|
191
|
+
function makeTimeoutError() {
|
192
|
+
return new core_1.TimeoutError("Request timed out");
|
193
|
+
}
|
194
|
+
exports.makeTimeoutError = makeTimeoutError;
|
195
|
+
function makeIllegalRedirectError() {
|
196
|
+
return new Error("Server responded illegally with a " +
|
197
|
+
"redirect code but missing 'location' header");
|
198
|
+
}
|
199
|
+
exports.makeIllegalRedirectError = makeIllegalRedirectError;
|
200
|
+
function makeRedirectionError(location) {
|
201
|
+
return new Error(`URL got redirected to ${location}`);
|
202
|
+
}
|
203
|
+
exports.makeRedirectionError = makeRedirectionError;
|
204
|
+
function makeRedirectionMethodError(location, method) {
|
205
|
+
return new Error(`URL got redirected to ${location}, which ` +
|
206
|
+
`'fetch-h2' doesn't support for ${method}`);
|
207
|
+
}
|
208
|
+
exports.makeRedirectionMethodError = makeRedirectionMethodError;
|
209
|
+
//# sourceMappingURL=fetch-common.js.map
|
@@ -0,0 +1,7 @@
|
|
1
|
+
import { FetchInit } from "./core";
|
2
|
+
import { SimpleSessionHttp1 } from "./simple-session";
|
3
|
+
import { FetchExtra } from "./fetch-common";
|
4
|
+
import { Request } from "./request";
|
5
|
+
import { Response } from "./response";
|
6
|
+
export declare function fetchImpl(session: SimpleSessionHttp1, input: Request, init: Partial<FetchInit> | undefined, extra: FetchExtra): Promise<Response>;
|
7
|
+
export declare function fetch(session: SimpleSessionHttp1, input: Request, init?: Partial<FetchInit>, extra?: FetchExtra): Promise<Response>;
|
@@ -0,0 +1,148 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.fetch = exports.fetchImpl = void 0;
|
4
|
+
const http2_1 = require("http2");
|
5
|
+
const callguard_1 = require("callguard");
|
6
|
+
const abort_1 = require("./abort");
|
7
|
+
const fetch_common_1 = require("./fetch-common");
|
8
|
+
const headers_1 = require("./headers");
|
9
|
+
const response_1 = require("./response");
|
10
|
+
const utils_1 = require("./utils");
|
11
|
+
const {
|
12
|
+
// Responses, these are the same in HTTP/1.1 and HTTP/2
|
13
|
+
HTTP2_HEADER_LOCATION: HTTP1_HEADER_LOCATION, HTTP2_HEADER_SET_COOKIE: HTTP1_HEADER_SET_COOKIE, } = http2_1.constants;
|
14
|
+
async function fetchImpl(session, input, init = {}, extra) {
|
15
|
+
const { cleanup, contentDecoders, endStream, headersToSend, integrity, method, onTrailers, redirect, redirected, request, signal, signalPromise, timeoutAt, timeoutInfo, url, } = await (0, fetch_common_1.setupFetch)(session, input, init, extra);
|
16
|
+
const { req, cleanup: socketCleanup } = session.get(url);
|
17
|
+
const doFetch = async () => {
|
18
|
+
for (const [key, value] of Object.entries(headersToSend)) {
|
19
|
+
if (value != null)
|
20
|
+
req.setHeader(key, value);
|
21
|
+
}
|
22
|
+
const response = new Promise((resolve, reject) => {
|
23
|
+
const guard = (0, callguard_1.syncGuard)(reject, { catchAsync: true });
|
24
|
+
req.once("error", reject);
|
25
|
+
req.once("aborted", guard(() => {
|
26
|
+
reject((0, fetch_common_1.makeAbortedError)());
|
27
|
+
}));
|
28
|
+
req.once("continue", guard(() => {
|
29
|
+
reject((0, fetch_common_1.make100Error)());
|
30
|
+
}));
|
31
|
+
req.once("information", guard((res) => {
|
32
|
+
resolve(new response_1.Response(null, // No body
|
33
|
+
{ status: res.statusCode }));
|
34
|
+
}));
|
35
|
+
req.once("timeout", guard(() => {
|
36
|
+
reject((0, fetch_common_1.makeTimeoutError)());
|
37
|
+
req.abort();
|
38
|
+
}));
|
39
|
+
req.once("upgrade", guard((_res, _socket, _upgradeHead) => {
|
40
|
+
reject(new Error("Upgrade not implemented!"));
|
41
|
+
req.abort();
|
42
|
+
}));
|
43
|
+
req.once("response", guard((res) => {
|
44
|
+
res.once("end", socketCleanup);
|
45
|
+
const { signal: bodySignal = void 0, abort: bodyAbort = void 0, } = signal ? new abort_1.AbortController() : {};
|
46
|
+
if (signal) {
|
47
|
+
const abortHandler = () => {
|
48
|
+
bodyAbort();
|
49
|
+
req.abort();
|
50
|
+
res.destroy();
|
51
|
+
};
|
52
|
+
if (signal.aborted) {
|
53
|
+
// No reason to continue, the request is aborted
|
54
|
+
abortHandler();
|
55
|
+
return;
|
56
|
+
}
|
57
|
+
signal.once("abort", abortHandler);
|
58
|
+
res.once("end", () => {
|
59
|
+
signal.removeListener("abort", abortHandler);
|
60
|
+
});
|
61
|
+
}
|
62
|
+
const { headers, statusCode } = res;
|
63
|
+
res.once("end", guard(() => {
|
64
|
+
if (!onTrailers)
|
65
|
+
return;
|
66
|
+
try {
|
67
|
+
const { trailers } = res;
|
68
|
+
const headers = new headers_1.GuardedHeaders("response");
|
69
|
+
Object.keys(trailers).forEach(key => {
|
70
|
+
if (trailers[key] != null)
|
71
|
+
headers.set(key, "" + trailers[key]);
|
72
|
+
});
|
73
|
+
onTrailers(headers);
|
74
|
+
}
|
75
|
+
catch (err) {
|
76
|
+
// TODO: Implement #8
|
77
|
+
// tslint:disable-next-line
|
78
|
+
console.warn("Trailer handling failed", err);
|
79
|
+
}
|
80
|
+
}));
|
81
|
+
const location = (0, utils_1.parseLocation)(headers[HTTP1_HEADER_LOCATION], url);
|
82
|
+
const isRedirected = utils_1.isRedirectStatus["" + statusCode];
|
83
|
+
if (headers[HTTP1_HEADER_SET_COOKIE]) {
|
84
|
+
const setCookies = (0, utils_1.arrayify)(headers[HTTP1_HEADER_SET_COOKIE]);
|
85
|
+
session.cookieJar.setCookies(setCookies, url);
|
86
|
+
}
|
87
|
+
if (!input.allowForbiddenHeaders) {
|
88
|
+
delete headers["set-cookie"];
|
89
|
+
delete headers["set-cookie2"];
|
90
|
+
}
|
91
|
+
if (isRedirected && !location)
|
92
|
+
return reject((0, fetch_common_1.makeIllegalRedirectError)());
|
93
|
+
if (!isRedirected || redirect === "manual")
|
94
|
+
return resolve(new response_1.StreamResponse(contentDecoders, url, res, headers, redirect === "manual"
|
95
|
+
? false
|
96
|
+
: extra.redirected.length > 0, {
|
97
|
+
status: res.statusCode,
|
98
|
+
statusText: res.statusMessage,
|
99
|
+
}, bodySignal, 1, input.allowForbiddenHeaders, integrity));
|
100
|
+
const { url: locationUrl, isRelative } = location;
|
101
|
+
if (redirect === "error")
|
102
|
+
return reject((0, fetch_common_1.makeRedirectionError)(locationUrl));
|
103
|
+
// redirect is 'follow'
|
104
|
+
// We don't support re-sending a non-GET/HEAD request (as
|
105
|
+
// we don't want to [can't, if its' streamed] re-send the
|
106
|
+
// body). The concept is fundementally broken anyway...
|
107
|
+
if (!endStream)
|
108
|
+
return reject((0, fetch_common_1.makeRedirectionMethodError)(locationUrl, method));
|
109
|
+
res.destroy();
|
110
|
+
if (isRelative) {
|
111
|
+
resolve(fetchImpl(session, request.clone(locationUrl), { signal, onTrailers }, {
|
112
|
+
redirected: redirected.concat(url),
|
113
|
+
timeoutAt,
|
114
|
+
}));
|
115
|
+
}
|
116
|
+
else {
|
117
|
+
resolve(session.newFetch(request.clone(locationUrl), init, {
|
118
|
+
timeoutAt,
|
119
|
+
redirected: redirected.concat(url),
|
120
|
+
}));
|
121
|
+
}
|
122
|
+
}));
|
123
|
+
});
|
124
|
+
if (endStream)
|
125
|
+
req.end();
|
126
|
+
else
|
127
|
+
await request.readable()
|
128
|
+
.then(readable => {
|
129
|
+
(0, utils_1.pipeline)(readable, req)
|
130
|
+
.catch(_err => {
|
131
|
+
// TODO: Implement error handling
|
132
|
+
});
|
133
|
+
});
|
134
|
+
return response;
|
135
|
+
};
|
136
|
+
return (0, fetch_common_1.handleSignalAndTimeout)(signalPromise, timeoutInfo, cleanup, doFetch, socketCleanup);
|
137
|
+
}
|
138
|
+
exports.fetchImpl = fetchImpl;
|
139
|
+
function fetch(session, input, init, extra) {
|
140
|
+
var _a;
|
141
|
+
extra = {
|
142
|
+
timeoutAt: extra === null || extra === void 0 ? void 0 : extra.timeoutAt,
|
143
|
+
redirected: (_a = extra === null || extra === void 0 ? void 0 : extra.redirected) !== null && _a !== void 0 ? _a : [],
|
144
|
+
};
|
145
|
+
return fetchImpl(session, input, init, extra);
|
146
|
+
}
|
147
|
+
exports.fetch = fetch;
|
148
|
+
//# sourceMappingURL=fetch-http1.js.map
|
@@ -0,0 +1,6 @@
|
|
1
|
+
import { FetchInit } from "./core";
|
2
|
+
import { SimpleSessionHttp2 } from "./simple-session";
|
3
|
+
import { FetchExtra } from "./fetch-common";
|
4
|
+
import { Request } from "./request";
|
5
|
+
import { Response } from "./response";
|
6
|
+
export declare function fetch(session: SimpleSessionHttp2, input: Request, init?: Partial<FetchInit>, extra?: FetchExtra): Promise<Response>;
|