bdy 1.22.33-dev → 1.22.34-stage
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/distTs/package.json +1 -1
- package/distTs/src/tunnel/agent.js +74 -11
- package/distTs/src/tunnel/http.js +69 -10
- package/package.json +1 -1
package/distTs/package.json
CHANGED
|
@@ -9,7 +9,9 @@ const http2_1 = __importDefault(require("http2"));
|
|
|
9
9
|
const uuid_1 = require("uuid");
|
|
10
10
|
const texts_1 = require("../texts");
|
|
11
11
|
const CONNECTION_TIMEOUT = 5000;
|
|
12
|
-
const
|
|
12
|
+
const HTTP2_MAX_POOL_SIZE = 4;
|
|
13
|
+
const HTTP2_MAX_CONCURRENT_STREAMS = 100;
|
|
14
|
+
const HTTP2_MAX_LIFETIME_REQUESTS = 1000;
|
|
13
15
|
class TunnelAgent {
|
|
14
16
|
static httpAgent1;
|
|
15
17
|
static httpsAgent1;
|
|
@@ -40,34 +42,68 @@ class TunnelAgent {
|
|
|
40
42
|
TunnelAgent.deleteClient(authority, client, id);
|
|
41
43
|
reject(new Error(texts_1.ERR_CONNECTION_TIMEOUT));
|
|
42
44
|
}, CONNECTION_TIMEOUT);
|
|
45
|
+
let pingTs;
|
|
43
46
|
const client = http2_1.default.connect(authority, {
|
|
44
47
|
rejectUnauthorized: verify,
|
|
45
48
|
maxSessionMemory: 100,
|
|
46
49
|
servername,
|
|
47
50
|
});
|
|
51
|
+
client.setTimeout(60000);
|
|
48
52
|
client.once('close', () => {
|
|
53
|
+
clearInterval(pingTs);
|
|
54
|
+
TunnelAgent.deleteClient(authority, client, id);
|
|
55
|
+
});
|
|
56
|
+
client.once('goaway', () => {
|
|
57
|
+
clearInterval(pingTs);
|
|
49
58
|
TunnelAgent.deleteClient(authority, client, id);
|
|
50
59
|
});
|
|
51
60
|
client.once('timeout', () => {
|
|
61
|
+
clearInterval(pingTs);
|
|
52
62
|
TunnelAgent.deleteClient(authority, client, id);
|
|
53
63
|
});
|
|
54
64
|
client.once('error', () => {
|
|
55
65
|
clearTimeout(ts);
|
|
66
|
+
clearInterval(pingTs);
|
|
56
67
|
TunnelAgent.deleteClient(authority, client, id);
|
|
57
68
|
reject(new Error(texts_1.ERR_CONNECTION_ERROR));
|
|
58
69
|
});
|
|
59
70
|
client.once('connect', () => {
|
|
60
71
|
clearTimeout(ts);
|
|
72
|
+
pingTs = setInterval(() => {
|
|
73
|
+
if (client.closed || client.destroyed)
|
|
74
|
+
return;
|
|
75
|
+
let acked = false;
|
|
76
|
+
const ackTs = setTimeout(() => {
|
|
77
|
+
if (!acked) {
|
|
78
|
+
clearInterval(pingTs);
|
|
79
|
+
TunnelAgent.deleteClient(authority, client, id);
|
|
80
|
+
}
|
|
81
|
+
}, 5000);
|
|
82
|
+
try {
|
|
83
|
+
client.ping(() => {
|
|
84
|
+
acked = true;
|
|
85
|
+
clearTimeout(ackTs);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
clearTimeout(ackTs);
|
|
90
|
+
clearInterval(pingTs);
|
|
91
|
+
TunnelAgent.deleteClient(authority, client, id);
|
|
92
|
+
}
|
|
93
|
+
}, 10000);
|
|
61
94
|
resolve(client);
|
|
62
95
|
});
|
|
63
96
|
});
|
|
64
97
|
}
|
|
65
98
|
static deleteClient(authority, client, id) {
|
|
66
99
|
if (this.http2Clients && this.http2Clients[authority]) {
|
|
67
|
-
if (this.http2Clients[authority][id])
|
|
100
|
+
if (this.http2Clients[authority][id]) {
|
|
101
|
+
this.http2Clients[authority][id].closed = true;
|
|
68
102
|
delete this.http2Clients[authority][id];
|
|
69
|
-
|
|
103
|
+
}
|
|
104
|
+
if (!Object.keys(this.http2Clients[authority]).length) {
|
|
70
105
|
delete this.http2Clients[authority];
|
|
106
|
+
}
|
|
71
107
|
}
|
|
72
108
|
try {
|
|
73
109
|
client.removeAllListeners();
|
|
@@ -82,22 +118,49 @@ class TunnelAgent {
|
|
|
82
118
|
this.http2Clients = {};
|
|
83
119
|
if (!this.http2Clients[authority])
|
|
84
120
|
this.http2Clients[authority] = {};
|
|
85
|
-
const
|
|
121
|
+
const pool = this.http2Clients[authority];
|
|
122
|
+
let best = null;
|
|
123
|
+
let bestLoad = Infinity;
|
|
124
|
+
const keys = Object.keys(pool);
|
|
86
125
|
for (let i = 0; i < keys.length; i += 1) {
|
|
87
126
|
const id = keys[i];
|
|
88
|
-
const
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
|
|
127
|
+
const c = pool[id];
|
|
128
|
+
if (c.hasCapacity() && c.concurrent < bestLoad) {
|
|
129
|
+
best = c;
|
|
130
|
+
bestLoad = c.concurrent;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (best)
|
|
134
|
+
return best;
|
|
135
|
+
if (keys.length >= HTTP2_MAX_POOL_SIZE) {
|
|
136
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
137
|
+
const id = keys[i];
|
|
138
|
+
const c = pool[id];
|
|
139
|
+
if (c.concurrent < bestLoad) {
|
|
140
|
+
best = c;
|
|
141
|
+
bestLoad = c.concurrent;
|
|
142
|
+
}
|
|
92
143
|
}
|
|
93
144
|
}
|
|
145
|
+
if (best)
|
|
146
|
+
return best;
|
|
94
147
|
const id = (0, uuid_1.v4)();
|
|
95
148
|
const promise = this.createHttp2Client(authority, servername, verify, id);
|
|
96
|
-
|
|
149
|
+
best = {
|
|
97
150
|
promise,
|
|
98
|
-
|
|
151
|
+
closed: false,
|
|
152
|
+
requests: 0,
|
|
153
|
+
concurrent: 0,
|
|
154
|
+
hasCapacity: function () {
|
|
155
|
+
if (this.closed)
|
|
156
|
+
return false;
|
|
157
|
+
if (this.requests >= HTTP2_MAX_LIFETIME_REQUESTS)
|
|
158
|
+
return false;
|
|
159
|
+
return this.concurrent < HTTP2_MAX_CONCURRENT_STREAMS;
|
|
160
|
+
},
|
|
99
161
|
};
|
|
100
|
-
|
|
162
|
+
this.http2Clients[authority][id] = best;
|
|
163
|
+
return best;
|
|
101
164
|
}
|
|
102
165
|
}
|
|
103
166
|
exports.default = TunnelAgent;
|
|
@@ -243,10 +243,14 @@ class TunnelHttp extends events_1.default {
|
|
|
243
243
|
const compressionMethod = compression_1.default.detect(this.compression || false, reqHeaders, resHeaders);
|
|
244
244
|
this.outputHeaders(statusCode, this.getClearedHeaders(resHeaders, compressionMethod));
|
|
245
245
|
if (this.logRequest) {
|
|
246
|
-
(0, node_stream_1.pipeline)(this.proxyRes, this.logRequest.responseBody, compression_1.default.compress(compressionMethod), this.res, () => {
|
|
246
|
+
(0, node_stream_1.pipeline)(this.proxyRes, this.logRequest.responseBody, compression_1.default.compress(compressionMethod), this.res, () => {
|
|
247
|
+
this.clear();
|
|
248
|
+
});
|
|
247
249
|
}
|
|
248
250
|
else {
|
|
249
|
-
(0, node_stream_1.pipeline)(this.proxyRes, compression_1.default.compress(compressionMethod), this.res, () => {
|
|
251
|
+
(0, node_stream_1.pipeline)(this.proxyRes, compression_1.default.compress(compressionMethod), this.res, () => {
|
|
252
|
+
this.clear();
|
|
253
|
+
});
|
|
250
254
|
}
|
|
251
255
|
if (this.httpLog) {
|
|
252
256
|
this.httpLog.newResponse(statusCode, resHeaders, this.logRequest);
|
|
@@ -286,10 +290,14 @@ class TunnelHttp extends events_1.default {
|
|
|
286
290
|
const compressionMethod = compression_1.default.detect(this.compression || false, reqHeaders, resHeaders);
|
|
287
291
|
this.outputHeaders(statusCode, this.getClearedHeaders(resHeaders, compressionMethod));
|
|
288
292
|
if (this.logRequest) {
|
|
289
|
-
(0, node_stream_1.pipeline)(this.proxyRes, this.logRequest.responseBody, compression_1.default.compress(compressionMethod), this.res, () => {
|
|
293
|
+
(0, node_stream_1.pipeline)(this.proxyRes, this.logRequest.responseBody, compression_1.default.compress(compressionMethod), this.res, () => {
|
|
294
|
+
this.clear();
|
|
295
|
+
});
|
|
290
296
|
}
|
|
291
297
|
else {
|
|
292
|
-
(0, node_stream_1.pipeline)(this.proxyRes, compression_1.default.compress(compressionMethod), this.res, () => {
|
|
298
|
+
(0, node_stream_1.pipeline)(this.proxyRes, compression_1.default.compress(compressionMethod), this.res, () => {
|
|
299
|
+
this.clear();
|
|
300
|
+
});
|
|
293
301
|
}
|
|
294
302
|
if (this.httpLog) {
|
|
295
303
|
this.httpLog.newResponse(statusCode, resHeaders, this.logRequest);
|
|
@@ -314,10 +322,14 @@ class TunnelHttp extends events_1.default {
|
|
|
314
322
|
const compressionMethod = compression_1.default.detect(this.compression || false, reqHeaders, resHeaders);
|
|
315
323
|
this.outputHeaders(statusCode, this.getClearedHeaders(resHeaders, compressionMethod));
|
|
316
324
|
if (this.logRequest) {
|
|
317
|
-
(0, node_stream_1.pipeline)(stream, this.logRequest.responseBody, compression_1.default.compress(compressionMethod), this.res, () => {
|
|
325
|
+
(0, node_stream_1.pipeline)(stream, this.logRequest.responseBody, compression_1.default.compress(compressionMethod), this.res, () => {
|
|
326
|
+
this.clear();
|
|
327
|
+
});
|
|
318
328
|
}
|
|
319
329
|
else {
|
|
320
|
-
(0, node_stream_1.pipeline)(stream, compression_1.default.compress(compressionMethod), this.res, () => {
|
|
330
|
+
(0, node_stream_1.pipeline)(stream, compression_1.default.compress(compressionMethod), this.res, () => {
|
|
331
|
+
this.clear();
|
|
332
|
+
});
|
|
321
333
|
}
|
|
322
334
|
}
|
|
323
335
|
if (this.httpLog) {
|
|
@@ -326,10 +338,32 @@ class TunnelHttp extends events_1.default {
|
|
|
326
338
|
});
|
|
327
339
|
return r;
|
|
328
340
|
}
|
|
341
|
+
async getHttp2Client(authority) {
|
|
342
|
+
let c = agent_1.default.getHttp2Client(authority, this.host || '', this.verify || false);
|
|
343
|
+
let client;
|
|
344
|
+
try {
|
|
345
|
+
client = await c.promise;
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
// do nothing
|
|
349
|
+
}
|
|
350
|
+
if (c.closed || !client || client.closed || client.destroyed) {
|
|
351
|
+
// try again
|
|
352
|
+
c = agent_1.default.getHttp2Client(authority, this.host || '', this.verify || false);
|
|
353
|
+
client = await c.promise;
|
|
354
|
+
}
|
|
355
|
+
if (c.closed || !client || client.closed || client.destroyed) {
|
|
356
|
+
throw new Error(texts_1.ERR_CONNECTION_ERROR);
|
|
357
|
+
}
|
|
358
|
+
return {
|
|
359
|
+
client,
|
|
360
|
+
c,
|
|
361
|
+
};
|
|
362
|
+
}
|
|
329
363
|
async createRequestHttps2() {
|
|
330
364
|
const reqHeaders = this.req.headers;
|
|
331
365
|
const authority = `${this.proto}://${(0, utils_1.getRealTargetHost)(this.host)}:${this.port}`;
|
|
332
|
-
const client = await
|
|
366
|
+
const { c, client } = await this.getHttp2Client(authority);
|
|
333
367
|
const method = this.getMethod();
|
|
334
368
|
const path = this.getPath();
|
|
335
369
|
const headers = {
|
|
@@ -337,28 +371,53 @@ class TunnelHttp extends events_1.default {
|
|
|
337
371
|
...this.headers,
|
|
338
372
|
...this.getRequestHeaders(true),
|
|
339
373
|
};
|
|
340
|
-
|
|
374
|
+
c.requests += 1;
|
|
375
|
+
c.concurrent += 1;
|
|
376
|
+
let concurrentDecremented = false;
|
|
377
|
+
const decrementConcurrent = () => {
|
|
378
|
+
if (concurrentDecremented)
|
|
379
|
+
return;
|
|
380
|
+
concurrentDecremented = true;
|
|
381
|
+
if (c.concurrent > 0)
|
|
382
|
+
c.concurrent -= 1;
|
|
383
|
+
};
|
|
384
|
+
let r;
|
|
385
|
+
try {
|
|
386
|
+
r = client.request(headers);
|
|
387
|
+
}
|
|
388
|
+
catch (err) {
|
|
389
|
+
decrementConcurrent();
|
|
390
|
+
throw err;
|
|
391
|
+
}
|
|
341
392
|
if (this.httpLog) {
|
|
342
393
|
this.logRequest = this.httpLog.newRequest(method, headers, path, tunnel_1.TUNNEL_HTTP_IDENTIFY.HTTP2, this.req);
|
|
343
394
|
}
|
|
344
395
|
r.on('error', () => {
|
|
345
396
|
try {
|
|
397
|
+
decrementConcurrent();
|
|
346
398
|
this.res.end();
|
|
347
399
|
}
|
|
348
400
|
catch {
|
|
349
401
|
// do nothing
|
|
350
402
|
}
|
|
351
403
|
});
|
|
404
|
+
r.once('close', decrementConcurrent);
|
|
352
405
|
r.on('response', (resHeaders) => {
|
|
353
406
|
r.setTimeout(0);
|
|
354
407
|
const status = resHeaders[':status'] || 200;
|
|
355
408
|
const compressionMethod = compression_1.default.detect(this.compression || false, reqHeaders, resHeaders);
|
|
356
409
|
this.outputHeaders(status, this.getClearedHeaders(resHeaders, compressionMethod));
|
|
357
410
|
if (this.logRequest) {
|
|
358
|
-
(0, node_stream_1.pipeline)(r, this.logRequest.responseBody, compression_1.default.compress(compressionMethod), this.res, () => {
|
|
411
|
+
(0, node_stream_1.pipeline)(r, this.logRequest.responseBody, compression_1.default.compress(compressionMethod), this.res, () => {
|
|
412
|
+
decrementConcurrent();
|
|
413
|
+
this.clear();
|
|
414
|
+
});
|
|
359
415
|
}
|
|
360
416
|
else {
|
|
361
|
-
(0, node_stream_1.pipeline)(r, compression_1.default.compress(compressionMethod), this.res, () => {
|
|
417
|
+
(0, node_stream_1.pipeline)(r, compression_1.default.compress(compressionMethod), this.res, () => {
|
|
418
|
+
decrementConcurrent();
|
|
419
|
+
this.clear();
|
|
420
|
+
});
|
|
362
421
|
}
|
|
363
422
|
if (this.httpLog) {
|
|
364
423
|
this.httpLog.newResponse(status, resHeaders, this.logRequest);
|