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,204 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.fetch = void 0;
|
4
|
+
const http2_1 = require("http2");
|
5
|
+
const callguard_1 = require("callguard");
|
6
|
+
const abort_1 = require("./abort");
|
7
|
+
const core_1 = require("./core");
|
8
|
+
const fetch_common_1 = require("./fetch-common");
|
9
|
+
const headers_1 = require("./headers");
|
10
|
+
const response_1 = require("./response");
|
11
|
+
const utils_1 = require("./utils");
|
12
|
+
const utils_http2_1 = require("./utils-http2");
|
13
|
+
const {
|
14
|
+
// Responses
|
15
|
+
HTTP2_HEADER_STATUS, HTTP2_HEADER_LOCATION, HTTP2_HEADER_SET_COOKIE,
|
16
|
+
// Error codes
|
17
|
+
NGHTTP2_NO_ERROR, } = http2_1.constants;
|
18
|
+
// This is from nghttp2.h, but undocumented in Node.js
|
19
|
+
const NGHTTP2_ERR_START_STREAM_NOT_ALLOWED = -516;
|
20
|
+
async function fetchImpl(session, input, init = {}, extra) {
|
21
|
+
const { cleanup, contentDecoders, endStream, headersToSend, integrity, method, onTrailers, origin, redirect, redirected, request, signal, signalPromise, timeoutAt, timeoutInfo, url, } = await (0, fetch_common_1.setupFetch)(session, input, init, extra);
|
22
|
+
const { raceConditionedGoaway } = extra;
|
23
|
+
const streamPromise = session.get();
|
24
|
+
async function doFetch() {
|
25
|
+
const { session: ph2session, cleanup: socketCleanup } = streamPromise;
|
26
|
+
const h2session = await ph2session;
|
27
|
+
const tryRetryOnGoaway = (resolve) => {
|
28
|
+
// This could be due to a race-condition in GOAWAY.
|
29
|
+
// As of current Node.js, the 'goaway' event is emitted on the
|
30
|
+
// session before this event (at least frameError, probably
|
31
|
+
// 'error' too) is emitted, so we will know if we got it.
|
32
|
+
if (!raceConditionedGoaway.has(origin) &&
|
33
|
+
(0, utils_http2_1.hasGotGoaway)(h2session)) {
|
34
|
+
// Don't retry again due to potential GOAWAY
|
35
|
+
raceConditionedGoaway.add(origin);
|
36
|
+
// Since we've got the 'goaway' event, the
|
37
|
+
// context has already released the session,
|
38
|
+
// so a retry will create a new session.
|
39
|
+
resolve(fetchImpl(session, request, { signal, onTrailers }, {
|
40
|
+
raceConditionedGoaway,
|
41
|
+
redirected,
|
42
|
+
timeoutAt,
|
43
|
+
}));
|
44
|
+
return true;
|
45
|
+
}
|
46
|
+
return false;
|
47
|
+
};
|
48
|
+
let stream;
|
49
|
+
let shouldCleanupSocket = true;
|
50
|
+
try {
|
51
|
+
stream = h2session.request(headersToSend, { endStream });
|
52
|
+
}
|
53
|
+
catch (err) {
|
54
|
+
if (err.code === "ERR_HTTP2_GOAWAY_SESSION") {
|
55
|
+
// Retry with new session
|
56
|
+
throw new core_1.RetryError(err.code);
|
57
|
+
}
|
58
|
+
throw err;
|
59
|
+
}
|
60
|
+
const response = new Promise((resolve, reject) => {
|
61
|
+
const guard = (0, callguard_1.syncGuard)(reject, { catchAsync: true });
|
62
|
+
stream.on("aborted", guard((..._whatever) => {
|
63
|
+
reject((0, fetch_common_1.makeAbortedError)());
|
64
|
+
}));
|
65
|
+
stream.on("error", guard((err) => {
|
66
|
+
if (err &&
|
67
|
+
err.code === "ERR_HTTP2_STREAM_ERROR" &&
|
68
|
+
err.message &&
|
69
|
+
err.message.includes("NGHTTP2_REFUSED_STREAM")) {
|
70
|
+
if (tryRetryOnGoaway(resolve))
|
71
|
+
return;
|
72
|
+
}
|
73
|
+
reject(err);
|
74
|
+
}));
|
75
|
+
stream.on("frameError", guard((_type, code, _streamId) => {
|
76
|
+
if (code === NGHTTP2_ERR_START_STREAM_NOT_ALLOWED &&
|
77
|
+
endStream) {
|
78
|
+
if (tryRetryOnGoaway(resolve))
|
79
|
+
return;
|
80
|
+
}
|
81
|
+
reject(new Error("Request failed"));
|
82
|
+
}));
|
83
|
+
stream.on("close", guard(() => {
|
84
|
+
if (shouldCleanupSocket)
|
85
|
+
socketCleanup();
|
86
|
+
// We'll get an 'error' event if there actually is an
|
87
|
+
// error, but not if we got NGHTTP2_NO_ERROR.
|
88
|
+
// In case of an error, the 'error' event will be awaited
|
89
|
+
// instead, to get (and propagate) the error object.
|
90
|
+
if (stream.rstCode === NGHTTP2_NO_ERROR)
|
91
|
+
reject(new core_1.AbortError("Stream prematurely closed"));
|
92
|
+
}));
|
93
|
+
stream.on("timeout", guard((..._whatever) => {
|
94
|
+
reject((0, fetch_common_1.makeTimeoutError)());
|
95
|
+
}));
|
96
|
+
stream.on("trailers", guard((_headers, _flags) => {
|
97
|
+
if (!onTrailers)
|
98
|
+
return;
|
99
|
+
try {
|
100
|
+
const headers = new headers_1.GuardedHeaders("response");
|
101
|
+
Object.keys(_headers).forEach(key => {
|
102
|
+
if (Array.isArray(_headers[key]))
|
103
|
+
_headers[key]
|
104
|
+
.forEach(value => headers.append(key, value));
|
105
|
+
else
|
106
|
+
headers.set(key, "" + _headers[key]);
|
107
|
+
});
|
108
|
+
onTrailers(headers);
|
109
|
+
}
|
110
|
+
catch (err) {
|
111
|
+
// TODO: Implement #8
|
112
|
+
// tslint:disable-next-line
|
113
|
+
console.warn("Trailer handling failed", err);
|
114
|
+
}
|
115
|
+
}));
|
116
|
+
// ClientHttp2Stream events
|
117
|
+
stream.on("continue", guard((..._whatever) => {
|
118
|
+
reject((0, fetch_common_1.make100Error)());
|
119
|
+
}));
|
120
|
+
stream.on("response", guard((headers) => {
|
121
|
+
const { signal: bodySignal = void 0, abort: bodyAbort = void 0, } = signal ? new abort_1.AbortController() : {};
|
122
|
+
if (signal) {
|
123
|
+
const abortHandler = () => {
|
124
|
+
bodyAbort();
|
125
|
+
stream.destroy();
|
126
|
+
};
|
127
|
+
if (signal.aborted) {
|
128
|
+
// No reason to continue, the request is aborted
|
129
|
+
abortHandler();
|
130
|
+
return;
|
131
|
+
}
|
132
|
+
signal.once("abort", abortHandler);
|
133
|
+
stream.once("close", () => {
|
134
|
+
signal.removeListener("abort", abortHandler);
|
135
|
+
});
|
136
|
+
}
|
137
|
+
const status = "" + headers[HTTP2_HEADER_STATUS];
|
138
|
+
const location = (0, utils_1.parseLocation)(headers[HTTP2_HEADER_LOCATION], url);
|
139
|
+
const isRedirected = utils_1.isRedirectStatus[status];
|
140
|
+
if (headers[HTTP2_HEADER_SET_COOKIE]) {
|
141
|
+
const setCookies = (0, utils_1.arrayify)(headers[HTTP2_HEADER_SET_COOKIE]);
|
142
|
+
session.cookieJar.setCookies(setCookies, url);
|
143
|
+
}
|
144
|
+
if (!input.allowForbiddenHeaders) {
|
145
|
+
delete headers["set-cookie"];
|
146
|
+
delete headers["set-cookie2"];
|
147
|
+
}
|
148
|
+
if (isRedirected && !location)
|
149
|
+
return reject((0, fetch_common_1.makeIllegalRedirectError)());
|
150
|
+
if (!isRedirected || redirect === "manual")
|
151
|
+
return resolve(new response_1.StreamResponse(contentDecoders, url, stream, headers, redirect === "manual"
|
152
|
+
? false
|
153
|
+
: extra.redirected.length > 0, {}, bodySignal, 2, input.allowForbiddenHeaders, integrity));
|
154
|
+
const { url: locationUrl, isRelative } = location;
|
155
|
+
if (redirect === "error")
|
156
|
+
return reject((0, fetch_common_1.makeRedirectionError)(locationUrl));
|
157
|
+
// redirect is 'follow'
|
158
|
+
// We don't support re-sending a non-GET/HEAD request (as
|
159
|
+
// we don't want to [can't, if its' streamed] re-send the
|
160
|
+
// body). The concept is fundementally broken anyway...
|
161
|
+
if (!endStream)
|
162
|
+
return reject((0, fetch_common_1.makeRedirectionMethodError)(locationUrl, method));
|
163
|
+
if (!location)
|
164
|
+
return reject((0, fetch_common_1.makeIllegalRedirectError)());
|
165
|
+
if (isRelative) {
|
166
|
+
shouldCleanupSocket = false;
|
167
|
+
stream.destroy();
|
168
|
+
resolve(fetchImpl(session, request.clone(locationUrl), init, {
|
169
|
+
raceConditionedGoaway,
|
170
|
+
redirected: redirected.concat(url),
|
171
|
+
timeoutAt,
|
172
|
+
}));
|
173
|
+
}
|
174
|
+
else {
|
175
|
+
resolve(session.newFetch(request.clone(locationUrl), init, {
|
176
|
+
timeoutAt,
|
177
|
+
redirected: redirected.concat(url),
|
178
|
+
}));
|
179
|
+
}
|
180
|
+
}));
|
181
|
+
});
|
182
|
+
if (!endStream)
|
183
|
+
await request.readable()
|
184
|
+
.then(readable => {
|
185
|
+
(0, utils_1.pipeline)(readable, stream)
|
186
|
+
.catch(_err => {
|
187
|
+
// TODO: Implement error handling
|
188
|
+
});
|
189
|
+
});
|
190
|
+
return response;
|
191
|
+
}
|
192
|
+
return (0, fetch_common_1.handleSignalAndTimeout)(signalPromise, timeoutInfo, cleanup, doFetch, streamPromise.cleanup);
|
193
|
+
}
|
194
|
+
function fetch(session, input, init, extra) {
|
195
|
+
var _a;
|
196
|
+
const http2Extra = {
|
197
|
+
timeoutAt: extra === null || extra === void 0 ? void 0 : extra.timeoutAt,
|
198
|
+
redirected: (_a = extra === null || extra === void 0 ? void 0 : extra.redirected) !== null && _a !== void 0 ? _a : [],
|
199
|
+
raceConditionedGoaway: new Set(),
|
200
|
+
};
|
201
|
+
return fetchImpl(session, input, init, http2Extra);
|
202
|
+
}
|
203
|
+
exports.fetch = fetch;
|
204
|
+
//# sourceMappingURL=fetch-http2.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const version = "3.0.2";
|
@@ -0,0 +1,24 @@
|
|
1
|
+
export declare type GuardTypes = "immutable" | "request" | "request-no-cors" | "response" | "none";
|
2
|
+
export interface RawHeaders {
|
3
|
+
[key: string]: string | Array<string> | undefined;
|
4
|
+
}
|
5
|
+
export declare class Headers {
|
6
|
+
protected _guard: GuardTypes;
|
7
|
+
private _data;
|
8
|
+
constructor(init?: RawHeaders | Headers);
|
9
|
+
get [Symbol.toStringTag](): string;
|
10
|
+
[Symbol.iterator](): IterableIterator<[string, string]>;
|
11
|
+
append(name: string, value: string): void;
|
12
|
+
delete(name: string): void;
|
13
|
+
entries(): IterableIterator<[string, string]>;
|
14
|
+
get(name: string): string | null;
|
15
|
+
has(name: string): boolean;
|
16
|
+
keys(): IterableIterator<string>;
|
17
|
+
set(name: string, value: string): void;
|
18
|
+
values(): IterableIterator<string>;
|
19
|
+
toJSON(): {};
|
20
|
+
}
|
21
|
+
export declare class GuardedHeaders extends Headers {
|
22
|
+
constructor(guard: GuardTypes, init?: RawHeaders | Headers);
|
23
|
+
}
|
24
|
+
export declare function ensureHeaders(headers: RawHeaders | Headers | undefined): Headers;
|
@@ -0,0 +1,173 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.ensureHeaders = exports.GuardedHeaders = exports.Headers = void 0;
|
4
|
+
const utils_1 = require("./utils");
|
5
|
+
const forbiddenHeaders = [
|
6
|
+
"accept-charset",
|
7
|
+
"accept-encoding",
|
8
|
+
"access-control-request-headers",
|
9
|
+
"access-control-request-method",
|
10
|
+
"connection",
|
11
|
+
"content-length",
|
12
|
+
"cookie",
|
13
|
+
"cookie2",
|
14
|
+
"date",
|
15
|
+
"dnt",
|
16
|
+
"expect",
|
17
|
+
"host",
|
18
|
+
"keep-alive",
|
19
|
+
"origin",
|
20
|
+
"referer",
|
21
|
+
"te",
|
22
|
+
"trailer",
|
23
|
+
"transfer-encoding",
|
24
|
+
"upgrade",
|
25
|
+
"via",
|
26
|
+
];
|
27
|
+
function isForbiddenHeader(name) {
|
28
|
+
if (name.startsWith("proxy-") || name.startsWith("sec-"))
|
29
|
+
// Safe headers
|
30
|
+
return false;
|
31
|
+
return forbiddenHeaders.includes(name);
|
32
|
+
}
|
33
|
+
function isForbiddenResponseHeader(name) {
|
34
|
+
return ["set-cookie", "set-cookie2"].includes(name);
|
35
|
+
}
|
36
|
+
function isSimpleHeader(name, value) {
|
37
|
+
const simpleHeaders = [
|
38
|
+
"accept",
|
39
|
+
"accept-language",
|
40
|
+
"content-language",
|
41
|
+
"dpr",
|
42
|
+
"downlink",
|
43
|
+
"save-data",
|
44
|
+
"viewport-width",
|
45
|
+
"width",
|
46
|
+
];
|
47
|
+
if (simpleHeaders.includes(name))
|
48
|
+
return true;
|
49
|
+
if (name !== "content-type")
|
50
|
+
return false;
|
51
|
+
if (value == null)
|
52
|
+
return false;
|
53
|
+
const mimeType = value.replace(/;.*/, "").toLowerCase();
|
54
|
+
return [
|
55
|
+
"application/x-www-form-urlencoded",
|
56
|
+
"multipart/form-data",
|
57
|
+
"text/plain",
|
58
|
+
].includes(mimeType);
|
59
|
+
}
|
60
|
+
function filterName(name) {
|
61
|
+
if (/[^A-Za-z0-9\-#$%&'*+.\^_`|~]/.test(name))
|
62
|
+
throw new TypeError("Invalid character in header field name: " + name);
|
63
|
+
return name.toLowerCase();
|
64
|
+
}
|
65
|
+
function _ensureGuard(guard, name, value) {
|
66
|
+
if (guard === "immutable")
|
67
|
+
throw new TypeError("Header guard error: Cannot change immutable header");
|
68
|
+
if (!name)
|
69
|
+
return;
|
70
|
+
if (guard === "request" && isForbiddenHeader(name))
|
71
|
+
throw new TypeError("Header guard error: " +
|
72
|
+
"Cannot set forbidden header for requests" +
|
73
|
+
` (${name})`);
|
74
|
+
if (guard === "request-no-cors" && !isSimpleHeader(name, value))
|
75
|
+
throw new TypeError("Header guard error: " +
|
76
|
+
"Cannot set non-simple header for no-cors requests" +
|
77
|
+
` (${name})`);
|
78
|
+
if (guard === "response" && isForbiddenResponseHeader(name))
|
79
|
+
throw new TypeError("Header guard error: " +
|
80
|
+
"Cannot set forbidden response header for response" +
|
81
|
+
` (${name})`);
|
82
|
+
}
|
83
|
+
let _guard = null;
|
84
|
+
class Headers {
|
85
|
+
constructor(init) {
|
86
|
+
this._guard = _guard || "none";
|
87
|
+
_guard = null;
|
88
|
+
this._data = new Map();
|
89
|
+
const set = (name, values) => {
|
90
|
+
if (values.length === 1)
|
91
|
+
this.set(name, values[0]);
|
92
|
+
else
|
93
|
+
for (const value of values)
|
94
|
+
this.append(name, value);
|
95
|
+
};
|
96
|
+
if (!init)
|
97
|
+
return;
|
98
|
+
else if (init instanceof Headers) {
|
99
|
+
for (const [name, values] of init._data.entries())
|
100
|
+
set(name, values);
|
101
|
+
}
|
102
|
+
else {
|
103
|
+
for (const _name of Object.keys(init)) {
|
104
|
+
const name = filterName(_name);
|
105
|
+
const value = (0, utils_1.arrayify)(init[_name])
|
106
|
+
.map(val => `${val}`);
|
107
|
+
set(name, [...value]);
|
108
|
+
}
|
109
|
+
}
|
110
|
+
}
|
111
|
+
get [Symbol.toStringTag]() {
|
112
|
+
return "Map"; // This causes unit test libraries to treat this as a Map
|
113
|
+
}
|
114
|
+
[Symbol.iterator]() {
|
115
|
+
return this.entries();
|
116
|
+
}
|
117
|
+
append(name, value) {
|
118
|
+
const _name = filterName(name);
|
119
|
+
_ensureGuard(this._guard, _name, value);
|
120
|
+
if (!this._data.has(_name))
|
121
|
+
this._data.set(_name, [value]);
|
122
|
+
else
|
123
|
+
this._data.get(_name).push(value);
|
124
|
+
}
|
125
|
+
delete(name) {
|
126
|
+
const _name = filterName(name);
|
127
|
+
_ensureGuard(this._guard);
|
128
|
+
this._data.delete(_name);
|
129
|
+
}
|
130
|
+
*entries() {
|
131
|
+
for (const [name, value] of this._data.entries())
|
132
|
+
yield [name, value.join(",")];
|
133
|
+
}
|
134
|
+
get(name) {
|
135
|
+
const _name = filterName(name);
|
136
|
+
return this._data.has(_name)
|
137
|
+
? this._data.get(_name).join(",")
|
138
|
+
: null;
|
139
|
+
}
|
140
|
+
has(name) {
|
141
|
+
return this._data.has(filterName(name));
|
142
|
+
}
|
143
|
+
keys() {
|
144
|
+
return this._data.keys();
|
145
|
+
}
|
146
|
+
set(name, value) {
|
147
|
+
const _name = filterName(name);
|
148
|
+
_ensureGuard(this._guard, _name, value);
|
149
|
+
this._data.set(_name, [value]);
|
150
|
+
}
|
151
|
+
*values() {
|
152
|
+
for (const value of this._data.values())
|
153
|
+
yield value.join(",");
|
154
|
+
}
|
155
|
+
// This is non-standard, but useful
|
156
|
+
toJSON() {
|
157
|
+
return [...this.entries()]
|
158
|
+
.reduce((prev, [key, val]) => Object.assign(prev, { [key]: val }), {});
|
159
|
+
}
|
160
|
+
}
|
161
|
+
exports.Headers = Headers;
|
162
|
+
class GuardedHeaders extends Headers {
|
163
|
+
constructor(guard, init) {
|
164
|
+
super((_guard = guard, init));
|
165
|
+
_guard = null;
|
166
|
+
}
|
167
|
+
}
|
168
|
+
exports.GuardedHeaders = GuardedHeaders;
|
169
|
+
function ensureHeaders(headers) {
|
170
|
+
return headers instanceof Headers ? headers : new Headers(headers);
|
171
|
+
}
|
172
|
+
exports.ensureHeaders = ensureHeaders;
|
173
|
+
//# sourceMappingURL=headers.js.map
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { AltNameMatch } from "./san";
|
2
|
+
export declare type Protocol = 'https1' | 'https2' | 'http1' | 'http2';
|
3
|
+
declare type AnySessionMap = {
|
4
|
+
[key in Protocol]: unknown;
|
5
|
+
};
|
6
|
+
export interface OriginCacheEntry<P, Session> {
|
7
|
+
protocol: P;
|
8
|
+
session: Session;
|
9
|
+
firstOrigin: string;
|
10
|
+
}
|
11
|
+
export default class OriginCache<SessionMap extends AnySessionMap> {
|
12
|
+
private sessionMap;
|
13
|
+
private staticMap;
|
14
|
+
get<P extends Protocol>(protocol: P, origin: string): OriginCacheEntry<typeof protocol, SessionMap[P]> | undefined;
|
15
|
+
set(origin: string, protocol: Protocol, session: SessionMap[typeof protocol], altNameMatch?: AltNameMatch, cleanup?: () => void): void;
|
16
|
+
delete(session: SessionMap[keyof SessionMap]): boolean;
|
17
|
+
disconnectAll(): void;
|
18
|
+
disconnect(origin: string): void;
|
19
|
+
}
|
20
|
+
export {};
|
@@ -0,0 +1,93 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
function makeKey(protocol, origin) {
|
4
|
+
return protocol + ":" + origin;
|
5
|
+
}
|
6
|
+
class OriginCache {
|
7
|
+
constructor() {
|
8
|
+
this.sessionMap = new Map();
|
9
|
+
this.staticMap = new Map();
|
10
|
+
}
|
11
|
+
get(protocol, origin) {
|
12
|
+
const key = makeKey(protocol, origin);
|
13
|
+
const stateByStatic = this.staticMap.get(key);
|
14
|
+
if (stateByStatic)
|
15
|
+
return {
|
16
|
+
protocol: stateByStatic.protocol,
|
17
|
+
session: stateByStatic.session,
|
18
|
+
firstOrigin: stateByStatic.firstOrigin,
|
19
|
+
};
|
20
|
+
const stateByDynamic = [...this.sessionMap.values()].find(state => state.protocol === protocol &&
|
21
|
+
state.match &&
|
22
|
+
state.match.dynamic &&
|
23
|
+
state.match.dynamic(origin));
|
24
|
+
if (stateByDynamic) {
|
25
|
+
// An origin matching a dynamic (wildcard) alt-name was found.
|
26
|
+
// Cache this to find it statically in the future.
|
27
|
+
stateByDynamic.resolved.push(origin);
|
28
|
+
this.staticMap.set(key, stateByDynamic);
|
29
|
+
return {
|
30
|
+
protocol: stateByDynamic.protocol,
|
31
|
+
session: stateByDynamic.session,
|
32
|
+
firstOrigin: stateByDynamic.firstOrigin,
|
33
|
+
};
|
34
|
+
}
|
35
|
+
}
|
36
|
+
set(origin, protocol, session, altNameMatch, cleanup) {
|
37
|
+
const state = {
|
38
|
+
protocol,
|
39
|
+
firstOrigin: origin,
|
40
|
+
session,
|
41
|
+
match: altNameMatch,
|
42
|
+
resolved: [],
|
43
|
+
cleanup,
|
44
|
+
};
|
45
|
+
this.sessionMap.set(session, state);
|
46
|
+
if (altNameMatch)
|
47
|
+
altNameMatch.names.forEach(origin => {
|
48
|
+
this.staticMap.set(makeKey(protocol, origin), state);
|
49
|
+
});
|
50
|
+
this.staticMap.set(makeKey(protocol, origin), state);
|
51
|
+
}
|
52
|
+
// Returns true if a session was deleted, false otherwise
|
53
|
+
delete(session) {
|
54
|
+
var _a, _b;
|
55
|
+
const state = this.sessionMap.get(session);
|
56
|
+
if (!state)
|
57
|
+
return false;
|
58
|
+
[
|
59
|
+
state.firstOrigin,
|
60
|
+
...state.resolved,
|
61
|
+
...((_b = (_a = state.match) === null || _a === void 0 ? void 0 : _a.names) !== null && _b !== void 0 ? _b : []),
|
62
|
+
]
|
63
|
+
.forEach(origin => {
|
64
|
+
this.staticMap.delete(makeKey(state.protocol, origin));
|
65
|
+
});
|
66
|
+
this.sessionMap.delete(session);
|
67
|
+
return true;
|
68
|
+
}
|
69
|
+
disconnectAll() {
|
70
|
+
[...this.sessionMap].forEach(([_, session]) => {
|
71
|
+
var _a;
|
72
|
+
(_a = session.cleanup) === null || _a === void 0 ? void 0 : _a.call(session);
|
73
|
+
});
|
74
|
+
this.sessionMap.clear();
|
75
|
+
this.staticMap.clear();
|
76
|
+
}
|
77
|
+
disconnect(origin) {
|
78
|
+
[
|
79
|
+
this.get('https1', origin),
|
80
|
+
this.get('https2', origin),
|
81
|
+
this.get('http1', origin),
|
82
|
+
this.get('http2', origin),
|
83
|
+
]
|
84
|
+
.filter((t) => !!t)
|
85
|
+
.forEach(({ session }) => {
|
86
|
+
var _a, _b;
|
87
|
+
(_b = (_a = this.sessionMap.get(session)) === null || _a === void 0 ? void 0 : _a.cleanup) === null || _b === void 0 ? void 0 : _b.call(_a);
|
88
|
+
this.delete(session);
|
89
|
+
});
|
90
|
+
}
|
91
|
+
}
|
92
|
+
exports.default = OriginCache;
|
93
|
+
//# sourceMappingURL=origin-cache.js.map
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { CacheTypes, CredentialsTypes, Method, ModeTypes, RedirectTypes, ReferrerPolicyTypes, ReferrerTypes, RequestInitWithoutBody, RequestInitWithUrl } from "./core";
|
2
|
+
import { Body } from "./body";
|
3
|
+
import { Headers } from "./headers";
|
4
|
+
export declare class Request extends Body implements RequestInitWithoutBody {
|
5
|
+
readonly method: Method;
|
6
|
+
readonly url: string;
|
7
|
+
readonly headers: Headers;
|
8
|
+
readonly referrer: ReferrerTypes;
|
9
|
+
readonly referrerPolicy: ReferrerPolicyTypes;
|
10
|
+
readonly mode: ModeTypes;
|
11
|
+
readonly credentials: CredentialsTypes;
|
12
|
+
readonly redirect: RedirectTypes;
|
13
|
+
readonly integrity: string;
|
14
|
+
readonly cache: CacheTypes;
|
15
|
+
readonly allowForbiddenHeaders: boolean;
|
16
|
+
private _url;
|
17
|
+
private _init;
|
18
|
+
constructor(input: string | Request, init?: Partial<RequestInitWithUrl>);
|
19
|
+
clone(newUrl?: string): Request;
|
20
|
+
}
|
@@ -0,0 +1,106 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.Request = void 0;
|
4
|
+
const body_1 = require("./body");
|
5
|
+
const headers_1 = require("./headers");
|
6
|
+
const defaultInit = {
|
7
|
+
allowForbiddenHeaders: false,
|
8
|
+
cache: "default",
|
9
|
+
credentials: "omit",
|
10
|
+
method: "GET",
|
11
|
+
mode: "same-origin",
|
12
|
+
redirect: "manual",
|
13
|
+
referrer: "client",
|
14
|
+
};
|
15
|
+
class Request extends body_1.Body {
|
16
|
+
constructor(input, init) {
|
17
|
+
super();
|
18
|
+
const { url: overwriteUrl } = init || {};
|
19
|
+
// TODO: Consider throwing a TypeError if the URL has credentials
|
20
|
+
this._url =
|
21
|
+
input instanceof Request
|
22
|
+
? (overwriteUrl || input._url)
|
23
|
+
: (overwriteUrl || input);
|
24
|
+
if (input instanceof Request) {
|
25
|
+
if (input.hasBody())
|
26
|
+
// Move body to this request
|
27
|
+
this.setBody(input);
|
28
|
+
const newInit = Object.assign({}, input, init);
|
29
|
+
init = newInit;
|
30
|
+
// TODO: Follow MDN:
|
31
|
+
// If this object exists on another origin to the
|
32
|
+
// constructor call, the Request.referrer is stripped out.
|
33
|
+
// If this object has a Request.mode of navigate, the mode
|
34
|
+
// value is converted to same-origin.
|
35
|
+
}
|
36
|
+
this._init = Object.assign({}, defaultInit, init);
|
37
|
+
const allowForbiddenHeaders = this._init.allowForbiddenHeaders;
|
38
|
+
const headers = new headers_1.GuardedHeaders(allowForbiddenHeaders
|
39
|
+
? "none"
|
40
|
+
: this._init.mode === "no-cors"
|
41
|
+
? "request-no-cors"
|
42
|
+
: "request", this._init.headers);
|
43
|
+
if (this._init.body && this._init.json)
|
44
|
+
throw new Error("Cannot specify both 'body' and 'json'");
|
45
|
+
if (!this.hasBody() && this._init.body) {
|
46
|
+
if (headers.has("content-type"))
|
47
|
+
this.setBody(this._init.body, headers.get("content-type"));
|
48
|
+
else
|
49
|
+
this.setBody(this._init.body);
|
50
|
+
}
|
51
|
+
else if (!this.hasBody() && this._init.json) {
|
52
|
+
this.setBody(new body_1.JsonBody(this._init.json));
|
53
|
+
}
|
54
|
+
Object.defineProperties(this, {
|
55
|
+
allowForbiddenHeaders: {
|
56
|
+
enumerable: true,
|
57
|
+
value: allowForbiddenHeaders,
|
58
|
+
},
|
59
|
+
cache: {
|
60
|
+
enumerable: true,
|
61
|
+
value: this._init.cache,
|
62
|
+
},
|
63
|
+
credentials: {
|
64
|
+
enumerable: true,
|
65
|
+
value: this._init.credentials,
|
66
|
+
},
|
67
|
+
headers: {
|
68
|
+
enumerable: true,
|
69
|
+
value: headers,
|
70
|
+
},
|
71
|
+
integrity: {
|
72
|
+
enumerable: true,
|
73
|
+
value: this._init.integrity,
|
74
|
+
},
|
75
|
+
method: {
|
76
|
+
enumerable: true,
|
77
|
+
value: this._init.method,
|
78
|
+
},
|
79
|
+
mode: {
|
80
|
+
enumerable: true,
|
81
|
+
value: this._init.mode,
|
82
|
+
},
|
83
|
+
redirect: {
|
84
|
+
enumerable: true,
|
85
|
+
value: this._init.redirect,
|
86
|
+
},
|
87
|
+
referrer: {
|
88
|
+
enumerable: true,
|
89
|
+
value: this._init.referrer,
|
90
|
+
},
|
91
|
+
referrerPolicy: {
|
92
|
+
enumerable: true,
|
93
|
+
value: this._init.referrerPolicy,
|
94
|
+
},
|
95
|
+
url: {
|
96
|
+
enumerable: true,
|
97
|
+
value: this._url,
|
98
|
+
},
|
99
|
+
});
|
100
|
+
}
|
101
|
+
clone(newUrl) {
|
102
|
+
return new Request(this, { url: newUrl });
|
103
|
+
}
|
104
|
+
}
|
105
|
+
exports.Request = Request;
|
106
|
+
//# sourceMappingURL=request.js.map
|
@@ -0,0 +1,33 @@
|
|
1
|
+
/// <reference types="node" />
|
2
|
+
import { BodyTypes, Decoder, HttpVersion, ResponseInit, ResponseTypes } from "./core";
|
3
|
+
import { AbortSignal } from "./abort";
|
4
|
+
import { Headers } from "./headers";
|
5
|
+
import { Body } from "./body";
|
6
|
+
import { IncomingHttpHeaders } from "./types";
|
7
|
+
interface Extra {
|
8
|
+
httpVersion: HttpVersion;
|
9
|
+
redirected: boolean;
|
10
|
+
integrity: string;
|
11
|
+
signal: AbortSignal;
|
12
|
+
type: ResponseTypes;
|
13
|
+
url: string;
|
14
|
+
}
|
15
|
+
export declare class Response extends Body {
|
16
|
+
readonly headers: Headers;
|
17
|
+
readonly ok: boolean;
|
18
|
+
readonly redirected: boolean;
|
19
|
+
readonly status: number;
|
20
|
+
readonly statusText: string;
|
21
|
+
readonly type: ResponseTypes;
|
22
|
+
readonly url: string;
|
23
|
+
readonly useFinalURL: boolean;
|
24
|
+
readonly httpVersion: HttpVersion;
|
25
|
+
constructor(body?: BodyTypes | Body | null, init?: Partial<ResponseInit>, extra?: Partial<Extra>);
|
26
|
+
static error(): Response;
|
27
|
+
static redirect(url: string, status?: number): Response;
|
28
|
+
clone(): Response;
|
29
|
+
}
|
30
|
+
export declare class StreamResponse extends Response {
|
31
|
+
constructor(contentDecoders: ReadonlyArray<Decoder>, url: string, stream: NodeJS.ReadableStream, headers: IncomingHttpHeaders, redirected: boolean, init: Partial<ResponseInit>, signal: AbortSignal | undefined, httpVersion: HttpVersion, allowForbiddenHeaders: boolean, integrity?: string);
|
32
|
+
}
|
33
|
+
export {};
|