fetch-h 3.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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>;
|