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,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 {};
|