Skip to content

Commit 8422a78

Browse files
committed
Implement prototype for maxDatagramSize
1 parent 48e39e9 commit 8422a78

10 files changed

Lines changed: 154 additions & 53 deletions

File tree

main/lib/http2/browser/browser.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ export class Http2WebTransportBrowser {
3232
args.sessionShouldAutoTuneReceiveWindow || true
3333
this.sessionFlowControlWindowSizeLimit =
3434
args?.sessionFlowControlWindowSizeLimit || 15 * 1024 * 1024
35+
36+
this.initialDatagramSize =
37+
args.initialDatagramSize || this.streamFlowControlWindowSizeLimit - 128
3538
/** @type {import('../../session.js').HttpClient} */
3639
// @ts-ignore
3740
this.jsobj = undefined // the transport will set this
@@ -148,7 +151,9 @@ export class Http2WebTransportBrowser {
148151
this.initialStreamFlowControlWindow,
149152
streamShouldAutoTuneReceiveWindow:
150153
this.streamShouldAutoTuneReceiveWindow,
151-
streamReceiveWindowSizeLimit: this.streamFlowControlWindowSizeLimit
154+
streamReceiveWindowSizeLimit: this.streamFlowControlWindowSizeLimit,
155+
maxDatagramSize: this.initialDatagramSize,
156+
remoteMaxDatagramSize: 2 ** 62 - 1
152157
})
153158
if (this.clientInt)
154159
this.clientInt.addEventListener('close', (event) => {

main/lib/http2/browser/browserparser.js

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@ export class BrowserParser extends ParserBase {
8686
initialStreamSendWindowOffsetBidi,
8787
initialStreamReceiveWindowOffset,
8888
streamShouldAutoTuneReceiveWindow,
89-
streamReceiveWindowSizeLimit
89+
streamReceiveWindowSizeLimit,
90+
maxDatagramSize,
91+
remoteMaxDatagramSize
9092
}) {
9193
super({
9294
nativesession,
@@ -95,7 +97,9 @@ export class BrowserParser extends ParserBase {
9597
initialStreamSendWindowOffsetBidi,
9698
initialStreamReceiveWindowOffset,
9799
streamShouldAutoTuneReceiveWindow,
98-
streamReceiveWindowSizeLimit
100+
streamReceiveWindowSizeLimit,
101+
maxDatagramSize,
102+
remoteMaxDatagramSize
99103
})
100104
this.ws = ws
101105
/** @type {Buffer|undefined} */
@@ -218,6 +222,9 @@ export class BrowserParser extends ParserBase {
218222
case ParserBase.WT_STREAMS_BLOCKED_BIDI:
219223
this.onStreamsBlockedBidi(readVarInt(bufferstate))
220224
break
225+
case ParserBase.WT_MAX_DATAGRAM_SIZE:
226+
this.onMaxDatagramSize(readVarInt(bufferstate))
227+
break
221228
case ParserBase.CLOSE_WEBTRANSPORT_SESSION:
222229
{
223230
const code = readUint32(bufferstate) || 0
@@ -236,13 +243,18 @@ export class BrowserParser extends ParserBase {
236243
this.onDrain()
237244
break
238245
case ParserBase.DATAGRAM:
239-
this.session.jsobj.onDatagramReceived({
240-
datagram: new Uint8Array(
241-
bufferstate.buffer.buffer,
242-
bufferstate.buffer.byteOffset + bufferstate.offset,
243-
offsetend - bufferstate.offset
244-
)
245-
})
246+
if (offsetend - bufferstate.offset <= this.maxDatagramSize) {
247+
// actually for the browser it is already too late
248+
// but to give developers a consitent behaviour, we drop it here as well
249+
// drop too large datagrams
250+
this.session.jsobj.onDatagramReceived({
251+
datagram: new Uint8Array(
252+
bufferstate.buffer.buffer,
253+
bufferstate.buffer.byteOffset + bufferstate.offset,
254+
offsetend - bufferstate.offset
255+
)
256+
})
257+
}
246258

247259
break
248260
default:

main/lib/http2/node/capsuleparser.js

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
1818
initialStreamSendWindowOffsetUnidi,
1919
initialStreamReceiveWindowOffset,
2020
streamShouldAutoTuneReceiveWindow,
21-
streamReceiveWindowSizeLimit
21+
streamReceiveWindowSizeLimit,
22+
maxDatagramSize,
23+
remoteMaxDatagramSize
2224
}) {
2325
super({
2426
stream,
@@ -28,7 +30,9 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
2830
initialStreamSendWindowOffsetUnidi,
2931
initialStreamReceiveWindowOffset,
3032
streamShouldAutoTuneReceiveWindow,
31-
streamReceiveWindowSizeLimit
33+
streamReceiveWindowSizeLimit,
34+
maxDatagramSize,
35+
remoteMaxDatagramSize
3236
})
3337
this.mode = 's' // capsule start
3438
/** @type {Buffer|undefined} */
@@ -94,8 +98,9 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
9498
if (
9599
type === Http2CapsuleParser.PADDING ||
96100
type === Http2CapsuleParser.WT_STREAM_WOFIN ||
97-
type ===
98-
Http2CapsuleParser.WT_STREAM_WFIN /* || type === Http2CapsuleParser.DATAGRAM */
101+
type === Http2CapsuleParser.WT_STREAM_WFIN ||
102+
(type === Http2CapsuleParser.DATAGRAM &&
103+
length > this.maxDatagramSize) // if we exceed maximum size of datagram we drop
99104
) {
100105
checklength = Math.min(length, 64) // stream id + some Data
101106
}
@@ -107,7 +112,7 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
107112
// too long abort, could be an attack vector
108113
this.session.closeConnection({
109114
code: 63, // QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA, // probably the right one...
110-
reason: 'Frame length too big :' + length
115+
reason: 'Frame length too big : ' + length
111116
})
112117
return
113118
}
@@ -221,6 +226,9 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
221226
case Http2CapsuleParser.WT_STREAMS_BLOCKED_BIDI:
222227
this.onStreamsBlockedBidi(readVarInt(bufferstate))
223228
break
229+
case Http2CapsuleParser.WT_MAX_DATAGRAM_SIZE:
230+
this.onMaxDatagramSize(readVarInt(bufferstate))
231+
break
224232
case Http2CapsuleParser.CLOSE_WEBTRANSPORT_SESSION:
225233
{
226234
const code = readUint32(bufferstate) || 0
@@ -239,13 +247,16 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
239247
this.onDrain()
240248
break
241249
case Http2CapsuleParser.DATAGRAM:
242-
this.session.jsobj.onDatagramReceived({
243-
datagram: new Uint8Array(
244-
bufferstate.buffer.buffer,
245-
bufferstate.buffer.byteOffset + bufferstate.offset,
246-
offsetend - bufferstate.offset
247-
)
248-
})
250+
if (length <= this.maxDatagramSize) {
251+
// drop too large datagrams
252+
this.session.jsobj.onDatagramReceived({
253+
datagram: new Uint8Array(
254+
bufferstate.buffer.buffer,
255+
bufferstate.buffer.byteOffset + bufferstate.offset,
256+
offsetend - bufferstate.offset
257+
)
258+
})
259+
}
249260
break
250261
default:
251262
// do nothing

main/lib/http2/node/client.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ export class Http2WebTransportClient {
3838
args.sessionShouldAutoTuneReceiveWindow || true
3939
this.sessionFlowControlWindowSizeLimit =
4040
args?.sessionFlowControlWindowSizeLimit || 15 * 1024 * 1024
41+
42+
this.initialDatagramSize =
43+
args.initialDatagramSize || this.streamFlowControlWindowSizeLimit - 128
4144
/** @type {import('../../session.js').HttpClient} */
4245
// @ts-ignore
4346
this.jsobj = undefined // the transport will set this
@@ -92,10 +95,13 @@ export class Http2WebTransportClient {
9295
0x2b62: this.initialStreamFlowControlWindow, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAM_DATA_UNI
9396
0x2b63: this.initialStreamFlowControlWindow, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAM_DATA_BIDI
9497
0x2b64: this.initialUnidirectionalStreams, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_UNI
95-
0x2b65: this.initialBidirectionalStreams // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_BIDI
98+
0x2b65: this.initialBidirectionalStreams, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_BIDI
99+
0x2b66: this.initialDatagramSize // SETTINGS_MAX_DATAGRAM_SIZE
96100
}
97101
},
98-
remoteCustomSettings: [0x2b60, 0x2b61, 0x2b62, 0x2b63, 0x2b64, 0x2b65],
102+
remoteCustomSettings: [
103+
0x2b60, 0x2b61, 0x2b62, 0x2b63, 0x2b64, 0x2b65, 0x2b66
104+
],
99105
localPort: this.localPort,
100106
// TODO: REMOVE BEFORE RELEASE; UNSAFE SETTING
101107
rejectUnauthorized: !this.serverCertificateHashes
@@ -231,7 +237,8 @@ export class Http2WebTransportClient {
231237
0x2b64: remoteUnidirectionalStreams = undefined,
232238
0x2b63: remoteBidirectionalStreamFlowControlWindow = undefined,
233239
0x2b62: remoteUnidirectionalStreamFlowControlWindow = undefined,
234-
0x2b61: remoteSessionFlowControlWindow = undefined
240+
0x2b61: remoteSessionFlowControlWindow = undefined,
241+
0x2b66: remoteMaxDatagramSize = 2 ** 62 - 1 // note this exceeds safe integer
235242
// @ts-ignore
236243
} = this.clientInt.remoteSettings?.customSettings || {}
237244

@@ -255,7 +262,9 @@ export class Http2WebTransportClient {
255262
this.initialStreamFlowControlWindow,
256263
streamShouldAutoTuneReceiveWindow:
257264
this.streamShouldAutoTuneReceiveWindow,
258-
streamReceiveWindowSizeLimit: this.streamFlowControlWindowSizeLimit
265+
streamReceiveWindowSizeLimit: this.streamFlowControlWindowSizeLimit,
266+
maxDatagramSize: this.initialDatagramSize,
267+
remoteMaxDatagramSize
259268
}),
260269
initialBidirectionalSendStreams:
261270
remoteBidirectionalStreams || this.initialBidirectionalStreams,

main/lib/http2/node/server.js

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ export class Http2WebTransportServer {
4242
this.sessionFlowControlWindowSizeLimit =
4343
args?.sessionFlowControlWindowSizeLimit || 15 * 1024 * 1024
4444

45+
this.initialDatagramSize =
46+
args.initialDatagramSize || this.streamFlowControlWindowSizeLimit - 128
47+
4548
/** @type {Record<string, boolean>} */
4649
this.paths = {}
4750
this.hasrequesthandler = false
@@ -64,10 +67,13 @@ export class Http2WebTransportServer {
6467
0x2b62: this.initialStreamFlowControlWindow, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAM_DATA_UNI
6568
0x2b63: this.initialStreamFlowControlWindow, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAM_DATA_BIDI
6669
0x2b64: this.initialUnidirectionalStreams, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_UNI
67-
0x2b65: this.initialBidirectionalStreams // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_BIDI
70+
0x2b65: this.initialBidirectionalStreams, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_BIDI
71+
0x2b66: this.initialDatagramSize // SETTINGS_MAX_DATAGRAM_SIZE
6872
}
6973
},
70-
remoteCustomSettings: [0x2b60, 0x2b61, 0x2b62, 0x2b63, 0x2b64, 0x2b65]
74+
remoteCustomSettings: [
75+
0x2b60, 0x2b61, 0x2b62, 0x2b63, 0x2b64, 0x2b65, 0x2b66
76+
]
7177
})
7278

7379
this.serverInt.on('listening', () => {
@@ -179,7 +185,9 @@ export class Http2WebTransportServer {
179185
streamShouldAutoTuneReceiveWindow:
180186
this.streamShouldAutoTuneReceiveWindow,
181187
streamReceiveWindowSizeLimit:
182-
this.streamFlowControlWindowSizeLimit
188+
this.streamFlowControlWindowSizeLimit,
189+
maxDatagramSize: this.initialDatagramSize,
190+
remoteMaxDatagramSize: 2 ** 62 - 1 // we wait for the settings frame to be received
183191
}))
184192
if (head.byteLength > 0) parse.parseData(head)
185193
return parse
@@ -272,7 +280,8 @@ export class Http2WebTransportServer {
272280
0x2b64: remoteUnidirectionalStreams = undefined,
273281
0x2b63: remoteBidirectionalStreamFlowControlWindow = undefined,
274282
0x2b62: remoteUnidirectionalStreamFlowControlWindow = undefined,
275-
0x2b61: remoteSessionFlowControlWindow = undefined
283+
0x2b61: remoteSessionFlowControlWindow = undefined,
284+
0x2b66: remoteMaxDatagramSize = 2 ** 62 - 1 // note this exceeds safe integer
276285
// @ts-ignore
277286
} = stream?.session?.remoteSettings?.customSettings || {}
278287
const retObj = {
@@ -298,7 +307,9 @@ export class Http2WebTransportServer {
298307
streamShouldAutoTuneReceiveWindow:
299308
this.streamShouldAutoTuneReceiveWindow,
300309
streamReceiveWindowSizeLimit:
301-
this.streamFlowControlWindowSizeLimit
310+
this.streamFlowControlWindowSizeLimit,
311+
maxDatagramSize: this.initialDatagramSize,
312+
remoteMaxDatagramSize
302313
})
303314
} else {
304315
return (this.capsParser = new WebSocketParser({
@@ -312,7 +323,9 @@ export class Http2WebTransportServer {
312323
streamShouldAutoTuneReceiveWindow:
313324
this.streamShouldAutoTuneReceiveWindow,
314325
streamReceiveWindowSizeLimit:
315-
this.streamFlowControlWindowSizeLimit
326+
this.streamFlowControlWindowSizeLimit,
327+
maxDatagramSize: this.initialDatagramSize,
328+
remoteMaxDatagramSize
316329
}))
317330
}
318331
},
@@ -515,7 +528,9 @@ export class Http2WebTransportServer {
515528
streamShouldAutoTuneReceiveWindow:
516529
this.streamShouldAutoTuneReceiveWindow,
517530
streamReceiveWindowSizeLimit:
518-
this.streamFlowControlWindowSizeLimit
531+
this.streamFlowControlWindowSizeLimit,
532+
maxDatagramSize: this.initialDatagramSize,
533+
remoteMaxDatagramSize: 2 ** 62 - 1 // we wait for the frame
519534
}))
520535
if (head && head.byteLength > 0) parse.parseData(head)
521536
return parse
@@ -562,7 +577,8 @@ export class Http2WebTransportServer {
562577
0x2b64: remoteUnidirectionalStreams = undefined,
563578
0x2b63: remoteBidirectionalStreamFlowControlWindow = undefined,
564579
0x2b62: remoteUnidirectionalStreamFlowControlWindow = undefined,
565-
0x2b61: remoteSessionFlowControlWindow = undefined
580+
0x2b61: remoteSessionFlowControlWindow = undefined,
581+
0x2b66: remoteMaxDatagramSize = 2 ** 62 - 1 // note this exceeds safe integer
566582
// @ts-ignore
567583
} = stream?.session?.remoteSettings?.customSettings || {}
568584
const retObj = {
@@ -588,7 +604,9 @@ export class Http2WebTransportServer {
588604
streamShouldAutoTuneReceiveWindow:
589605
this.streamShouldAutoTuneReceiveWindow,
590606
streamReceiveWindowSizeLimit:
591-
this.streamFlowControlWindowSizeLimit
607+
this.streamFlowControlWindowSizeLimit,
608+
maxDatagramSize: this.initialDatagramSize,
609+
remoteMaxDatagramSize
592610
})
593611
} else {
594612
return (this.capsParser = new WebSocketParser({
@@ -602,7 +620,9 @@ export class Http2WebTransportServer {
602620
streamShouldAutoTuneReceiveWindow:
603621
this.streamShouldAutoTuneReceiveWindow,
604622
streamReceiveWindowSizeLimit:
605-
this.streamFlowControlWindowSizeLimit
623+
this.streamFlowControlWindowSizeLimit,
624+
maxDatagramSize: this.initialDatagramSize,
625+
remoteMaxDatagramSize
606626
}))
607627
}
608628
},

main/lib/http2/node/websocketparser.js

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,9 @@ export class WebSocketParser extends ParserBaseHttp2 {
183183
initialStreamSendWindowOffsetBidi,
184184
initialStreamReceiveWindowOffset,
185185
streamShouldAutoTuneReceiveWindow,
186-
streamReceiveWindowSizeLimit
186+
streamReceiveWindowSizeLimit,
187+
maxDatagramSize,
188+
remoteMaxDatagramSize
187189
}) {
188190
super({
189191
stream,
@@ -193,7 +195,9 @@ export class WebSocketParser extends ParserBaseHttp2 {
193195
initialStreamSendWindowOffsetBidi,
194196
initialStreamReceiveWindowOffset,
195197
streamShouldAutoTuneReceiveWindow,
196-
streamReceiveWindowSizeLimit
198+
streamReceiveWindowSizeLimit,
199+
maxDatagramSize,
200+
remoteMaxDatagramSize
197201
})
198202
this.mode = 's' // frame start
199203
/** @type {Buffer|undefined} */
@@ -433,8 +437,8 @@ export class WebSocketParser extends ParserBaseHttp2 {
433437
if (
434438
type === ParserBase.PADDING ||
435439
type === ParserBase.WT_STREAM_WOFIN ||
436-
type ===
437-
ParserBase.WT_STREAM_WFIN /* || type === ParserBase.DATAGRAM */
440+
type === ParserBase.WT_STREAM_WFIN ||
441+
(type === ParserBase.DATAGRAM && length > this.maxDatagramSize) // if we exceed maximum size of datagram we drop
438442
) {
439443
checklength = Math.min(length, 64) // stream id + some Data
440444
}
@@ -608,6 +612,9 @@ export class WebSocketParser extends ParserBaseHttp2 {
608612
case ParserBase.WT_STREAMS_BLOCKED_BIDI:
609613
this.onStreamsBlockedBidi(readVarInt(bufferstate))
610614
break
615+
case ParserBase.WT_MAX_DATAGRAM_SIZE:
616+
this.onMaxDatagramSize(readVarInt(bufferstate))
617+
break
611618
case ParserBase.CLOSE_WEBTRANSPORT_SESSION:
612619
{
613620
const code = readUint32(bufferstate) || 0
@@ -626,14 +633,17 @@ export class WebSocketParser extends ParserBaseHttp2 {
626633
this.onDrain()
627634
break
628635
case ParserBase.DATAGRAM:
629-
if (wbufferstate) {
630-
this.session.jsobj.onDatagramReceived({
631-
datagram: new Uint8Array(
632-
wbufferstate.buffer.buffer,
633-
wbufferstate.buffer.byteOffset + wbufferstate.offset,
634-
offsetend - wbufferstate.offset
635-
)
636-
})
636+
if (length <= this.maxDatagramSize) {
637+
// drop too large datagrams
638+
if (wbufferstate) {
639+
this.session.jsobj.onDatagramReceived({
640+
datagram: new Uint8Array(
641+
wbufferstate.buffer.buffer,
642+
wbufferstate.buffer.byteOffset + wbufferstate.offset,
643+
offsetend - wbufferstate.offset
644+
)
645+
})
646+
}
637647
}
638648
break
639649
default:

0 commit comments

Comments
 (0)