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
package/dist/lib/body.js
ADDED
@@ -0,0 +1,248 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.BodyInspector = exports.DataBody = exports.StreamBody = exports.JsonBody = exports.Body = void 0;
|
4
|
+
const crypto_1 = require("crypto");
|
5
|
+
const already_1 = require("already");
|
6
|
+
const get_stream_1 = require("get-stream");
|
7
|
+
const through2 = require("through2");
|
8
|
+
const toArrayBuffer = require("to-arraybuffer");
|
9
|
+
const core_1 = require("./core");
|
10
|
+
const abortError = new core_1.AbortError("Response aborted");
|
11
|
+
function makeUnknownDataError() {
|
12
|
+
return new Error("Unknown body data");
|
13
|
+
}
|
14
|
+
function throwIntegrityMismatch() {
|
15
|
+
throw new Error("Resource integrity mismatch");
|
16
|
+
}
|
17
|
+
function throwLengthMismatch() {
|
18
|
+
throw new RangeError("Resource length mismatch (possibly incomplete body)");
|
19
|
+
}
|
20
|
+
function parseIntegrity(integrity) {
|
21
|
+
const [algorithm, ...expectedHash] = integrity.split("-");
|
22
|
+
return { algorithm, hash: expectedHash.join("-") };
|
23
|
+
}
|
24
|
+
function isStream(body) {
|
25
|
+
return body &&
|
26
|
+
("readable" in Object(body));
|
27
|
+
}
|
28
|
+
const emptyBuffer = new ArrayBuffer(0);
|
29
|
+
class Body {
|
30
|
+
constructor() {
|
31
|
+
this._length = null;
|
32
|
+
this._used = false;
|
33
|
+
Object.defineProperties(this, {
|
34
|
+
bodyUsed: {
|
35
|
+
enumerable: true,
|
36
|
+
get: () => this._used,
|
37
|
+
},
|
38
|
+
});
|
39
|
+
}
|
40
|
+
async arrayBuffer(allowIncomplete = false) {
|
41
|
+
this._ensureUnused();
|
42
|
+
this._ensureNotAborted();
|
43
|
+
if (this._body == null)
|
44
|
+
return this.validateIntegrity(emptyBuffer, allowIncomplete);
|
45
|
+
else if (isStream(this._body))
|
46
|
+
return this.awaitBuffer(this._body)
|
47
|
+
.then(buffer => this.validateIntegrity(buffer, allowIncomplete))
|
48
|
+
.then(buffer => toArrayBuffer(buffer));
|
49
|
+
else if (Buffer.isBuffer(this._body))
|
50
|
+
return this.validateIntegrity(toArrayBuffer(this._body), allowIncomplete);
|
51
|
+
else
|
52
|
+
throw makeUnknownDataError();
|
53
|
+
}
|
54
|
+
async formData() {
|
55
|
+
throw new Error("Body.formData() is not yet implemented");
|
56
|
+
}
|
57
|
+
async json() {
|
58
|
+
this._ensureUnused();
|
59
|
+
this._ensureNotAborted();
|
60
|
+
if (this._body == null)
|
61
|
+
return Promise.resolve(this.validateIntegrity(emptyBuffer, false))
|
62
|
+
.then(() => this._body);
|
63
|
+
else if (isStream(this._body))
|
64
|
+
return this.awaitBuffer(this._body)
|
65
|
+
.then((0, already_1.tap)(buffer => this.validateIntegrity(buffer, false)))
|
66
|
+
.then(buffer => JSON.parse(buffer.toString()));
|
67
|
+
else if (Buffer.isBuffer(this._body))
|
68
|
+
return Promise.resolve(this._body)
|
69
|
+
.then((0, already_1.tap)(buffer => this.validateIntegrity(buffer, false)))
|
70
|
+
.then(buffer => JSON.parse(buffer.toString()));
|
71
|
+
else
|
72
|
+
throw makeUnknownDataError();
|
73
|
+
}
|
74
|
+
async text(allowIncomplete = false) {
|
75
|
+
this._ensureUnused();
|
76
|
+
this._ensureNotAborted();
|
77
|
+
if (this._body == null)
|
78
|
+
return Promise.resolve(this.validateIntegrity(emptyBuffer, allowIncomplete))
|
79
|
+
.then(() => this._body);
|
80
|
+
else if (isStream(this._body))
|
81
|
+
return this.awaitBuffer(this._body)
|
82
|
+
.then((0, already_1.tap)(buffer => this.validateIntegrity(buffer, allowIncomplete)))
|
83
|
+
.then(buffer => buffer.toString());
|
84
|
+
else if (Buffer.isBuffer(this._body))
|
85
|
+
return Promise.resolve(this._body)
|
86
|
+
.then((0, already_1.tap)(buffer => this.validateIntegrity(buffer, allowIncomplete)))
|
87
|
+
.then(buffer => buffer.toString());
|
88
|
+
else
|
89
|
+
throw makeUnknownDataError();
|
90
|
+
}
|
91
|
+
async readable() {
|
92
|
+
this._ensureUnused();
|
93
|
+
this._ensureNotAborted();
|
94
|
+
if (this._body == null) {
|
95
|
+
const stream = through2();
|
96
|
+
stream.end();
|
97
|
+
return Promise.resolve(stream);
|
98
|
+
}
|
99
|
+
else if (isStream(this._body))
|
100
|
+
return Promise.resolve(this._body);
|
101
|
+
else if (Buffer.isBuffer(this._body))
|
102
|
+
return Promise.resolve(through2())
|
103
|
+
.then(stream => {
|
104
|
+
stream.write(this._body);
|
105
|
+
stream.end();
|
106
|
+
return stream;
|
107
|
+
});
|
108
|
+
else
|
109
|
+
throw makeUnknownDataError();
|
110
|
+
}
|
111
|
+
setSignal(signal) {
|
112
|
+
this._signal = signal;
|
113
|
+
}
|
114
|
+
hasBody() {
|
115
|
+
return "_body" in this;
|
116
|
+
}
|
117
|
+
setBody(body, mime, integrity, length = null) {
|
118
|
+
this._ensureUnused();
|
119
|
+
this._length = length;
|
120
|
+
this._used = false;
|
121
|
+
if (body instanceof Body) {
|
122
|
+
body._ensureUnused();
|
123
|
+
this._body = body._body;
|
124
|
+
this._mime = body._mime;
|
125
|
+
}
|
126
|
+
else if (typeof body === "string")
|
127
|
+
this._body = Buffer.from(body);
|
128
|
+
else if (body != null)
|
129
|
+
this._body = body;
|
130
|
+
else
|
131
|
+
this._body = body;
|
132
|
+
if (Buffer.isBuffer(this._body))
|
133
|
+
this._length = this._body.length;
|
134
|
+
if (mime)
|
135
|
+
this._mime = mime;
|
136
|
+
if (integrity)
|
137
|
+
this._integrity = integrity;
|
138
|
+
}
|
139
|
+
async awaitBuffer(readable) {
|
140
|
+
if (!this._signal)
|
141
|
+
return (0, get_stream_1.buffer)(readable);
|
142
|
+
// Race the readable against the abort signal
|
143
|
+
let callback = () => { };
|
144
|
+
const onAborted = new Promise((_, reject) => {
|
145
|
+
var _a;
|
146
|
+
callback = () => { reject(abortError); };
|
147
|
+
(_a = this._signal) === null || _a === void 0 ? void 0 : _a.addListener('abort', callback);
|
148
|
+
});
|
149
|
+
try {
|
150
|
+
this._ensureNotAborted();
|
151
|
+
return await Promise.race([
|
152
|
+
(0, get_stream_1.buffer)(readable),
|
153
|
+
onAborted,
|
154
|
+
]);
|
155
|
+
}
|
156
|
+
finally {
|
157
|
+
this._signal.removeListener('abort', callback);
|
158
|
+
// Could happen if abort and other error happen practically
|
159
|
+
// simultaneously. Ensure Node.js won't get mad about this.
|
160
|
+
onAborted.catch(() => { });
|
161
|
+
}
|
162
|
+
}
|
163
|
+
validateIntegrity(data, allowIncomplete) {
|
164
|
+
this._ensureNotAborted();
|
165
|
+
if (!allowIncomplete &&
|
166
|
+
this._length != null &&
|
167
|
+
data.byteLength !== this._length)
|
168
|
+
throwLengthMismatch();
|
169
|
+
if (!this._integrity)
|
170
|
+
// This is valid
|
171
|
+
return data;
|
172
|
+
const { algorithm, hash: expectedHash } = parseIntegrity(this._integrity);
|
173
|
+
// jest (I presume) modifies ArrayBuffer, breaking instanceof
|
174
|
+
const instanceOfArrayBuffer = (val) => val && val.constructor && val.constructor.name === "ArrayBuffer";
|
175
|
+
const hash = (0, crypto_1.createHash)(algorithm)
|
176
|
+
.update(instanceOfArrayBuffer(data)
|
177
|
+
? new DataView(data)
|
178
|
+
: data)
|
179
|
+
.digest("base64");
|
180
|
+
if (expectedHash.toLowerCase() !== hash.toLowerCase())
|
181
|
+
throwIntegrityMismatch();
|
182
|
+
return data;
|
183
|
+
}
|
184
|
+
_ensureNotAborted() {
|
185
|
+
if (this._signal && this._signal.aborted)
|
186
|
+
throw abortError;
|
187
|
+
}
|
188
|
+
_ensureUnused() {
|
189
|
+
if (this._used)
|
190
|
+
throw new ReferenceError("Body already used");
|
191
|
+
this._used = true;
|
192
|
+
}
|
193
|
+
// @ts-ignore
|
194
|
+
async blob() {
|
195
|
+
throw new Error("Body.blob() is not implemented (makes no sense in Node.js), " +
|
196
|
+
"use another getter.");
|
197
|
+
}
|
198
|
+
}
|
199
|
+
exports.Body = Body;
|
200
|
+
class JsonBody extends Body {
|
201
|
+
constructor(obj) {
|
202
|
+
super();
|
203
|
+
const body = Buffer.from(JSON.stringify(obj));
|
204
|
+
this.setBody(body, "application/json");
|
205
|
+
}
|
206
|
+
}
|
207
|
+
exports.JsonBody = JsonBody;
|
208
|
+
class StreamBody extends Body {
|
209
|
+
constructor(readable) {
|
210
|
+
super();
|
211
|
+
this.setBody(readable);
|
212
|
+
}
|
213
|
+
}
|
214
|
+
exports.StreamBody = StreamBody;
|
215
|
+
class DataBody extends Body {
|
216
|
+
constructor(data) {
|
217
|
+
super();
|
218
|
+
this.setBody(data);
|
219
|
+
}
|
220
|
+
}
|
221
|
+
exports.DataBody = DataBody;
|
222
|
+
class BodyInspector extends Body {
|
223
|
+
constructor(body) {
|
224
|
+
super();
|
225
|
+
this._ref = body;
|
226
|
+
}
|
227
|
+
_getMime() {
|
228
|
+
return this._mime;
|
229
|
+
}
|
230
|
+
_getLength() {
|
231
|
+
return this._length;
|
232
|
+
}
|
233
|
+
_getBody() {
|
234
|
+
return this._body;
|
235
|
+
}
|
236
|
+
get mime() {
|
237
|
+
return this._getMime.call(this._ref);
|
238
|
+
}
|
239
|
+
get length() {
|
240
|
+
return this._getLength.call(this._ref);
|
241
|
+
}
|
242
|
+
get stream() {
|
243
|
+
const rawBody = this._getBody.call(this._ref);
|
244
|
+
return rawBody && isStream(rawBody) ? rawBody : undefined;
|
245
|
+
}
|
246
|
+
}
|
247
|
+
exports.BodyInspector = BodyInspector;
|
248
|
+
//# sourceMappingURL=body.js.map
|
@@ -0,0 +1,58 @@
|
|
1
|
+
/// <reference types="node" />
|
2
|
+
import { RequestOptions } from "https";
|
3
|
+
import { Socket } from "net";
|
4
|
+
import { URL } from "url";
|
5
|
+
import { Http1Options } from "./core";
|
6
|
+
import { Request } from "./request";
|
7
|
+
export interface ConnectOptions {
|
8
|
+
rejectUnauthorized: boolean | undefined;
|
9
|
+
createConnection: () => Socket;
|
10
|
+
}
|
11
|
+
export interface SocketAndCleanup {
|
12
|
+
socket: Socket;
|
13
|
+
cleanup: () => void;
|
14
|
+
}
|
15
|
+
export interface FreeSocketInfoWithSocket extends SocketAndCleanup {
|
16
|
+
shouldCreateNew: boolean;
|
17
|
+
}
|
18
|
+
export interface FreeSocketInfoWithoutSocket {
|
19
|
+
socket: never;
|
20
|
+
cleanup: never;
|
21
|
+
shouldCreateNew: boolean;
|
22
|
+
}
|
23
|
+
export declare type FreeSocketInfo = FreeSocketInfoWithSocket | FreeSocketInfoWithoutSocket;
|
24
|
+
export declare class OriginPool {
|
25
|
+
private usedSockets;
|
26
|
+
private unusedSockets;
|
27
|
+
private waiting;
|
28
|
+
private keepAlive;
|
29
|
+
private keepAliveMsecs;
|
30
|
+
private maxSockets;
|
31
|
+
private maxFreeSockets;
|
32
|
+
private connOpts;
|
33
|
+
constructor(keepAlive: boolean, keepAliveMsecs: number, maxSockets: number, maxFreeSockets: number, timeout: number | void);
|
34
|
+
connect(options: RequestOptions): import("http").ClientRequest;
|
35
|
+
addUsed(socket: Socket): () => void;
|
36
|
+
getFreeSocket(): FreeSocketInfo;
|
37
|
+
waitForSocket(): Promise<SocketAndCleanup>;
|
38
|
+
disconnectAll(): Promise<void>;
|
39
|
+
private getFirstUnused;
|
40
|
+
private tryReuse;
|
41
|
+
private pumpWaiting;
|
42
|
+
private disconnectSocket;
|
43
|
+
private makeCleaner;
|
44
|
+
private moveToUnused;
|
45
|
+
private moveToUsed;
|
46
|
+
}
|
47
|
+
export declare class H1Context {
|
48
|
+
private contextPool;
|
49
|
+
constructor(options: Partial<Http1Options>);
|
50
|
+
getSessionForOrigin(origin: string): OriginPool;
|
51
|
+
getFreeSocketForSession(session: OriginPool): FreeSocketInfo;
|
52
|
+
addUsedSocket(session: OriginPool, socket: Socket): () => void;
|
53
|
+
waitForSocketBySession(session: OriginPool): Promise<SocketAndCleanup>;
|
54
|
+
connect(url: URL, extraOptions: ConnectOptions, request: Request): import("http").ClientRequest;
|
55
|
+
makeNewConnection(url: string): Promise<Socket>;
|
56
|
+
disconnect(url: string): void;
|
57
|
+
disconnectAll(): void;
|
58
|
+
}
|
@@ -0,0 +1,220 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.H1Context = exports.OriginPool = void 0;
|
4
|
+
const http_1 = require("http");
|
5
|
+
const https_1 = require("https");
|
6
|
+
const net_1 = require("net");
|
7
|
+
const url_1 = require("url");
|
8
|
+
const already_1 = require("already");
|
9
|
+
const core_1 = require("./core");
|
10
|
+
const utils_1 = require("./utils");
|
11
|
+
class OriginPool {
|
12
|
+
constructor(keepAlive, keepAliveMsecs, maxSockets, maxFreeSockets, timeout) {
|
13
|
+
this.usedSockets = new Set();
|
14
|
+
this.unusedSockets = new Set();
|
15
|
+
this.waiting = [];
|
16
|
+
this.keepAlive = keepAlive;
|
17
|
+
this.keepAliveMsecs = keepAliveMsecs;
|
18
|
+
this.maxSockets = maxSockets;
|
19
|
+
this.maxFreeSockets = maxFreeSockets;
|
20
|
+
this.connOpts = timeout == null ? {} : { timeout };
|
21
|
+
}
|
22
|
+
connect(options) {
|
23
|
+
const request = options.protocol === "https:"
|
24
|
+
? https_1.request
|
25
|
+
: http_1.request;
|
26
|
+
const opts = { ...options };
|
27
|
+
if (opts.rejectUnauthorized == null || options.protocol === "https")
|
28
|
+
delete opts.rejectUnauthorized;
|
29
|
+
const req = request({ ...this.connOpts, ...opts });
|
30
|
+
return req;
|
31
|
+
}
|
32
|
+
addUsed(socket) {
|
33
|
+
if (this.keepAlive)
|
34
|
+
socket.setKeepAlive(true, this.keepAliveMsecs);
|
35
|
+
socket.once("close", () => {
|
36
|
+
this.usedSockets.delete(socket);
|
37
|
+
this.unusedSockets.delete(socket);
|
38
|
+
});
|
39
|
+
this.usedSockets.add(socket);
|
40
|
+
return this.makeCleaner(socket);
|
41
|
+
}
|
42
|
+
getFreeSocket() {
|
43
|
+
const socketAndCleanup = this.getFirstUnused();
|
44
|
+
if (socketAndCleanup)
|
45
|
+
return { ...socketAndCleanup, shouldCreateNew: false };
|
46
|
+
const shouldCreateNew = this.maxSockets >= this.usedSockets.size;
|
47
|
+
return { shouldCreateNew };
|
48
|
+
}
|
49
|
+
waitForSocket() {
|
50
|
+
const deferred = (0, already_1.defer)();
|
51
|
+
this.waiting.push(deferred);
|
52
|
+
// Trigger due to potential race-condition
|
53
|
+
this.pumpWaiting();
|
54
|
+
return deferred.promise;
|
55
|
+
}
|
56
|
+
async disconnectAll() {
|
57
|
+
await Promise.all([...this.usedSockets, ...this.unusedSockets]
|
58
|
+
.map(socket => socket.destroyed ? void 0 : this.disconnectSocket(socket)));
|
59
|
+
const waiting = this.waiting;
|
60
|
+
this.waiting.length = 0;
|
61
|
+
waiting.forEach(waiter =>
|
62
|
+
// TODO: Better error class + message
|
63
|
+
waiter.reject(new Error("Disconnected")));
|
64
|
+
}
|
65
|
+
getFirstUnused() {
|
66
|
+
for (const socket of this.unusedSockets.values()) {
|
67
|
+
// We obviously have a socket
|
68
|
+
this.moveToUsed(socket);
|
69
|
+
return { socket, cleanup: this.makeCleaner(socket) };
|
70
|
+
}
|
71
|
+
return null;
|
72
|
+
}
|
73
|
+
tryReuse(socket) {
|
74
|
+
if (this.waiting.length === 0)
|
75
|
+
return false;
|
76
|
+
const waiting = this.waiting.shift();
|
77
|
+
waiting.resolve({ socket, cleanup: this.makeCleaner(socket) });
|
78
|
+
return true;
|
79
|
+
}
|
80
|
+
pumpWaiting() {
|
81
|
+
while (this.waiting.length > 0 && this.unusedSockets.size > 0) {
|
82
|
+
const socketAndCleanup = this.getFirstUnused();
|
83
|
+
const waiting = this.waiting.shift();
|
84
|
+
waiting.resolve(socketAndCleanup);
|
85
|
+
}
|
86
|
+
}
|
87
|
+
async disconnectSocket(socket) {
|
88
|
+
socket.destroy();
|
89
|
+
}
|
90
|
+
makeCleaner(socket) {
|
91
|
+
let hasCleaned = false;
|
92
|
+
return () => {
|
93
|
+
if (hasCleaned)
|
94
|
+
return;
|
95
|
+
hasCleaned = true;
|
96
|
+
if (!socket.destroyed)
|
97
|
+
this.moveToUnused(socket);
|
98
|
+
};
|
99
|
+
}
|
100
|
+
async moveToUnused(socket) {
|
101
|
+
if (this.tryReuse(socket))
|
102
|
+
return;
|
103
|
+
this.usedSockets.delete(socket);
|
104
|
+
if (this.maxFreeSockets < this.unusedSockets.size + 1) {
|
105
|
+
await this.disconnectSocket(socket);
|
106
|
+
return;
|
107
|
+
}
|
108
|
+
this.unusedSockets.add(socket);
|
109
|
+
socket.unref();
|
110
|
+
}
|
111
|
+
moveToUsed(socket) {
|
112
|
+
this.unusedSockets.delete(socket);
|
113
|
+
this.usedSockets.add(socket);
|
114
|
+
socket.ref();
|
115
|
+
return socket;
|
116
|
+
}
|
117
|
+
}
|
118
|
+
exports.OriginPool = OriginPool;
|
119
|
+
class ContextPool {
|
120
|
+
constructor(options) {
|
121
|
+
this.pools = new Map();
|
122
|
+
this.keepAlive = (0, core_1.parsePerOrigin)(options.keepAlive, true);
|
123
|
+
this.keepAliveMsecs = (0, core_1.parsePerOrigin)(options.keepAliveMsecs, 1000);
|
124
|
+
this.maxSockets = (0, core_1.parsePerOrigin)(options.maxSockets, 256);
|
125
|
+
this.maxFreeSockets = (0, core_1.parsePerOrigin)(options.maxFreeSockets, Infinity);
|
126
|
+
this.timeout = (0, core_1.parsePerOrigin)(options.timeout, void 0);
|
127
|
+
}
|
128
|
+
hasOrigin(origin) {
|
129
|
+
return this.pools.has(origin);
|
130
|
+
}
|
131
|
+
getOriginPool(origin) {
|
132
|
+
const pool = this.pools.get(origin);
|
133
|
+
if (!pool) {
|
134
|
+
const keepAlive = (0, core_1.getByOrigin)(this.keepAlive, origin);
|
135
|
+
const keepAliveMsecs = (0, core_1.getByOrigin)(this.keepAliveMsecs, origin);
|
136
|
+
const maxSockets = (0, core_1.getByOrigin)(this.maxSockets, origin);
|
137
|
+
const maxFreeSockets = (0, core_1.getByOrigin)(this.maxFreeSockets, origin);
|
138
|
+
const timeout = (0, core_1.getByOrigin)(this.timeout, origin);
|
139
|
+
const newPool = new OriginPool(keepAlive, keepAliveMsecs, maxSockets, maxFreeSockets, timeout);
|
140
|
+
this.pools.set(origin, newPool);
|
141
|
+
return newPool;
|
142
|
+
}
|
143
|
+
return pool;
|
144
|
+
}
|
145
|
+
async disconnect(origin) {
|
146
|
+
const pool = this.pools.get(origin);
|
147
|
+
if (pool)
|
148
|
+
await pool.disconnectAll();
|
149
|
+
}
|
150
|
+
async disconnectAll() {
|
151
|
+
const pools = [...this.pools.values()];
|
152
|
+
await Promise.all(pools.map(pool => pool.disconnectAll()));
|
153
|
+
}
|
154
|
+
}
|
155
|
+
function sessionToPool(session) {
|
156
|
+
return session;
|
157
|
+
}
|
158
|
+
class H1Context {
|
159
|
+
constructor(options) {
|
160
|
+
this.contextPool = new ContextPool(options);
|
161
|
+
}
|
162
|
+
getSessionForOrigin(origin) {
|
163
|
+
return this.contextPool.getOriginPool(origin);
|
164
|
+
}
|
165
|
+
getFreeSocketForSession(session) {
|
166
|
+
const pool = sessionToPool(session);
|
167
|
+
return pool.getFreeSocket();
|
168
|
+
}
|
169
|
+
addUsedSocket(session, socket) {
|
170
|
+
const pool = sessionToPool(session);
|
171
|
+
return pool.addUsed(socket);
|
172
|
+
}
|
173
|
+
waitForSocketBySession(session) {
|
174
|
+
return sessionToPool(session).waitForSocket();
|
175
|
+
}
|
176
|
+
connect(url, extraOptions, request) {
|
177
|
+
const { origin, protocol, hostname, password, pathname, search, username, } = url;
|
178
|
+
const path = pathname + search;
|
179
|
+
const port = parseInt((0, utils_1.parseInput)(url.href).port, 10);
|
180
|
+
const method = request.method;
|
181
|
+
const auth = (username || password)
|
182
|
+
? { auth: `${username}:${password}` }
|
183
|
+
: {};
|
184
|
+
const options = {
|
185
|
+
...extraOptions,
|
186
|
+
agent: false,
|
187
|
+
hostname,
|
188
|
+
method,
|
189
|
+
path,
|
190
|
+
port,
|
191
|
+
protocol,
|
192
|
+
...auth,
|
193
|
+
};
|
194
|
+
if (!options.headers)
|
195
|
+
options.headers = {};
|
196
|
+
options.headers.connection = this.contextPool.keepAlive
|
197
|
+
? "keep-alive"
|
198
|
+
: "close";
|
199
|
+
return this.contextPool.getOriginPool(origin).connect(options);
|
200
|
+
}
|
201
|
+
async makeNewConnection(url) {
|
202
|
+
return new Promise((resolve, reject) => {
|
203
|
+
const { hostname, port } = (0, utils_1.parseInput)(url);
|
204
|
+
const socket = (0, net_1.createConnection)(parseInt(port, 10), hostname, () => {
|
205
|
+
resolve(socket);
|
206
|
+
});
|
207
|
+
socket.once("error", reject);
|
208
|
+
return socket;
|
209
|
+
});
|
210
|
+
}
|
211
|
+
disconnect(url) {
|
212
|
+
const { origin } = new url_1.URL(url);
|
213
|
+
this.contextPool.disconnect(origin);
|
214
|
+
}
|
215
|
+
disconnectAll() {
|
216
|
+
this.contextPool.disconnectAll();
|
217
|
+
}
|
218
|
+
}
|
219
|
+
exports.H1Context = H1Context;
|
220
|
+
//# sourceMappingURL=context-http1.js.map
|
@@ -0,0 +1,39 @@
|
|
1
|
+
/// <reference types="node" />
|
2
|
+
import { ClientHttp2Session, SecureClientSessionOptions } from "http2";
|
3
|
+
import { Decoder } from "./core";
|
4
|
+
import { Request } from "./request";
|
5
|
+
import { Response } from "./response";
|
6
|
+
interface H2SessionItem {
|
7
|
+
firstOrigin: string;
|
8
|
+
session: ClientHttp2Session;
|
9
|
+
promise: Promise<ClientHttp2Session>;
|
10
|
+
ref: () => void;
|
11
|
+
unref: () => void;
|
12
|
+
}
|
13
|
+
export interface CacheableH2Session {
|
14
|
+
ref: () => void;
|
15
|
+
session: Promise<ClientHttp2Session>;
|
16
|
+
unref: () => void;
|
17
|
+
}
|
18
|
+
export declare type PushHandler = (origin: string, request: Request, getResponse: () => Promise<Response>) => void;
|
19
|
+
export declare type GetDecoders = (origin: string) => ReadonlyArray<Decoder>;
|
20
|
+
export declare type GetSessionOptions = (origin: string) => SecureClientSessionOptions;
|
21
|
+
export declare class H2Context {
|
22
|
+
_pushHandler?: PushHandler;
|
23
|
+
private _h2sessions;
|
24
|
+
private _h2staleSessions;
|
25
|
+
private _getDecoders;
|
26
|
+
private _getSessionOptions;
|
27
|
+
constructor(getDecoders: GetDecoders, getSessionOptions: GetSessionOptions);
|
28
|
+
createHttp2(origin: string, onGotGoaway: () => void, extraOptions?: SecureClientSessionOptions): CacheableH2Session;
|
29
|
+
disconnectSession(session: ClientHttp2Session): Promise<void>;
|
30
|
+
releaseSession(origin: string): void;
|
31
|
+
deleteActiveSession(origin: string): H2SessionItem | void;
|
32
|
+
disconnectStaleSessions(origin: string): Promise<void>;
|
33
|
+
disconnectAll(): Promise<void>;
|
34
|
+
disconnect(url: string, session?: ClientHttp2Session): Promise<void>;
|
35
|
+
private handleDisconnect;
|
36
|
+
private handlePush;
|
37
|
+
private connectHttp2;
|
38
|
+
}
|
39
|
+
export {};
|