undici 7.15.0 → 7.16.0
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/README.md +1 -1
- package/docs/docs/api/Agent.md +1 -0
- package/docs/docs/api/Errors.md +0 -1
- package/index-fetch.js +2 -2
- package/index.js +4 -8
- package/lib/api/api-request.js +22 -8
- package/lib/api/readable.js +7 -5
- package/lib/core/errors.js +217 -13
- package/lib/core/request.js +5 -1
- package/lib/core/util.js +32 -10
- package/lib/dispatcher/agent.js +19 -7
- package/lib/dispatcher/client-h1.js +20 -9
- package/lib/dispatcher/client-h2.js +13 -3
- package/lib/dispatcher/client.js +57 -57
- package/lib/dispatcher/dispatcher-base.js +12 -7
- package/lib/dispatcher/env-http-proxy-agent.js +12 -16
- package/lib/dispatcher/fixed-queue.js +15 -39
- package/lib/dispatcher/h2c-client.js +6 -6
- package/lib/dispatcher/pool-base.js +60 -43
- package/lib/dispatcher/pool.js +2 -2
- package/lib/dispatcher/proxy-agent.js +14 -9
- package/lib/global.js +19 -1
- package/lib/interceptor/cache.js +61 -0
- package/lib/mock/mock-agent.js +4 -4
- package/lib/mock/mock-errors.js +10 -0
- package/lib/mock/mock-utils.js +12 -10
- package/lib/util/date.js +534 -140
- package/lib/web/cookies/index.js +1 -1
- package/lib/web/eventsource/eventsource-stream.js +2 -2
- package/lib/web/eventsource/eventsource.js +34 -29
- package/lib/web/eventsource/util.js +1 -9
- package/lib/web/fetch/body.js +16 -22
- package/lib/web/fetch/index.js +14 -15
- package/lib/web/fetch/response.js +2 -4
- package/lib/web/fetch/util.js +8 -14
- package/lib/web/webidl/index.js +203 -42
- package/lib/web/websocket/connection.js +4 -3
- package/lib/web/websocket/events.js +1 -1
- package/lib/web/websocket/stream/websocketerror.js +22 -1
- package/lib/web/websocket/stream/websocketstream.js +16 -7
- package/lib/web/websocket/websocket.js +32 -42
- package/package.json +7 -6
- package/types/agent.d.ts +1 -0
- package/types/errors.d.ts +5 -15
- package/types/webidl.d.ts +82 -21
package/lib/dispatcher/agent.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { InvalidArgumentError } = require('../core/errors')
|
|
3
|
+
const { InvalidArgumentError, MaxOriginsReachedError } = require('../core/errors')
|
|
4
4
|
const { kClients, kRunning, kClose, kDestroy, kDispatch, kUrl } = require('../core/symbols')
|
|
5
5
|
const DispatcherBase = require('./dispatcher-base')
|
|
6
6
|
const Pool = require('./pool')
|
|
@@ -13,6 +13,7 @@ const kOnConnectionError = Symbol('onConnectionError')
|
|
|
13
13
|
const kOnDrain = Symbol('onDrain')
|
|
14
14
|
const kFactory = Symbol('factory')
|
|
15
15
|
const kOptions = Symbol('options')
|
|
16
|
+
const kOrigins = Symbol('origins')
|
|
16
17
|
|
|
17
18
|
function defaultFactory (origin, opts) {
|
|
18
19
|
return opts && opts.connections === 1
|
|
@@ -21,7 +22,7 @@ function defaultFactory (origin, opts) {
|
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
class Agent extends DispatcherBase {
|
|
24
|
-
constructor ({ factory = defaultFactory, connect, ...options } = {}) {
|
|
25
|
+
constructor ({ factory = defaultFactory, maxOrigins = Infinity, connect, ...options } = {}) {
|
|
25
26
|
if (typeof factory !== 'function') {
|
|
26
27
|
throw new InvalidArgumentError('factory must be a function.')
|
|
27
28
|
}
|
|
@@ -30,15 +31,20 @@ class Agent extends DispatcherBase {
|
|
|
30
31
|
throw new InvalidArgumentError('connect must be a function or an object')
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
if (typeof maxOrigins !== 'number' || Number.isNaN(maxOrigins) || maxOrigins <= 0) {
|
|
35
|
+
throw new InvalidArgumentError('maxOrigins must be a number greater than 0')
|
|
36
|
+
}
|
|
37
|
+
|
|
33
38
|
super()
|
|
34
39
|
|
|
35
40
|
if (connect && typeof connect !== 'function') {
|
|
36
41
|
connect = { ...connect }
|
|
37
42
|
}
|
|
38
43
|
|
|
39
|
-
this[kOptions] = { ...util.deepClone(options), connect }
|
|
44
|
+
this[kOptions] = { ...util.deepClone(options), maxOrigins, connect }
|
|
40
45
|
this[kFactory] = factory
|
|
41
46
|
this[kClients] = new Map()
|
|
47
|
+
this[kOrigins] = new Set()
|
|
42
48
|
|
|
43
49
|
this[kOnDrain] = (origin, targets) => {
|
|
44
50
|
this.emit('drain', origin, [this, ...targets])
|
|
@@ -73,6 +79,10 @@ class Agent extends DispatcherBase {
|
|
|
73
79
|
throw new InvalidArgumentError('opts.origin must be a non-empty string or URL.')
|
|
74
80
|
}
|
|
75
81
|
|
|
82
|
+
if (this[kOrigins].size >= this[kOptions].maxOrigins && !this[kOrigins].has(key)) {
|
|
83
|
+
throw new MaxOriginsReachedError()
|
|
84
|
+
}
|
|
85
|
+
|
|
76
86
|
const result = this[kClients].get(key)
|
|
77
87
|
let dispatcher = result && result.dispatcher
|
|
78
88
|
if (!dispatcher) {
|
|
@@ -84,6 +94,7 @@ class Agent extends DispatcherBase {
|
|
|
84
94
|
this[kClients].delete(key)
|
|
85
95
|
result.dispatcher.close()
|
|
86
96
|
}
|
|
97
|
+
this[kOrigins].delete(key)
|
|
87
98
|
}
|
|
88
99
|
}
|
|
89
100
|
dispatcher = this[kFactory](opts.origin, this[kOptions])
|
|
@@ -105,29 +116,30 @@ class Agent extends DispatcherBase {
|
|
|
105
116
|
})
|
|
106
117
|
|
|
107
118
|
this[kClients].set(key, { count: 0, dispatcher })
|
|
119
|
+
this[kOrigins].add(key)
|
|
108
120
|
}
|
|
109
121
|
|
|
110
122
|
return dispatcher.dispatch(opts, handler)
|
|
111
123
|
}
|
|
112
124
|
|
|
113
|
-
|
|
125
|
+
[kClose] () {
|
|
114
126
|
const closePromises = []
|
|
115
127
|
for (const { dispatcher } of this[kClients].values()) {
|
|
116
128
|
closePromises.push(dispatcher.close())
|
|
117
129
|
}
|
|
118
130
|
this[kClients].clear()
|
|
119
131
|
|
|
120
|
-
|
|
132
|
+
return Promise.all(closePromises)
|
|
121
133
|
}
|
|
122
134
|
|
|
123
|
-
|
|
135
|
+
[kDestroy] (err) {
|
|
124
136
|
const destroyPromises = []
|
|
125
137
|
for (const { dispatcher } of this[kClients].values()) {
|
|
126
138
|
destroyPromises.push(dispatcher.destroy(err))
|
|
127
139
|
}
|
|
128
140
|
this[kClients].clear()
|
|
129
141
|
|
|
130
|
-
|
|
142
|
+
return Promise.all(destroyPromises)
|
|
131
143
|
}
|
|
132
144
|
|
|
133
145
|
get stats () {
|
|
@@ -64,11 +64,26 @@ function lazyllhttp () {
|
|
|
64
64
|
const llhttpWasmData = process.env.JEST_WORKER_ID ? require('../llhttp/llhttp-wasm.js') : undefined
|
|
65
65
|
|
|
66
66
|
let mod
|
|
67
|
-
try {
|
|
68
|
-
mod = new WebAssembly.Module(require('../llhttp/llhttp_simd-wasm.js'))
|
|
69
|
-
} catch {
|
|
70
|
-
/* istanbul ignore next */
|
|
71
67
|
|
|
68
|
+
// We disable wasm SIMD on ppc64 as it seems to be broken on Power 9 architectures.
|
|
69
|
+
let useWasmSIMD = process.arch !== 'ppc64'
|
|
70
|
+
// The Env Variable UNDICI_NO_WASM_SIMD allows explicitly overriding the default behavior
|
|
71
|
+
if (process.env.UNDICI_NO_WASM_SIMD === '1') {
|
|
72
|
+
useWasmSIMD = true
|
|
73
|
+
} else if (process.env.UNDICI_NO_WASM_SIMD === '0') {
|
|
74
|
+
useWasmSIMD = false
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (useWasmSIMD) {
|
|
78
|
+
try {
|
|
79
|
+
mod = new WebAssembly.Module(require('../llhttp/llhttp_simd-wasm.js'))
|
|
80
|
+
/* istanbul ignore next */
|
|
81
|
+
} catch {
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* istanbul ignore next */
|
|
86
|
+
if (!mod) {
|
|
72
87
|
// We could check if the error was caused by the simd option not
|
|
73
88
|
// being enabled, but the occurring of this other error
|
|
74
89
|
// * https://github.com/emscripten-core/emscripten/issues/11495
|
|
@@ -325,10 +340,6 @@ class Parser {
|
|
|
325
340
|
currentBufferRef = chunk
|
|
326
341
|
currentParser = this
|
|
327
342
|
ret = llhttp.llhttp_execute(this.ptr, currentBufferPtr, chunk.length)
|
|
328
|
-
/* eslint-disable-next-line no-useless-catch */
|
|
329
|
-
} catch (err) {
|
|
330
|
-
/* istanbul ignore next: difficult to make a test case for */
|
|
331
|
-
throw err
|
|
332
343
|
} finally {
|
|
333
344
|
currentParser = null
|
|
334
345
|
currentBufferRef = null
|
|
@@ -760,7 +771,7 @@ function onParserTimeout (parser) {
|
|
|
760
771
|
* @param {import('net').Socket} socket
|
|
761
772
|
* @returns
|
|
762
773
|
*/
|
|
763
|
-
|
|
774
|
+
function connectH1 (client, socket) {
|
|
764
775
|
client[kSocket] = socket
|
|
765
776
|
|
|
766
777
|
if (!llhttpInstance) {
|
|
@@ -77,7 +77,7 @@ function parseH2Headers (headers) {
|
|
|
77
77
|
return result
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
function connectH2 (client, socket) {
|
|
81
81
|
client[kSocket] = socket
|
|
82
82
|
|
|
83
83
|
const session = http2.connect(client[kUrl], {
|
|
@@ -279,7 +279,7 @@ function shouldSendContentLength (method) {
|
|
|
279
279
|
function writeH2 (client, request) {
|
|
280
280
|
const requestTimeout = request.bodyTimeout ?? client[kBodyTimeout]
|
|
281
281
|
const session = client[kHTTP2Session]
|
|
282
|
-
const { method, path, host, upgrade, expectContinue, signal, headers: reqHeaders } = request
|
|
282
|
+
const { method, path, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request
|
|
283
283
|
let { body } = request
|
|
284
284
|
|
|
285
285
|
if (upgrade) {
|
|
@@ -292,6 +292,16 @@ function writeH2 (client, request) {
|
|
|
292
292
|
const key = reqHeaders[n + 0]
|
|
293
293
|
const val = reqHeaders[n + 1]
|
|
294
294
|
|
|
295
|
+
if (key === 'cookie') {
|
|
296
|
+
if (headers[key] != null) {
|
|
297
|
+
headers[key] = Array.isArray(headers[key]) ? (headers[key].push(val), headers[key]) : [headers[key], val]
|
|
298
|
+
} else {
|
|
299
|
+
headers[key] = val
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
continue
|
|
303
|
+
}
|
|
304
|
+
|
|
295
305
|
if (Array.isArray(val)) {
|
|
296
306
|
for (let i = 0; i < val.length; i++) {
|
|
297
307
|
if (headers[key]) {
|
|
@@ -387,7 +397,7 @@ function writeH2 (client, request) {
|
|
|
387
397
|
// :path and :scheme headers must be omitted when sending CONNECT
|
|
388
398
|
|
|
389
399
|
headers[HTTP2_HEADER_PATH] = path
|
|
390
|
-
headers[HTTP2_HEADER_SCHEME] = 'https'
|
|
400
|
+
headers[HTTP2_HEADER_SCHEME] = protocol === 'http:' ? 'http' : 'https'
|
|
391
401
|
|
|
392
402
|
// https://tools.ietf.org/html/rfc7231#section-4.3.1
|
|
393
403
|
// https://tools.ietf.org/html/rfc7231#section-4.3.2
|
package/lib/dispatcher/client.js
CHANGED
|
@@ -296,8 +296,7 @@ class Client extends DispatcherBase {
|
|
|
296
296
|
}
|
|
297
297
|
|
|
298
298
|
[kDispatch] (opts, handler) {
|
|
299
|
-
const
|
|
300
|
-
const request = new Request(origin, opts, handler)
|
|
299
|
+
const request = new Request(this[kUrl].origin, opts, handler)
|
|
301
300
|
|
|
302
301
|
this[kQueue].push(request)
|
|
303
302
|
if (this[kResuming]) {
|
|
@@ -317,7 +316,7 @@ class Client extends DispatcherBase {
|
|
|
317
316
|
return this[kNeedDrain] < 2
|
|
318
317
|
}
|
|
319
318
|
|
|
320
|
-
|
|
319
|
+
[kClose] () {
|
|
321
320
|
// TODO: for H2 we need to gracefully flush the remaining enqueued
|
|
322
321
|
// request and close each stream.
|
|
323
322
|
return new Promise((resolve) => {
|
|
@@ -329,7 +328,7 @@ class Client extends DispatcherBase {
|
|
|
329
328
|
})
|
|
330
329
|
}
|
|
331
330
|
|
|
332
|
-
|
|
331
|
+
[kDestroy] (err) {
|
|
333
332
|
return new Promise((resolve) => {
|
|
334
333
|
const requests = this[kQueue].splice(this[kPendingIdx])
|
|
335
334
|
for (let i = 0; i < requests.length; i++) {
|
|
@@ -381,9 +380,9 @@ function onError (client, err) {
|
|
|
381
380
|
|
|
382
381
|
/**
|
|
383
382
|
* @param {Client} client
|
|
384
|
-
* @returns
|
|
383
|
+
* @returns {void}
|
|
385
384
|
*/
|
|
386
|
-
|
|
385
|
+
function connect (client) {
|
|
387
386
|
assert(!client[kConnecting])
|
|
388
387
|
assert(!client[kHTTPContext])
|
|
389
388
|
|
|
@@ -417,26 +416,23 @@ async function connect (client) {
|
|
|
417
416
|
})
|
|
418
417
|
}
|
|
419
418
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
resolve(socket)
|
|
434
|
-
}
|
|
435
|
-
})
|
|
436
|
-
})
|
|
419
|
+
client[kConnector]({
|
|
420
|
+
host,
|
|
421
|
+
hostname,
|
|
422
|
+
protocol,
|
|
423
|
+
port,
|
|
424
|
+
servername: client[kServerName],
|
|
425
|
+
localAddress: client[kLocalAddress]
|
|
426
|
+
}, (err, socket) => {
|
|
427
|
+
if (err) {
|
|
428
|
+
handleConnectError(client, err, { host, hostname, protocol, port })
|
|
429
|
+
client[kResume]()
|
|
430
|
+
return
|
|
431
|
+
}
|
|
437
432
|
|
|
438
433
|
if (client.destroyed) {
|
|
439
434
|
util.destroy(socket.on('error', noop), new ClientDestroyedError())
|
|
435
|
+
client[kResume]()
|
|
440
436
|
return
|
|
441
437
|
}
|
|
442
438
|
|
|
@@ -444,11 +440,13 @@ async function connect (client) {
|
|
|
444
440
|
|
|
445
441
|
try {
|
|
446
442
|
client[kHTTPContext] = socket.alpnProtocol === 'h2'
|
|
447
|
-
?
|
|
448
|
-
:
|
|
443
|
+
? connectH2(client, socket)
|
|
444
|
+
: connectH1(client, socket)
|
|
449
445
|
} catch (err) {
|
|
450
446
|
socket.destroy().on('error', noop)
|
|
451
|
-
|
|
447
|
+
handleConnectError(client, err, { host, hostname, protocol, port })
|
|
448
|
+
client[kResume]()
|
|
449
|
+
return
|
|
452
450
|
}
|
|
453
451
|
|
|
454
452
|
client[kConnecting] = false
|
|
@@ -473,44 +471,46 @@ async function connect (client) {
|
|
|
473
471
|
socket
|
|
474
472
|
})
|
|
475
473
|
}
|
|
474
|
+
|
|
476
475
|
client.emit('connect', client[kUrl], [client])
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
}
|
|
476
|
+
client[kResume]()
|
|
477
|
+
})
|
|
478
|
+
}
|
|
481
479
|
|
|
482
|
-
|
|
480
|
+
function handleConnectError (client, err, { host, hostname, protocol, port }) {
|
|
481
|
+
if (client.destroyed) {
|
|
482
|
+
return
|
|
483
|
+
}
|
|
483
484
|
|
|
484
|
-
|
|
485
|
-
channels.connectError.publish({
|
|
486
|
-
connectParams: {
|
|
487
|
-
host,
|
|
488
|
-
hostname,
|
|
489
|
-
protocol,
|
|
490
|
-
port,
|
|
491
|
-
version: client[kHTTPContext]?.version,
|
|
492
|
-
servername: client[kServerName],
|
|
493
|
-
localAddress: client[kLocalAddress]
|
|
494
|
-
},
|
|
495
|
-
connector: client[kConnector],
|
|
496
|
-
error: err
|
|
497
|
-
})
|
|
498
|
-
}
|
|
485
|
+
client[kConnecting] = false
|
|
499
486
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
487
|
+
if (channels.connectError.hasSubscribers) {
|
|
488
|
+
channels.connectError.publish({
|
|
489
|
+
connectParams: {
|
|
490
|
+
host,
|
|
491
|
+
hostname,
|
|
492
|
+
protocol,
|
|
493
|
+
port,
|
|
494
|
+
version: client[kHTTPContext]?.version,
|
|
495
|
+
servername: client[kServerName],
|
|
496
|
+
localAddress: client[kLocalAddress]
|
|
497
|
+
},
|
|
498
|
+
connector: client[kConnector],
|
|
499
|
+
error: err
|
|
500
|
+
})
|
|
501
|
+
}
|
|
509
502
|
|
|
510
|
-
|
|
503
|
+
if (err.code === 'ERR_TLS_CERT_ALTNAME_INVALID') {
|
|
504
|
+
assert(client[kRunning] === 0)
|
|
505
|
+
while (client[kPending] > 0 && client[kQueue][client[kPendingIdx]].servername === client[kServerName]) {
|
|
506
|
+
const request = client[kQueue][client[kPendingIdx]++]
|
|
507
|
+
util.errorRequest(client, request, err)
|
|
508
|
+
}
|
|
509
|
+
} else {
|
|
510
|
+
onError(client, err)
|
|
511
511
|
}
|
|
512
512
|
|
|
513
|
-
client[
|
|
513
|
+
client.emit('connectionError', client[kUrl], [client], err)
|
|
514
514
|
}
|
|
515
515
|
|
|
516
516
|
function emitDrain (client) {
|
|
@@ -13,19 +13,24 @@ const kOnDestroyed = Symbol('onDestroyed')
|
|
|
13
13
|
const kOnClosed = Symbol('onClosed')
|
|
14
14
|
|
|
15
15
|
class DispatcherBase extends Dispatcher {
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
/** @type {boolean} */
|
|
17
|
+
[kDestroyed] = false;
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
/** @type {Array|null} */
|
|
20
|
+
[kOnDestroyed] = null;
|
|
21
|
+
|
|
22
|
+
/** @type {boolean} */
|
|
23
|
+
[kClosed] = false;
|
|
24
|
+
|
|
25
|
+
/** @type {Array} */
|
|
26
|
+
[kOnClosed] = []
|
|
24
27
|
|
|
28
|
+
/** @returns {boolean} */
|
|
25
29
|
get destroyed () {
|
|
26
30
|
return this[kDestroyed]
|
|
27
31
|
}
|
|
28
32
|
|
|
33
|
+
/** @returns {boolean} */
|
|
29
34
|
get closed () {
|
|
30
35
|
return this[kClosed]
|
|
31
36
|
}
|
|
@@ -46,24 +46,20 @@ class EnvHttpProxyAgent extends DispatcherBase {
|
|
|
46
46
|
return agent.dispatch(opts, handler)
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
await this[kHttpsProxyAgent].close()
|
|
56
|
-
}
|
|
49
|
+
[kClose] () {
|
|
50
|
+
return Promise.all([
|
|
51
|
+
this[kNoProxyAgent].close(),
|
|
52
|
+
!this[kHttpProxyAgent][kClosed] && this[kHttpProxyAgent].close(),
|
|
53
|
+
!this[kHttpsProxyAgent][kClosed] && this[kHttpsProxyAgent].close()
|
|
54
|
+
])
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
await this[kHttpsProxyAgent].destroy(err)
|
|
66
|
-
}
|
|
57
|
+
[kDestroy] (err) {
|
|
58
|
+
return Promise.all([
|
|
59
|
+
this[kNoProxyAgent].destroy(err),
|
|
60
|
+
!this[kHttpProxyAgent][kDestroyed] && this[kHttpProxyAgent].destroy(err),
|
|
61
|
+
!this[kHttpsProxyAgent][kDestroyed] && this[kHttpsProxyAgent].destroy(err)
|
|
62
|
+
])
|
|
67
63
|
}
|
|
68
64
|
|
|
69
65
|
#getProxyAgentForUrl (url) {
|
|
@@ -59,35 +59,21 @@ const kMask = kSize - 1
|
|
|
59
59
|
* @template T
|
|
60
60
|
*/
|
|
61
61
|
class FixedCircularBuffer {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
this.top = 0
|
|
71
|
-
/**
|
|
72
|
-
* @type {Array<T|undefined>}
|
|
73
|
-
*/
|
|
74
|
-
this.list = new Array(kSize).fill(undefined)
|
|
75
|
-
/**
|
|
76
|
-
* @type {T|null}
|
|
77
|
-
*/
|
|
78
|
-
this.next = null
|
|
79
|
-
}
|
|
62
|
+
/** @type {number} */
|
|
63
|
+
bottom = 0
|
|
64
|
+
/** @type {number} */
|
|
65
|
+
top = 0
|
|
66
|
+
/** @type {Array<T|undefined>} */
|
|
67
|
+
list = new Array(kSize).fill(undefined)
|
|
68
|
+
/** @type {T|null} */
|
|
69
|
+
next = null
|
|
80
70
|
|
|
81
|
-
/**
|
|
82
|
-
* @returns {boolean}
|
|
83
|
-
*/
|
|
71
|
+
/** @returns {boolean} */
|
|
84
72
|
isEmpty () {
|
|
85
73
|
return this.top === this.bottom
|
|
86
74
|
}
|
|
87
75
|
|
|
88
|
-
/**
|
|
89
|
-
* @returns {boolean}
|
|
90
|
-
*/
|
|
76
|
+
/** @returns {boolean} */
|
|
91
77
|
isFull () {
|
|
92
78
|
return ((this.top + 1) & kMask) === this.bottom
|
|
93
79
|
}
|
|
@@ -101,9 +87,7 @@ class FixedCircularBuffer {
|
|
|
101
87
|
this.top = (this.top + 1) & kMask
|
|
102
88
|
}
|
|
103
89
|
|
|
104
|
-
/**
|
|
105
|
-
* @returns {T|null}
|
|
106
|
-
*/
|
|
90
|
+
/** @returns {T|null} */
|
|
107
91
|
shift () {
|
|
108
92
|
const nextItem = this.list[this.bottom]
|
|
109
93
|
if (nextItem === undefined) { return null }
|
|
@@ -118,22 +102,16 @@ class FixedCircularBuffer {
|
|
|
118
102
|
*/
|
|
119
103
|
module.exports = class FixedQueue {
|
|
120
104
|
constructor () {
|
|
121
|
-
/**
|
|
122
|
-
* @type {FixedCircularBuffer<T>}
|
|
123
|
-
*/
|
|
105
|
+
/** @type {FixedCircularBuffer<T>} */
|
|
124
106
|
this.head = this.tail = new FixedCircularBuffer()
|
|
125
107
|
}
|
|
126
108
|
|
|
127
|
-
/**
|
|
128
|
-
* @returns {boolean}
|
|
129
|
-
*/
|
|
109
|
+
/** @returns {boolean} */
|
|
130
110
|
isEmpty () {
|
|
131
111
|
return this.head.isEmpty()
|
|
132
112
|
}
|
|
133
113
|
|
|
134
|
-
/**
|
|
135
|
-
* @param {T} data
|
|
136
|
-
*/
|
|
114
|
+
/** @param {T} data */
|
|
137
115
|
push (data) {
|
|
138
116
|
if (this.head.isFull()) {
|
|
139
117
|
// Head is full: Creates a new queue, sets the old queue's `.next` to it,
|
|
@@ -143,9 +121,7 @@ module.exports = class FixedQueue {
|
|
|
143
121
|
this.head.push(data)
|
|
144
122
|
}
|
|
145
123
|
|
|
146
|
-
/**
|
|
147
|
-
* @returns {T|null}
|
|
148
|
-
*/
|
|
124
|
+
/** @returns {T|null} */
|
|
149
125
|
shift () {
|
|
150
126
|
const tail = this.tail
|
|
151
127
|
const next = tail.shift()
|
|
@@ -12,8 +12,6 @@ class H2CClient extends DispatcherBase {
|
|
|
12
12
|
#client = null
|
|
13
13
|
|
|
14
14
|
constructor (origin, clientOpts) {
|
|
15
|
-
super()
|
|
16
|
-
|
|
17
15
|
if (typeof origin === 'string') {
|
|
18
16
|
origin = new URL(origin)
|
|
19
17
|
}
|
|
@@ -47,6 +45,8 @@ class H2CClient extends DispatcherBase {
|
|
|
47
45
|
)
|
|
48
46
|
}
|
|
49
47
|
|
|
48
|
+
super()
|
|
49
|
+
|
|
50
50
|
this.#client = new Client(origin, {
|
|
51
51
|
...opts,
|
|
52
52
|
connect: this.#buildConnector(connect),
|
|
@@ -110,12 +110,12 @@ class H2CClient extends DispatcherBase {
|
|
|
110
110
|
return this.#client.dispatch(opts, handler)
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
[kClose] () {
|
|
114
|
+
return this.#client.close()
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
[kDestroy] () {
|
|
118
|
+
return this.#client.destroy()
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
|