undici 6.25.0 → 6.27.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/docs/docs/api/Client.md +1 -0
- package/lib/dispatcher/agent.js +0 -1
- package/lib/dispatcher/client-h1.js +140 -23
- package/lib/dispatcher/dispatcher-base.js +1 -0
- package/lib/web/cookies/parse.js +16 -23
- package/lib/web/websocket/receiver.js +31 -8
- package/lib/web/websocket/websocket.js +4 -1
- package/package.json +1 -1
- package/types/client.d.ts +6 -0
package/docs/docs/api/Client.md
CHANGED
|
@@ -27,6 +27,7 @@ Returns: `Client`
|
|
|
27
27
|
* **maxHeaderSize** `number | null` (optional) - Default: `--max-http-header-size` or `16384` - The maximum length of request headers in bytes. Defaults to Node.js' --max-http-header-size or 16KiB.
|
|
28
28
|
* **maxResponseSize** `number | null` (optional) - Default: `-1` - The maximum length of response body in bytes. Set to `-1` to disable.
|
|
29
29
|
* **webSocket** `WebSocketOptions` (optional) - WebSocket-specific configuration options.
|
|
30
|
+
* **maxFragments** `number` (optional) - Default: `131072` - Maximum number of fragments in a message. Set to 0 to disable the limit.
|
|
30
31
|
* **maxPayloadSize** `number` (optional) - Default: `134217728` (128 MB) - Maximum allowed payload size in bytes for WebSocket messages. Applied to uncompressed messages, compressed frame payloads, and decompressed (permessage-deflate) messages. Set to 0 to disable the limit.
|
|
31
32
|
* **pipelining** `number | null` (optional) - Default: `1` - The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Carefully consider your workload and environment before enabling concurrent requests as pipelining may reduce performance if used incorrectly. Pipelining is sensitive to network stack settings as well as head of line blocking caused by e.g. long running requests. Set to `0` to disable keep-alive connections.
|
|
32
33
|
* **connect** `ConnectOptions | Function | null` (optional) - Default: `null`.
|
package/lib/dispatcher/agent.js
CHANGED
|
@@ -24,7 +24,6 @@ function defaultFactory (origin, opts) {
|
|
|
24
24
|
|
|
25
25
|
class Agent extends DispatcherBase {
|
|
26
26
|
constructor ({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) {
|
|
27
|
-
|
|
28
27
|
if (typeof factory !== 'function') {
|
|
29
28
|
throw new InvalidArgumentError('factory must be a function.')
|
|
30
29
|
}
|
|
@@ -57,6 +57,9 @@ const EMPTY_BUF = Buffer.alloc(0)
|
|
|
57
57
|
const FastBuffer = Buffer[Symbol.species]
|
|
58
58
|
const addListener = util.addListener
|
|
59
59
|
const removeAllListeners = util.removeAllListeners
|
|
60
|
+
const kIdleSocketValidation = Symbol('kIdleSocketValidation')
|
|
61
|
+
const kIdleSocketValidationTimeout = Symbol('kIdleSocketValidationTimeout')
|
|
62
|
+
const kSocketUsed = Symbol('kSocketUsed')
|
|
60
63
|
|
|
61
64
|
let extractBody
|
|
62
65
|
|
|
@@ -279,29 +282,71 @@ class Parser {
|
|
|
279
282
|
|
|
280
283
|
const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr
|
|
281
284
|
|
|
282
|
-
if (ret
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0)
|
|
293
|
-
message =
|
|
294
|
-
'Response does not match the HTTP/1.1 protocol (' +
|
|
295
|
-
Buffer.from(llhttp.memory.buffer, ptr, len).toString() +
|
|
296
|
-
')'
|
|
285
|
+
if (ret !== constants.ERROR.OK) {
|
|
286
|
+
const body = data.subarray(offset)
|
|
287
|
+
|
|
288
|
+
if (ret === constants.ERROR.PAUSED_UPGRADE) {
|
|
289
|
+
this.onUpgrade(body)
|
|
290
|
+
} else if (ret === constants.ERROR.PAUSED) {
|
|
291
|
+
this.paused = true
|
|
292
|
+
socket.unshift(body)
|
|
293
|
+
} else {
|
|
294
|
+
throw this.createError(ret, body)
|
|
297
295
|
}
|
|
298
|
-
throw new HTTPParserError(message, constants.ERROR[ret], data.slice(offset))
|
|
299
296
|
}
|
|
300
297
|
} catch (err) {
|
|
301
298
|
util.destroy(socket, err)
|
|
302
299
|
}
|
|
303
300
|
}
|
|
304
301
|
|
|
302
|
+
finish () {
|
|
303
|
+
assert(currentParser === null)
|
|
304
|
+
assert(this.ptr != null)
|
|
305
|
+
assert(!this.paused)
|
|
306
|
+
|
|
307
|
+
const { llhttp } = this
|
|
308
|
+
|
|
309
|
+
let ret
|
|
310
|
+
|
|
311
|
+
try {
|
|
312
|
+
currentParser = this
|
|
313
|
+
ret = llhttp.llhttp_finish(this.ptr)
|
|
314
|
+
} finally {
|
|
315
|
+
currentParser = null
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (ret === constants.ERROR.OK) {
|
|
319
|
+
return null
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (ret === constants.ERROR.PAUSED || ret === constants.ERROR.PAUSED_UPGRADE) {
|
|
323
|
+
this.paused = true
|
|
324
|
+
return null
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return this.createError(ret, EMPTY_BUF)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
createError (ret, data) {
|
|
331
|
+
const { llhttp, contentLength, bytesRead } = this
|
|
332
|
+
|
|
333
|
+
if (contentLength && bytesRead !== parseInt(contentLength, 10)) {
|
|
334
|
+
return new ResponseContentLengthMismatchError()
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const ptr = llhttp.llhttp_get_error_reason(this.ptr)
|
|
338
|
+
let message = ''
|
|
339
|
+
if (ptr) {
|
|
340
|
+
const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0)
|
|
341
|
+
message =
|
|
342
|
+
'Response does not match the HTTP/1.1 protocol (' +
|
|
343
|
+
Buffer.from(llhttp.memory.buffer, ptr, len).toString() +
|
|
344
|
+
')'
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return new HTTPParserError(message, constants.ERROR[ret], data)
|
|
348
|
+
}
|
|
349
|
+
|
|
305
350
|
destroy () {
|
|
306
351
|
assert(this.ptr != null)
|
|
307
352
|
assert(currentParser == null)
|
|
@@ -329,6 +374,11 @@ class Parser {
|
|
|
329
374
|
return -1
|
|
330
375
|
}
|
|
331
376
|
|
|
377
|
+
if (client[kRunning] === 0) {
|
|
378
|
+
util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket)))
|
|
379
|
+
return -1
|
|
380
|
+
}
|
|
381
|
+
|
|
332
382
|
const request = client[kQueue][client[kRunningIdx]]
|
|
333
383
|
if (!request) {
|
|
334
384
|
return -1
|
|
@@ -432,6 +482,11 @@ class Parser {
|
|
|
432
482
|
return -1
|
|
433
483
|
}
|
|
434
484
|
|
|
485
|
+
if (client[kRunning] === 0) {
|
|
486
|
+
util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket)))
|
|
487
|
+
return -1
|
|
488
|
+
}
|
|
489
|
+
|
|
435
490
|
const request = client[kQueue][client[kRunningIdx]]
|
|
436
491
|
|
|
437
492
|
/* istanbul ignore next: difficult to make a test case for */
|
|
@@ -605,6 +660,7 @@ class Parser {
|
|
|
605
660
|
request.onComplete(headers)
|
|
606
661
|
|
|
607
662
|
client[kQueue][client[kRunningIdx]++] = null
|
|
663
|
+
socket[kSocketUsed] = true
|
|
608
664
|
|
|
609
665
|
if (socket[kWriting]) {
|
|
610
666
|
assert(client[kRunning] === 0)
|
|
@@ -663,6 +719,9 @@ async function connectH1 (client, socket) {
|
|
|
663
719
|
socket[kWriting] = false
|
|
664
720
|
socket[kReset] = false
|
|
665
721
|
socket[kBlocking] = false
|
|
722
|
+
socket[kIdleSocketValidation] = 0
|
|
723
|
+
socket[kIdleSocketValidationTimeout] = null
|
|
724
|
+
socket[kSocketUsed] = false
|
|
666
725
|
socket[kParser] = new Parser(client, socket, llhttpInstance)
|
|
667
726
|
|
|
668
727
|
addListener(socket, 'error', function (err) {
|
|
@@ -673,8 +732,11 @@ async function connectH1 (client, socket) {
|
|
|
673
732
|
// On Mac OS, we get an ECONNRESET even if there is a full body to be forwarded
|
|
674
733
|
// to the user.
|
|
675
734
|
if (err.code === 'ECONNRESET' && parser.statusCode && !parser.shouldKeepAlive) {
|
|
676
|
-
|
|
677
|
-
|
|
735
|
+
const parserErr = parser.finish()
|
|
736
|
+
if (parserErr) {
|
|
737
|
+
this[kError] = parserErr
|
|
738
|
+
this[kClient][kOnError](parserErr)
|
|
739
|
+
}
|
|
678
740
|
return
|
|
679
741
|
}
|
|
680
742
|
|
|
@@ -693,8 +755,10 @@ async function connectH1 (client, socket) {
|
|
|
693
755
|
const parser = this[kParser]
|
|
694
756
|
|
|
695
757
|
if (parser.statusCode && !parser.shouldKeepAlive) {
|
|
696
|
-
|
|
697
|
-
|
|
758
|
+
const parserErr = parser.finish()
|
|
759
|
+
if (parserErr) {
|
|
760
|
+
util.destroy(this, parserErr)
|
|
761
|
+
}
|
|
698
762
|
return
|
|
699
763
|
}
|
|
700
764
|
|
|
@@ -704,10 +768,11 @@ async function connectH1 (client, socket) {
|
|
|
704
768
|
const client = this[kClient]
|
|
705
769
|
const parser = this[kParser]
|
|
706
770
|
|
|
771
|
+
clearIdleSocketValidation(this)
|
|
772
|
+
|
|
707
773
|
if (parser) {
|
|
708
774
|
if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) {
|
|
709
|
-
|
|
710
|
-
parser.onMessageComplete()
|
|
775
|
+
this[kError] = parser.finish() || this[kError]
|
|
711
776
|
}
|
|
712
777
|
|
|
713
778
|
this[kParser].destroy()
|
|
@@ -770,7 +835,7 @@ async function connectH1 (client, socket) {
|
|
|
770
835
|
return socket.destroyed
|
|
771
836
|
},
|
|
772
837
|
busy (request) {
|
|
773
|
-
if (socket[kWriting] || socket[kReset] || socket[kBlocking]) {
|
|
838
|
+
if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) {
|
|
774
839
|
return true
|
|
775
840
|
}
|
|
776
841
|
|
|
@@ -808,6 +873,31 @@ async function connectH1 (client, socket) {
|
|
|
808
873
|
}
|
|
809
874
|
}
|
|
810
875
|
|
|
876
|
+
function clearIdleSocketValidation (socket) {
|
|
877
|
+
if (socket[kIdleSocketValidationTimeout]) {
|
|
878
|
+
clearTimeout(socket[kIdleSocketValidationTimeout])
|
|
879
|
+
socket[kIdleSocketValidationTimeout] = null
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
socket[kIdleSocketValidation] = 0
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
function scheduleIdleSocketValidation (client, socket) {
|
|
886
|
+
socket[kIdleSocketValidation] = 1
|
|
887
|
+
socket[kIdleSocketValidationTimeout] = setTimeout(() => {
|
|
888
|
+
socket[kIdleSocketValidationTimeout] = null
|
|
889
|
+
socket[kIdleSocketValidation] = 2
|
|
890
|
+
|
|
891
|
+
if (client[kSocket] === socket && !socket.destroyed) {
|
|
892
|
+
client[kResume]()
|
|
893
|
+
}
|
|
894
|
+
}, 0)
|
|
895
|
+
socket[kIdleSocketValidationTimeout].unref?.()
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
/**
|
|
899
|
+
* @param {import('./client.js')} client
|
|
900
|
+
*/
|
|
811
901
|
function resumeH1 (client) {
|
|
812
902
|
const socket = client[kSocket]
|
|
813
903
|
|
|
@@ -822,6 +912,32 @@ function resumeH1 (client) {
|
|
|
822
912
|
socket[kNoRef] = false
|
|
823
913
|
}
|
|
824
914
|
|
|
915
|
+
if (client[kRunning] === 0 && client[kPending] > 0 && socket[kSocketUsed]) {
|
|
916
|
+
if (socket[kIdleSocketValidation] === 0) {
|
|
917
|
+
scheduleIdleSocketValidation(client, socket)
|
|
918
|
+
socket[kParser].readMore()
|
|
919
|
+
if (socket.destroyed) {
|
|
920
|
+
return
|
|
921
|
+
}
|
|
922
|
+
return
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
if (socket[kIdleSocketValidation] === 1) {
|
|
926
|
+
socket[kParser].readMore()
|
|
927
|
+
if (socket.destroyed) {
|
|
928
|
+
return
|
|
929
|
+
}
|
|
930
|
+
return
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
if (client[kRunning] === 0) {
|
|
935
|
+
socket[kParser].readMore()
|
|
936
|
+
if (socket.destroyed) {
|
|
937
|
+
return
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
825
941
|
if (client[kSize] === 0) {
|
|
826
942
|
if (socket[kParser].timeoutType !== TIMEOUT_KEEP_ALIVE) {
|
|
827
943
|
socket[kParser].setTimeout(client[kKeepAliveTimeoutValue], TIMEOUT_KEEP_ALIVE)
|
|
@@ -915,6 +1031,7 @@ function writeH1 (client, request) {
|
|
|
915
1031
|
}
|
|
916
1032
|
|
|
917
1033
|
const socket = client[kSocket]
|
|
1034
|
+
clearIdleSocketValidation(socket)
|
|
918
1035
|
|
|
919
1036
|
const abort = (err) => {
|
|
920
1037
|
if (request.aborted || request.completed) {
|
package/lib/web/cookies/parse.js
CHANGED
|
@@ -275,32 +275,25 @@ function parseUnparsedAttributes (unparsedAttributes, cookieAttributeList = {})
|
|
|
275
275
|
// If the attribute-name case-insensitively matches the string
|
|
276
276
|
// "SameSite", the user agent MUST process the cookie-av as follows:
|
|
277
277
|
|
|
278
|
-
// 1. Let enforcement be "Default".
|
|
279
|
-
let enforcement = 'Default'
|
|
280
|
-
|
|
281
278
|
const attributeValueLowercase = attributeValue.toLowerCase()
|
|
282
|
-
// 2. If cookie-av's attribute-value is a case-insensitive match for
|
|
283
|
-
// "None", set enforcement to "None".
|
|
284
|
-
if (attributeValueLowercase.includes('none')) {
|
|
285
|
-
enforcement = 'None'
|
|
286
|
-
}
|
|
287
279
|
|
|
288
|
-
//
|
|
289
|
-
// "
|
|
290
|
-
|
|
291
|
-
|
|
280
|
+
// 1. If cookie-av's attribute-value is a case-insensitive match for
|
|
281
|
+
// "None", append an attribute to the cookie-attribute-list with an
|
|
282
|
+
// attribute-name of "SameSite" and an attribute-value of "None".
|
|
283
|
+
if (attributeValueLowercase === 'none') {
|
|
284
|
+
cookieAttributeList.sameSite = 'None'
|
|
285
|
+
} else if (attributeValueLowercase === 'strict') {
|
|
286
|
+
// 2. If cookie-av's attribute-value is a case-insensitive match for
|
|
287
|
+
// "Strict", append an attribute to the cookie-attribute-list with
|
|
288
|
+
// an attribute-name of "SameSite" and an attribute-value of
|
|
289
|
+
// "Strict".
|
|
290
|
+
cookieAttributeList.sameSite = 'Strict'
|
|
291
|
+
} else if (attributeValueLowercase === 'lax') {
|
|
292
|
+
// 3. If cookie-av's attribute-value is a case-insensitive match for
|
|
293
|
+
// "Lax", append an attribute to the cookie-attribute-list with an
|
|
294
|
+
// attribute-name of "SameSite" and an attribute-value of "Lax".
|
|
295
|
+
cookieAttributeList.sameSite = 'Lax'
|
|
292
296
|
}
|
|
293
|
-
|
|
294
|
-
// 4. If cookie-av's attribute-value is a case-insensitive match for
|
|
295
|
-
// "Lax", set enforcement to "Lax".
|
|
296
|
-
if (attributeValueLowercase.includes('lax')) {
|
|
297
|
-
enforcement = 'Lax'
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// 5. Append an attribute to the cookie-attribute-list with an
|
|
301
|
-
// attribute-name of "SameSite" and an attribute-value of
|
|
302
|
-
// enforcement.
|
|
303
|
-
cookieAttributeList.sameSite = enforcement
|
|
304
297
|
} else {
|
|
305
298
|
cookieAttributeList.unparsed ??= []
|
|
306
299
|
|
|
@@ -20,6 +20,11 @@ const { closeWebSocketConnection } = require('./connection')
|
|
|
20
20
|
const { PerMessageDeflate } = require('./permessage-deflate')
|
|
21
21
|
const { MessageSizeExceededError } = require('../../core/errors')
|
|
22
22
|
|
|
23
|
+
function failWebsocketConnectionWithCode (ws, code, reason) {
|
|
24
|
+
closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason))
|
|
25
|
+
failWebsocketConnection(ws, reason)
|
|
26
|
+
}
|
|
27
|
+
|
|
23
28
|
// This code was influenced by ws released under the MIT license.
|
|
24
29
|
// Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
|
25
30
|
// Copyright (c) 2013 Arnout Kazemier and contributors
|
|
@@ -39,19 +44,23 @@ class ByteParser extends Writable {
|
|
|
39
44
|
/** @type {Map<string, PerMessageDeflate>} */
|
|
40
45
|
#extensions
|
|
41
46
|
|
|
47
|
+
/** @type {number} */
|
|
48
|
+
#maxFragments
|
|
49
|
+
|
|
42
50
|
/** @type {number} */
|
|
43
51
|
#maxPayloadSize
|
|
44
52
|
|
|
45
53
|
/**
|
|
46
54
|
* @param {import('./websocket').WebSocket} ws
|
|
47
55
|
* @param {Map<string, string>|null} extensions
|
|
48
|
-
* @param {{ maxPayloadSize?: number }} [options]
|
|
56
|
+
* @param {{ maxFragments?: number, maxPayloadSize?: number }} [options]
|
|
49
57
|
*/
|
|
50
58
|
constructor (ws, extensions, options = {}) {
|
|
51
59
|
super()
|
|
52
60
|
|
|
53
61
|
this.ws = ws
|
|
54
62
|
this.#extensions = extensions == null ? new Map() : extensions
|
|
63
|
+
this.#maxFragments = options.maxFragments ?? 0
|
|
55
64
|
this.#maxPayloadSize = options.maxPayloadSize ?? 0
|
|
56
65
|
|
|
57
66
|
if (this.#extensions.has('permessage-deflate')) {
|
|
@@ -75,9 +84,9 @@ class ByteParser extends Writable {
|
|
|
75
84
|
if (
|
|
76
85
|
this.#maxPayloadSize > 0 &&
|
|
77
86
|
!isControlFrame(this.#info.opcode) &&
|
|
78
|
-
this.#info.payloadLength > this.#maxPayloadSize
|
|
87
|
+
this.#info.payloadLength + this.#fragmentsBytes > this.#maxPayloadSize
|
|
79
88
|
) {
|
|
80
|
-
|
|
89
|
+
failWebsocketConnectionWithCode(this.ws, 1009, 'Payload size exceeds maximum allowed size')
|
|
81
90
|
return false
|
|
82
91
|
}
|
|
83
92
|
|
|
@@ -242,10 +251,12 @@ class ByteParser extends Writable {
|
|
|
242
251
|
this.#state = parserStates.INFO
|
|
243
252
|
} else {
|
|
244
253
|
if (!this.#info.compressed) {
|
|
245
|
-
this.writeFragments(body)
|
|
254
|
+
if (!this.writeFragments(body)) {
|
|
255
|
+
return
|
|
256
|
+
}
|
|
246
257
|
|
|
247
258
|
if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) {
|
|
248
|
-
|
|
259
|
+
failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message)
|
|
249
260
|
return
|
|
250
261
|
}
|
|
251
262
|
|
|
@@ -264,14 +275,17 @@ class ByteParser extends Writable {
|
|
|
264
275
|
this.#info.fin,
|
|
265
276
|
(error, data) => {
|
|
266
277
|
if (error) {
|
|
267
|
-
|
|
278
|
+
const code = error instanceof MessageSizeExceededError ? 1009 : 1007
|
|
279
|
+
failWebsocketConnectionWithCode(this.ws, code, error.message)
|
|
268
280
|
return
|
|
269
281
|
}
|
|
270
282
|
|
|
271
|
-
this.writeFragments(data)
|
|
283
|
+
if (!this.writeFragments(data)) {
|
|
284
|
+
return
|
|
285
|
+
}
|
|
272
286
|
|
|
273
287
|
if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) {
|
|
274
|
-
|
|
288
|
+
failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message)
|
|
275
289
|
return
|
|
276
290
|
}
|
|
277
291
|
|
|
@@ -341,8 +355,17 @@ class ByteParser extends Writable {
|
|
|
341
355
|
}
|
|
342
356
|
|
|
343
357
|
writeFragments (fragment) {
|
|
358
|
+
if (
|
|
359
|
+
this.#maxFragments > 0 &&
|
|
360
|
+
this.#fragments.length === this.#maxFragments
|
|
361
|
+
) {
|
|
362
|
+
failWebsocketConnectionWithCode(this.ws, 1008, 'Too many message fragments')
|
|
363
|
+
return false
|
|
364
|
+
}
|
|
365
|
+
|
|
344
366
|
this.#fragmentsBytes += fragment.length
|
|
345
367
|
this.#fragments.push(fragment)
|
|
368
|
+
return true
|
|
346
369
|
}
|
|
347
370
|
|
|
348
371
|
consumeFragments () {
|
|
@@ -435,9 +435,12 @@ class WebSocket extends EventTarget {
|
|
|
435
435
|
// once this happens, the connection is open
|
|
436
436
|
this[kResponse] = response
|
|
437
437
|
|
|
438
|
-
const
|
|
438
|
+
const webSocketOptions = this[kController]?.dispatcher?.webSocketOptions
|
|
439
|
+
const maxFragments = webSocketOptions?.maxFragments
|
|
440
|
+
const maxPayloadSize = webSocketOptions?.maxPayloadSize
|
|
439
441
|
|
|
440
442
|
const parser = new ByteParser(this, parsedExtensions, {
|
|
443
|
+
maxFragments,
|
|
441
444
|
maxPayloadSize
|
|
442
445
|
})
|
|
443
446
|
parser.on('drain', onParserDrain)
|
package/package.json
CHANGED
package/types/client.d.ts
CHANGED
|
@@ -106,6 +106,12 @@ export declare namespace Client {
|
|
|
106
106
|
bytesRead?: number
|
|
107
107
|
}
|
|
108
108
|
export interface WebSocketOptions {
|
|
109
|
+
/**
|
|
110
|
+
* Maximum number of fragments in a message.
|
|
111
|
+
* Set to 0 to disable the limit.
|
|
112
|
+
* @default 131072
|
|
113
|
+
*/
|
|
114
|
+
maxFragments?: number;
|
|
109
115
|
/**
|
|
110
116
|
* Maximum allowed payload size in bytes for WebSocket messages.
|
|
111
117
|
* Applied to uncompressed messages, compressed frame payloads, and decompressed (permessage-deflate) messages.
|