Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion main/lib/http2/browser/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ export class Http2WebTransportBrowser {
args.sessionShouldAutoTuneReceiveWindow || true
this.sessionFlowControlWindowSizeLimit =
args?.sessionFlowControlWindowSizeLimit || 15 * 1024 * 1024

this.initialDatagramSize =
args.initialDatagramSize || this.initialSessionFlowControlWindow - 128
/** @type {import('../../session.js').HttpClient} */
// @ts-ignore
this.jsobj = undefined // the transport will set this
Expand Down Expand Up @@ -148,7 +151,9 @@ export class Http2WebTransportBrowser {
this.initialStreamFlowControlWindow,
streamShouldAutoTuneReceiveWindow:
this.streamShouldAutoTuneReceiveWindow,
streamReceiveWindowSizeLimit: this.streamFlowControlWindowSizeLimit
streamReceiveWindowSizeLimit: this.streamFlowControlWindowSizeLimit,
maxDatagramSize: this.initialDatagramSize,
remoteMaxDatagramSize: 2 ** 62 - 1
})
if (this.clientInt)
this.clientInt.addEventListener('close', (event) => {
Expand Down
30 changes: 21 additions & 9 deletions main/lib/http2/browser/browserparser.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ export class BrowserParser extends ParserBase {
initialStreamSendWindowOffsetBidi,
initialStreamReceiveWindowOffset,
streamShouldAutoTuneReceiveWindow,
streamReceiveWindowSizeLimit
streamReceiveWindowSizeLimit,
maxDatagramSize,
remoteMaxDatagramSize
}) {
super({
nativesession,
Expand All @@ -95,7 +97,9 @@ export class BrowserParser extends ParserBase {
initialStreamSendWindowOffsetBidi,
initialStreamReceiveWindowOffset,
streamShouldAutoTuneReceiveWindow,
streamReceiveWindowSizeLimit
streamReceiveWindowSizeLimit,
maxDatagramSize,
remoteMaxDatagramSize
})
this.ws = ws
/** @type {Buffer|undefined} */
Expand Down Expand Up @@ -220,6 +224,9 @@ export class BrowserParser extends ParserBase {
case ParserBase.WT_STREAMS_BLOCKED_BIDI:
this.onStreamsBlockedBidi(readVarInt(bufferstate))
break
case ParserBase.WT_MAX_DATAGRAM_SIZE:
this.onMaxDatagramSize(readVarInt(bufferstate))
break
case ParserBase.CLOSE_WEBTRANSPORT_SESSION:
{
const code = readUint32(bufferstate) || 0
Expand All @@ -238,13 +245,18 @@ export class BrowserParser extends ParserBase {
this.onDrain()
break
case ParserBase.DATAGRAM:
this.session.jsobj.onDatagramReceived({
datagram: new Uint8Array(
bufferstate.buffer.buffer,
bufferstate.buffer.byteOffset + bufferstate.offset,
offsetend - bufferstate.offset
)
})
if (offsetend - bufferstate.offset <= this.maxDatagramSize) {
// actually for the browser it is already too late
// but to give developers a consistent behaviour, we drop it here as well
// drop too large datagrams
this.session.jsobj.onDatagramReceived({
datagram: new Uint8Array(
bufferstate.buffer.buffer,
bufferstate.buffer.byteOffset + bufferstate.offset,
offsetend - bufferstate.offset
)
})
}

break
default:
Expand Down
37 changes: 24 additions & 13 deletions main/lib/http2/node/capsuleparser.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
initialStreamSendWindowOffsetUnidi,
initialStreamReceiveWindowOffset,
streamShouldAutoTuneReceiveWindow,
streamReceiveWindowSizeLimit
streamReceiveWindowSizeLimit,
maxDatagramSize,
remoteMaxDatagramSize
}) {
super({
stream,
Expand All @@ -28,7 +30,9 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
initialStreamSendWindowOffsetUnidi,
initialStreamReceiveWindowOffset,
streamShouldAutoTuneReceiveWindow,
streamReceiveWindowSizeLimit
streamReceiveWindowSizeLimit,
maxDatagramSize,
remoteMaxDatagramSize
})
this.mode = 's' // capsule start
/** @type {Buffer|undefined} */
Expand Down Expand Up @@ -96,8 +100,9 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
if (
type === Http2CapsuleParser.PADDING ||
type === Http2CapsuleParser.WT_STREAM_WOFIN ||
type ===
Http2CapsuleParser.WT_STREAM_WFIN /* || type === Http2CapsuleParser.DATAGRAM */
type === Http2CapsuleParser.WT_STREAM_WFIN ||
(type === Http2CapsuleParser.DATAGRAM &&
length > this.maxDatagramSize) // if we exceed maximum size of datagram we drop
) {
checklength = Math.min(length, 64) // stream id + some Data
}
Expand All @@ -109,7 +114,7 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
// too long abort, could be an attack vector
this.session.closeConnection({
code: 63, // QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA, // probably the right one...
reason: 'Frame length too big :' + length
reason: 'Frame length too big : ' + length
})
return
}
Expand Down Expand Up @@ -223,6 +228,9 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
case Http2CapsuleParser.WT_STREAMS_BLOCKED_BIDI:
this.onStreamsBlockedBidi(readVarInt(bufferstate))
break
case Http2CapsuleParser.WT_MAX_DATAGRAM_SIZE:
this.onMaxDatagramSize(readVarInt(bufferstate))
break
case Http2CapsuleParser.CLOSE_WEBTRANSPORT_SESSION:
{
const code = readUint32(bufferstate) || 0
Expand All @@ -241,13 +249,16 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
this.onDrain()
break
case Http2CapsuleParser.DATAGRAM:
this.session.jsobj.onDatagramReceived({
datagram: new Uint8Array(
bufferstate.buffer.buffer,
bufferstate.buffer.byteOffset + bufferstate.offset,
offsetend - bufferstate.offset
)
})
if (length <= this.maxDatagramSize) {
// drop too large datagrams
this.session.jsobj.onDatagramReceived({
datagram: new Uint8Array(
bufferstate.buffer.buffer,
bufferstate.buffer.byteOffset + bufferstate.offset,
offsetend - bufferstate.offset
)
})
}
break
default:
// do nothing
Expand Down Expand Up @@ -317,7 +328,7 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
writeVarInt(bufferstate, type)
writeVarInt(bufferstate, length)
for (const ind in headerVints) writeVarInt(bufferstate, headerVints[ind])
if (!this.stream) return
if (!this.stream) return true
// note it might be illegal to split the write
if (!end) {
let blocked = !this.stream.write(cdata)
Expand Down
17 changes: 13 additions & 4 deletions main/lib/http2/node/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ export class Http2WebTransportClient {
args.sessionShouldAutoTuneReceiveWindow || true
this.sessionFlowControlWindowSizeLimit =
args?.sessionFlowControlWindowSizeLimit || 15 * 1024 * 1024

this.initialDatagramSize =
args.initialDatagramSize || this.initialSessionFlowControlWindow - 128
/** @type {import('../../session.js').HttpClient} */
// @ts-ignore
this.jsobj = undefined // the transport will set this
Expand Down Expand Up @@ -92,10 +95,13 @@ export class Http2WebTransportClient {
0x2b62: this.initialStreamFlowControlWindow, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAM_DATA_UNI
0x2b63: this.initialStreamFlowControlWindow, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAM_DATA_BIDI
0x2b64: this.initialUnidirectionalStreams, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_UNI
0x2b65: this.initialBidirectionalStreams // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_BIDI
0x2b65: this.initialBidirectionalStreams, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_BIDI
0x2b66: this.initialDatagramSize // SETTINGS_MAX_DATAGRAM_SIZE
}
},
remoteCustomSettings: [0x2b60, 0x2b61, 0x2b62, 0x2b63, 0x2b64, 0x2b65],
remoteCustomSettings: [
0x2b60, 0x2b61, 0x2b62, 0x2b63, 0x2b64, 0x2b65, 0x2b66
],
localPort: this.localPort,
// TODO: REMOVE BEFORE RELEASE; UNSAFE SETTING
rejectUnauthorized: !this.serverCertificateHashes
Expand Down Expand Up @@ -231,7 +237,8 @@ export class Http2WebTransportClient {
0x2b64: remoteUnidirectionalStreams = undefined,
0x2b63: remoteBidirectionalStreamFlowControlWindow = undefined,
0x2b62: remoteUnidirectionalStreamFlowControlWindow = undefined,
0x2b61: remoteSessionFlowControlWindow = undefined
0x2b61: remoteSessionFlowControlWindow = undefined,
0x2b66: remoteMaxDatagramSize = 2 ** 62 - 1 // note this exceeds safe integer
// @ts-ignore
} = this.clientInt.remoteSettings?.customSettings || {}

Expand All @@ -255,7 +262,9 @@ export class Http2WebTransportClient {
this.initialStreamFlowControlWindow,
streamShouldAutoTuneReceiveWindow:
this.streamShouldAutoTuneReceiveWindow,
streamReceiveWindowSizeLimit: this.streamFlowControlWindowSizeLimit
streamReceiveWindowSizeLimit: this.streamFlowControlWindowSizeLimit,
maxDatagramSize: this.initialDatagramSize,
remoteMaxDatagramSize
}),
initialBidirectionalSendStreams:
remoteBidirectionalStreams || this.initialBidirectionalStreams,
Expand Down
40 changes: 30 additions & 10 deletions main/lib/http2/node/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ export class Http2WebTransportServer {
this.sessionFlowControlWindowSizeLimit =
args?.sessionFlowControlWindowSizeLimit || 15 * 1024 * 1024

this.initialDatagramSize =
args.initialDatagramSize || this.initialSessionFlowControlWindow - 128

/** @type {Record<string, boolean>} */
this.paths = {}
this.hasrequesthandler = false
Expand All @@ -64,10 +67,13 @@ export class Http2WebTransportServer {
0x2b62: this.initialStreamFlowControlWindow, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAM_DATA_UNI
0x2b63: this.initialStreamFlowControlWindow, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAM_DATA_BIDI
0x2b64: this.initialUnidirectionalStreams, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_UNI
0x2b65: this.initialBidirectionalStreams // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_BIDI
0x2b65: this.initialBidirectionalStreams, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_BIDI
0x2b66: this.initialDatagramSize // SETTINGS_MAX_DATAGRAM_SIZE
}
},
remoteCustomSettings: [0x2b60, 0x2b61, 0x2b62, 0x2b63, 0x2b64, 0x2b65]
remoteCustomSettings: [
0x2b60, 0x2b61, 0x2b62, 0x2b63, 0x2b64, 0x2b65, 0x2b66
]
})

this.serverInt.on('listening', () => {
Expand Down Expand Up @@ -180,7 +186,9 @@ export class Http2WebTransportServer {
streamShouldAutoTuneReceiveWindow:
this.streamShouldAutoTuneReceiveWindow,
streamReceiveWindowSizeLimit:
this.streamFlowControlWindowSizeLimit
this.streamFlowControlWindowSizeLimit,
maxDatagramSize: this.initialDatagramSize,
remoteMaxDatagramSize: 2 ** 62 - 1 // we wait for the settings frame to be received
}))
if (head.byteLength > 0) parse.parseData(head)
return parse
Expand Down Expand Up @@ -278,7 +286,8 @@ export class Http2WebTransportServer {
0x2b64: remoteUnidirectionalStreams = undefined,
0x2b63: remoteBidirectionalStreamFlowControlWindow = undefined,
0x2b62: remoteUnidirectionalStreamFlowControlWindow = undefined,
0x2b61: remoteSessionFlowControlWindow = undefined
0x2b61: remoteSessionFlowControlWindow = undefined,
0x2b66: remoteMaxDatagramSize = 2 ** 62 - 1 // note this exceeds safe integer
// @ts-ignore
} = stream?.session?.remoteSettings?.customSettings || {}
const retObj = {
Expand All @@ -304,7 +313,9 @@ export class Http2WebTransportServer {
streamShouldAutoTuneReceiveWindow:
this.streamShouldAutoTuneReceiveWindow,
streamReceiveWindowSizeLimit:
this.streamFlowControlWindowSizeLimit
this.streamFlowControlWindowSizeLimit,
maxDatagramSize: this.initialDatagramSize,
remoteMaxDatagramSize
})
} else {
return (this.capsParser = new WebSocketParser({
Expand All @@ -318,7 +329,9 @@ export class Http2WebTransportServer {
streamShouldAutoTuneReceiveWindow:
this.streamShouldAutoTuneReceiveWindow,
streamReceiveWindowSizeLimit:
this.streamFlowControlWindowSizeLimit
this.streamFlowControlWindowSizeLimit,
maxDatagramSize: this.initialDatagramSize,
remoteMaxDatagramSize
}))
}
},
Expand Down Expand Up @@ -523,7 +536,9 @@ export class Http2WebTransportServer {
streamShouldAutoTuneReceiveWindow:
this.streamShouldAutoTuneReceiveWindow,
streamReceiveWindowSizeLimit:
this.streamFlowControlWindowSizeLimit
this.streamFlowControlWindowSizeLimit,
maxDatagramSize: this.initialDatagramSize,
remoteMaxDatagramSize: 2 ** 62 - 1 // we wait for the frame
}))
if (head && head.byteLength > 0) parse.parseData(head)
return parse
Expand Down Expand Up @@ -570,7 +585,8 @@ export class Http2WebTransportServer {
0x2b64: remoteUnidirectionalStreams = undefined,
0x2b63: remoteBidirectionalStreamFlowControlWindow = undefined,
0x2b62: remoteUnidirectionalStreamFlowControlWindow = undefined,
0x2b61: remoteSessionFlowControlWindow = undefined
0x2b61: remoteSessionFlowControlWindow = undefined,
0x2b66: remoteMaxDatagramSize = 2 ** 62 - 1 // note this exceeds safe integer
// @ts-ignore
} = stream?.session?.remoteSettings?.customSettings || {}
const retObj = {
Expand All @@ -596,7 +612,9 @@ export class Http2WebTransportServer {
streamShouldAutoTuneReceiveWindow:
this.streamShouldAutoTuneReceiveWindow,
streamReceiveWindowSizeLimit:
this.streamFlowControlWindowSizeLimit
this.streamFlowControlWindowSizeLimit,
maxDatagramSize: this.initialDatagramSize,
remoteMaxDatagramSize
})
} else {
return (this.capsParser = new WebSocketParser({
Expand All @@ -610,7 +628,9 @@ export class Http2WebTransportServer {
streamShouldAutoTuneReceiveWindow:
this.streamShouldAutoTuneReceiveWindow,
streamReceiveWindowSizeLimit:
this.streamFlowControlWindowSizeLimit
this.streamFlowControlWindowSizeLimit,
maxDatagramSize: this.initialDatagramSize,
remoteMaxDatagramSize
}))
}
},
Expand Down
34 changes: 22 additions & 12 deletions main/lib/http2/node/websocketparser.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,9 @@ export class WebSocketParser extends ParserBaseHttp2 {
initialStreamSendWindowOffsetBidi,
initialStreamReceiveWindowOffset,
streamShouldAutoTuneReceiveWindow,
streamReceiveWindowSizeLimit
streamReceiveWindowSizeLimit,
maxDatagramSize,
remoteMaxDatagramSize
}) {
super({
stream,
Expand All @@ -193,7 +195,9 @@ export class WebSocketParser extends ParserBaseHttp2 {
initialStreamSendWindowOffsetBidi,
initialStreamReceiveWindowOffset,
streamShouldAutoTuneReceiveWindow,
streamReceiveWindowSizeLimit
streamReceiveWindowSizeLimit,
maxDatagramSize,
remoteMaxDatagramSize
})
this.mode = 's' // frame start
/** @type {Buffer|undefined} */
Expand Down Expand Up @@ -433,8 +437,8 @@ export class WebSocketParser extends ParserBaseHttp2 {
if (
type === ParserBase.PADDING ||
type === ParserBase.WT_STREAM_WOFIN ||
type ===
ParserBase.WT_STREAM_WFIN /* || type === ParserBase.DATAGRAM */
type === ParserBase.WT_STREAM_WFIN ||
(type === ParserBase.DATAGRAM && length > this.maxDatagramSize) // if we exceed maximum size of datagram we drop
) {
checklength = Math.min(length, 64) // stream id + some Data
}
Expand Down Expand Up @@ -608,6 +612,9 @@ export class WebSocketParser extends ParserBaseHttp2 {
case ParserBase.WT_STREAMS_BLOCKED_BIDI:
this.onStreamsBlockedBidi(readVarInt(bufferstate))
break
case ParserBase.WT_MAX_DATAGRAM_SIZE:
this.onMaxDatagramSize(readVarInt(bufferstate))
break
case ParserBase.CLOSE_WEBTRANSPORT_SESSION:
{
const code = readUint32(bufferstate) || 0
Expand All @@ -626,14 +633,17 @@ export class WebSocketParser extends ParserBaseHttp2 {
this.onDrain()
break
case ParserBase.DATAGRAM:
if (wbufferstate) {
this.session.jsobj.onDatagramReceived({
datagram: new Uint8Array(
wbufferstate.buffer.buffer,
wbufferstate.buffer.byteOffset + wbufferstate.offset,
offsetend - wbufferstate.offset
)
})
if (length <= this.maxDatagramSize) {
// drop too large datagrams
if (wbufferstate) {
this.session.jsobj.onDatagramReceived({
datagram: new Uint8Array(
wbufferstate.buffer.buffer,
wbufferstate.buffer.byteOffset + wbufferstate.offset,
offsetend - wbufferstate.offset
)
})
}
}
break
default:
Expand Down
Loading