@fails-components/webtransport 1.1.4 → 1.2.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/dist/lib/dom.d.ts +27 -10
- package/dist/lib/dom.d.ts.map +1 -1
- package/dist/lib/http2/browser/browser.d.ts +5 -2
- package/dist/lib/http2/browser/browser.d.ts.map +1 -1
- package/dist/lib/http2/browser/browserparser.d.ts.map +1 -1
- package/dist/lib/http2/node/capsuleparser.d.ts.map +1 -1
- package/dist/lib/http2/node/client.d.ts +3 -2
- package/dist/lib/http2/node/client.d.ts.map +1 -1
- package/dist/lib/http2/node/server.d.ts +10 -5
- package/dist/lib/http2/node/server.d.ts.map +1 -1
- package/dist/lib/http2/node/websocketparser.d.ts.map +1 -1
- package/dist/lib/http2/parserbase.d.ts +33 -1
- package/dist/lib/http2/parserbase.d.ts.map +1 -1
- package/dist/lib/http2/priorityscheduler.d.ts +167 -0
- package/dist/lib/http2/priorityscheduler.d.ts.map +1 -0
- package/dist/lib/http2/session.d.ts +25 -16
- package/dist/lib/http2/session.d.ts.map +1 -1
- package/dist/lib/http2/stream.d.ts +10 -0
- package/dist/lib/http2/stream.d.ts.map +1 -1
- package/dist/lib/http2/websocketcommon.d.ts.map +1 -1
- package/dist/lib/server.d.ts.map +1 -1
- package/dist/lib/session.d.ts +31 -17
- package/dist/lib/session.d.ts.map +1 -1
- package/dist/lib/stream.d.ts +13 -0
- package/dist/lib/stream.d.ts.map +1 -1
- package/dist/lib/types.d.ts +18 -15
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/webtransport.browser.d.ts +3 -2
- package/dist/lib/webtransport.browser.d.ts.map +1 -1
- package/dist/lib/webtransportbase.d.ts +1 -0
- package/dist/lib/webtransportbase.d.ts.map +1 -1
- package/eslint.config.js +20 -22
- package/lib/dom.ts +31 -13
- package/lib/http2/browser/browser.js +28 -13
- package/lib/http2/browser/browserparser.js +4 -1
- package/lib/http2/node/capsuleparser.js +4 -1
- package/lib/http2/node/client.js +38 -27
- package/lib/http2/node/server.js +56 -19
- package/lib/http2/node/websocketparser.js +5 -2
- package/lib/http2/parserbase.js +76 -7
- package/lib/http2/priorityscheduler.js +654 -0
- package/lib/http2/session.js +69 -20
- package/lib/http2/stream.js +60 -10
- package/lib/http2/websocketcommon.js +1 -1
- package/lib/server.js +0 -1
- package/lib/session.js +128 -64
- package/lib/stream.js +50 -8
- package/lib/types.ts +15 -8
- package/lib/webtransport.browser.js +77 -18
- package/lib/webtransportbase.js +7 -0
- package/old_test/testsuite.js +6 -2
- package/package.json +6 -6
- package/readme.md +3 -1
package/lib/stream.js
CHANGED
|
@@ -20,6 +20,8 @@ const log = logger(`webtransport:http3wtstream(${pid})`)
|
|
|
20
20
|
* @typedef {import('./dom').WebTransportReceiveStream} WebTransportReceiveStream
|
|
21
21
|
* @typedef {import('./dom').WebTransportSendStream} WebTransportSendStream
|
|
22
22
|
*
|
|
23
|
+
* @typedef {import('./dom').WebTransportSendGroup} WebTransportSendGroup
|
|
24
|
+
*
|
|
23
25
|
* @typedef {import('./session').HttpWTSession} HttpWTSession
|
|
24
26
|
*
|
|
25
27
|
* @typedef {import('stream/web').WritableStreamDefaultController} WritableStreamDefaultController
|
|
@@ -33,6 +35,8 @@ export class HttpWTStream {
|
|
|
33
35
|
* @param {object} args.transport
|
|
34
36
|
* @param {boolean} args.bidirectional
|
|
35
37
|
* @param {boolean} args.incoming
|
|
38
|
+
* @param {WebTransportSendGroup|undefined} args.sendGroup
|
|
39
|
+
* @param {bigint} args.sendOrder
|
|
36
40
|
*/
|
|
37
41
|
constructor(args) {
|
|
38
42
|
this.objint = args.object
|
|
@@ -43,6 +47,9 @@ export class HttpWTStream {
|
|
|
43
47
|
this.incoming = args.incoming
|
|
44
48
|
this.closed = false
|
|
45
49
|
|
|
50
|
+
this._sendGroup = args.sendGroup
|
|
51
|
+
this._sendOrder = args.sendOrder
|
|
52
|
+
|
|
46
53
|
if (this.objint.sendInitialParameters) {
|
|
47
54
|
this.objint.sendInitialParameters()
|
|
48
55
|
}
|
|
@@ -140,18 +147,15 @@ export class HttpWTStream {
|
|
|
140
147
|
wchunk = new Uint8Array(wchunk)
|
|
141
148
|
}
|
|
142
149
|
if (wchunk instanceof Uint8Array) {
|
|
150
|
+
if (wchunk.byteLength === 0) {
|
|
151
|
+
// or should we throw an error ?, Ask the W3C people!
|
|
152
|
+
return
|
|
153
|
+
}
|
|
143
154
|
// eslint-disable-next-line no-unused-vars
|
|
144
155
|
this.pendingoperation = new Promise((resolve, reject) => {
|
|
145
156
|
this.pendingres = resolve
|
|
146
157
|
})
|
|
147
|
-
this.
|
|
148
|
-
.waitForDatagramsSend()
|
|
149
|
-
.finally(() => {
|
|
150
|
-
this.objint.writeChunk(wchunk)
|
|
151
|
-
})
|
|
152
|
-
.catch((/** @type {any} */ err) => {
|
|
153
|
-
log.error(err)
|
|
154
|
-
})
|
|
158
|
+
this.objint.writeChunk(wchunk)
|
|
155
159
|
return this.pendingoperation
|
|
156
160
|
} else {
|
|
157
161
|
log.trace('chunk info:', chunk)
|
|
@@ -203,6 +207,36 @@ export class HttpWTStream {
|
|
|
203
207
|
bytesAcknowledged: 0n
|
|
204
208
|
})
|
|
205
209
|
}
|
|
210
|
+
Object.defineProperties(this.writable, {
|
|
211
|
+
sendOrder: {
|
|
212
|
+
get: () => {
|
|
213
|
+
return this._sendOrder
|
|
214
|
+
},
|
|
215
|
+
/**
|
|
216
|
+
* @param {bigint} value
|
|
217
|
+
*/
|
|
218
|
+
set: (value) => {
|
|
219
|
+
if (value !== this._sendOrder) {
|
|
220
|
+
this._sendOrder = args.sendOrder
|
|
221
|
+
this.updateSendOrderAndGroup()
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
sendGroup: {
|
|
226
|
+
get: () => {
|
|
227
|
+
return this._sendGroup
|
|
228
|
+
},
|
|
229
|
+
/**
|
|
230
|
+
* @param {WebTransportSendGroup} value
|
|
231
|
+
*/
|
|
232
|
+
set: (value) => {
|
|
233
|
+
if (value !== this._sendGroup) {
|
|
234
|
+
this._sendGroup = value
|
|
235
|
+
this.updateSendOrderAndGroup()
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
})
|
|
206
240
|
// @ts-ignore
|
|
207
241
|
this.parentobj.addSendStream(this.writable, this.writableController)
|
|
208
242
|
}
|
|
@@ -278,6 +312,14 @@ export class HttpWTStream {
|
|
|
278
312
|
return retObj
|
|
279
313
|
}
|
|
280
314
|
|
|
315
|
+
updateSendOrderAndGroup() {
|
|
316
|
+
this.objint.updateSendOrderAndGroup({
|
|
317
|
+
sendOrder: this._sendOrder,
|
|
318
|
+
// @ts-ignore
|
|
319
|
+
sendGroupId: this._sendGroup._sendGroupId
|
|
320
|
+
})
|
|
321
|
+
}
|
|
322
|
+
|
|
281
323
|
/**
|
|
282
324
|
* @param {import('./types').StreamRecvSignalEvent} args
|
|
283
325
|
* @returns {void}
|
package/lib/types.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type {
|
|
|
2
2
|
WebTransportSession,
|
|
3
3
|
WebTransportHash,
|
|
4
4
|
WebTransportOptions,
|
|
5
|
-
|
|
5
|
+
WebTransportSendStreamOptions
|
|
6
6
|
} from './dom'
|
|
7
7
|
import type { IncomingHttpHeaders, Http2Stream, ServerHttp2Stream } from 'http2'
|
|
8
8
|
import { ParserBase } from './http2/parserbase'
|
|
@@ -15,12 +15,13 @@ import { HttpClient } from './client'
|
|
|
15
15
|
export interface NativeHttpWTSession {
|
|
16
16
|
jsobj: WebTransportSessionEventHandler
|
|
17
17
|
sendInitialParameters?: () => void
|
|
18
|
-
writeDatagram: (chunk: Uint8Array) =>
|
|
19
|
-
orderUnidiStream: (opts:
|
|
20
|
-
orderBidiStream: (opts:
|
|
18
|
+
writeDatagram: (chunk: Uint8Array) => { code: 'success' | 'blocked' | 'internalError' | 'tooBig', message?: string}
|
|
19
|
+
orderUnidiStream: (opts: WebTransportSendStreamOptions) => boolean
|
|
20
|
+
orderBidiStream: (opts: WebTransportSendStreamOptions) => boolean
|
|
21
21
|
orderSessionStats: () => void
|
|
22
22
|
orderDatagramStats: () => void
|
|
23
23
|
notifySessionDraining: () => void
|
|
24
|
+
getMaxDatagramSize: () => number
|
|
24
25
|
close: (arg: { code: number; reason: string }) => void
|
|
25
26
|
}
|
|
26
27
|
|
|
@@ -38,6 +39,10 @@ export interface NativeHttpWTStream {
|
|
|
38
39
|
resetStream: (code: number) => void
|
|
39
40
|
writeChunk: (buf: Uint8Array) => void
|
|
40
41
|
streamFinal: () => void
|
|
42
|
+
updateSendOrderAndGroup: (args :{
|
|
43
|
+
sendOrder: bigint,
|
|
44
|
+
sendGroupId: bigint
|
|
45
|
+
}) => void
|
|
41
46
|
}
|
|
42
47
|
|
|
43
48
|
export interface NativeServerOptions {
|
|
@@ -79,6 +84,7 @@ export interface NativeClientOptions {
|
|
|
79
84
|
initialSessionFlowControlWindow?: number
|
|
80
85
|
sessionShouldAutoTuneReceiveWindow?: boolean
|
|
81
86
|
sessionFlowControlWindowSizeLimit?: number
|
|
87
|
+
protocols?: string[]
|
|
82
88
|
}
|
|
83
89
|
|
|
84
90
|
export interface FlowControlable {
|
|
@@ -110,7 +116,8 @@ export interface NativeFinishSessionRequest {
|
|
|
110
116
|
protocol: 'capsule' | 'websocket' | 'websocketoverhttp1' | 'http3'
|
|
111
117
|
head?: Buffer
|
|
112
118
|
userData?: object
|
|
113
|
-
transportPrivate?: object
|
|
119
|
+
transportPrivate?: object,
|
|
120
|
+
selectedProtocol?: string
|
|
114
121
|
}
|
|
115
122
|
|
|
116
123
|
export type Purpose =
|
|
@@ -150,6 +157,7 @@ export interface WebTransportStreamEventHandler {
|
|
|
150
157
|
|
|
151
158
|
export interface SessionReadyEvent {
|
|
152
159
|
object: NativeHttpWTSession
|
|
160
|
+
protocol?: string
|
|
153
161
|
}
|
|
154
162
|
|
|
155
163
|
export interface SessionCloseEvent {
|
|
@@ -179,21 +187,20 @@ export interface DatagramReceivedEvent {
|
|
|
179
187
|
datagram: Uint8Array
|
|
180
188
|
}
|
|
181
189
|
|
|
182
|
-
export interface DatagramSendEvent {}
|
|
183
|
-
|
|
184
190
|
export interface GoawayReceivedEvent {}
|
|
185
191
|
|
|
186
192
|
export interface NewStreamEvent {
|
|
187
193
|
stream: NativeHttpWTStream
|
|
188
194
|
bidirectional: boolean
|
|
189
195
|
incoming: boolean
|
|
196
|
+
sendGroupId?: bigint;
|
|
197
|
+
sendOrder: bigint;
|
|
190
198
|
}
|
|
191
199
|
|
|
192
200
|
export interface WebTransportSessionEventHandler {
|
|
193
201
|
onReady: (evt: SessionReadyEvent) => void
|
|
194
202
|
onClose: (evt: SessionCloseEvent) => void
|
|
195
203
|
onDatagramReceived: (evt: DatagramReceivedEvent) => void
|
|
196
|
-
onDatagramSend: (evt: DatagramSendEvent) => void
|
|
197
204
|
onGoAwayReceived: (evt: GoawayReceivedEvent) => void
|
|
198
205
|
onSessionStats: (evt: SessionStatsEvent) => void
|
|
199
206
|
onDatagramStats: (evt: DatagramStatsEvent) => void
|
|
@@ -3,6 +3,7 @@ import { HttpWTSession } from './session.js'
|
|
|
3
3
|
import { HttpClient } from './client.js'
|
|
4
4
|
import { Http2WebTransportBrowser } from './http2/browser/browser.js'
|
|
5
5
|
import { logger } from './utils.js'
|
|
6
|
+
import { WebTransportError } from './error'
|
|
6
7
|
|
|
7
8
|
const log = logger(`webtransport:browser()`)
|
|
8
9
|
|
|
@@ -13,7 +14,7 @@ const log = logger(`webtransport:browser()`)
|
|
|
13
14
|
* @typedef {import('./dom').WebTransportSendStream} WebTransportSendStream
|
|
14
15
|
* @typedef {import('./dom').WebTransportSendStreamOptions} WebTransportSendStreamOptions
|
|
15
16
|
* @typedef {import('./dom').WebTransportReceiveStream} WebTransportReceiveStream
|
|
16
|
-
* @typedef {import('./
|
|
17
|
+
* @typedef {import('./dom').WebTransportSendGroup} WebTransportSendGroup
|
|
17
18
|
*/
|
|
18
19
|
|
|
19
20
|
/**
|
|
@@ -215,7 +216,17 @@ export class WebTransportPolyfill {
|
|
|
215
216
|
}
|
|
216
217
|
/** @type {import('./dom').WebTransportDatagramDuplexStream} */
|
|
217
218
|
// @ts-ignore
|
|
218
|
-
this.datagrams = {
|
|
219
|
+
this.datagrams = {
|
|
220
|
+
// @ts-ignore
|
|
221
|
+
get writable() {
|
|
222
|
+
// @ts-ignore
|
|
223
|
+
if (!this.datagramwritablepolyfilled_) {
|
|
224
|
+
console.warn('datagrams.writable is deprecated')
|
|
225
|
+
}
|
|
226
|
+
// @ts-ignore
|
|
227
|
+
return (this.datagramwritablepolyfilled_ ||= this.createWritable())
|
|
228
|
+
}
|
|
229
|
+
}
|
|
219
230
|
// @ts-ignore
|
|
220
231
|
this.datagrams.readable = new ReadableStream({
|
|
221
232
|
// eslint-disable-next-line no-unused-vars
|
|
@@ -233,23 +244,67 @@ export class WebTransportPolyfill {
|
|
|
233
244
|
}
|
|
234
245
|
})
|
|
235
246
|
// @ts-ignore
|
|
236
|
-
this.datagrams.
|
|
237
|
-
//
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
this.datagramsWriter = this.curtransport.datagrams.writable.getWriter()
|
|
241
|
-
},
|
|
242
|
-
// eslint-disable-next-line no-unused-vars
|
|
243
|
-
write: async (chunk, controller) => {
|
|
244
|
-
await this.datagramsWriter.write(chunk)
|
|
245
|
-
},
|
|
246
|
-
abort: async (reason) => {
|
|
247
|
-
await this.datagramsWriter.abort(reason)
|
|
248
|
-
},
|
|
249
|
-
close: async () => {
|
|
250
|
-
await this.datagramsWriter.close()
|
|
247
|
+
this.datagrams.createWritable = (options) => {
|
|
248
|
+
// @ts-ignore Must not exist for older browser
|
|
249
|
+
if (this.curtransport.datagrams.createWritable) {
|
|
250
|
+
return this.curtransport.datagrams.createWritable(options)
|
|
251
251
|
}
|
|
252
|
-
|
|
252
|
+
// we need to fallback to the old default writable
|
|
253
|
+
// @ts-ignore
|
|
254
|
+
if (!this.curtransport.datagrams.writable) {
|
|
255
|
+
throw new WebTransportError('No way to send out datagrams')
|
|
256
|
+
}
|
|
257
|
+
let sendOrder = options?.sendOrder
|
|
258
|
+
let sendGroup = options?.sendGroup
|
|
259
|
+
const retWritable = new WritableStream({
|
|
260
|
+
// eslint-disable-next-line no-unused-vars
|
|
261
|
+
start: async (controller) => {
|
|
262
|
+
await this.ready
|
|
263
|
+
if (!this.datagramsWriter) {
|
|
264
|
+
this.datagramsWriter =
|
|
265
|
+
// @ts-ignore
|
|
266
|
+
this.curtransport.datagrams.writable.getWriter()
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
// eslint-disable-next-line no-unused-vars
|
|
270
|
+
write: async (chunk, controller) => {
|
|
271
|
+
await this.datagramsWriter.write(chunk)
|
|
272
|
+
},
|
|
273
|
+
abort: async (reason) => {
|
|
274
|
+
await this.datagramsWriter.abort(reason)
|
|
275
|
+
},
|
|
276
|
+
close: async () => {
|
|
277
|
+
await this.datagramsWriter.close()
|
|
278
|
+
}
|
|
279
|
+
})
|
|
280
|
+
Object.defineProperties(retWritable, {
|
|
281
|
+
sendOrder: {
|
|
282
|
+
get: () => {
|
|
283
|
+
return sendOrder
|
|
284
|
+
},
|
|
285
|
+
/**
|
|
286
|
+
* @param {number} value
|
|
287
|
+
*/
|
|
288
|
+
set: (value) => {
|
|
289
|
+
sendOrder = value
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
sendGroup: {
|
|
293
|
+
get: () => {
|
|
294
|
+
return sendGroup
|
|
295
|
+
},
|
|
296
|
+
/**
|
|
297
|
+
* @param {WebTransportSendGroup} value
|
|
298
|
+
*/
|
|
299
|
+
set: (value) => {
|
|
300
|
+
if (value !== sendGroup) {
|
|
301
|
+
sendGroup = value
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
})
|
|
306
|
+
return retWritable
|
|
307
|
+
}
|
|
253
308
|
this.incomingBidirectionalStreams = new ReadableStream({
|
|
254
309
|
// eslint-disable-next-line no-unused-vars
|
|
255
310
|
start: async (controller) => {
|
|
@@ -300,6 +355,10 @@ export class WebTransportPolyfill {
|
|
|
300
355
|
return true
|
|
301
356
|
}
|
|
302
357
|
|
|
358
|
+
get protocol() {
|
|
359
|
+
return this.curtransport?.protocol || undefined
|
|
360
|
+
}
|
|
361
|
+
|
|
303
362
|
getStats() {
|
|
304
363
|
// @ts-ignore
|
|
305
364
|
return this.curtransport.getStats()
|
package/lib/webtransportbase.js
CHANGED
package/old_test/testsuite.js
CHANGED
|
@@ -70,7 +70,9 @@ export async function unidirectionalEchoTest(session) {
|
|
|
70
70
|
*/
|
|
71
71
|
export async function datagramEchoTest(session) {
|
|
72
72
|
try {
|
|
73
|
-
|
|
73
|
+
const writable =
|
|
74
|
+
session.datagrams.writable || session.datagrams.createWritable()
|
|
75
|
+
session.datagrams.readable.pipeTo(writable)
|
|
74
76
|
} catch (error) {
|
|
75
77
|
console.log('datagram echo exited with', error)
|
|
76
78
|
}
|
|
@@ -287,7 +289,9 @@ export async function echoTestsConnection(transport) {
|
|
|
287
289
|
console.log('TEST 3: finish')
|
|
288
290
|
console.log('TEST 4: start')
|
|
289
291
|
console.log('finally test datagrams')
|
|
290
|
-
const
|
|
292
|
+
const dwritable =
|
|
293
|
+
transport.datagrams.writable || transport.datagrams.createWritable()
|
|
294
|
+
const datawrite = await dwritable.getWriter()
|
|
291
295
|
const data7 = new Uint8Array([83, 84, 85])
|
|
292
296
|
const data8 = new Uint8Array([86, 87, 88])
|
|
293
297
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fails-components/webtransport",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "A component to add webtransport support (server and client) to node.js using libquiche",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -53,13 +53,13 @@
|
|
|
53
53
|
"@types/node": "^18.15.3",
|
|
54
54
|
"eslint": "^9.3.0",
|
|
55
55
|
"eslint-config-prettier": "^9.1.0",
|
|
56
|
-
"eslint-
|
|
57
|
-
"eslint-plugin-import": "^2.25.2",
|
|
56
|
+
"eslint-plugin-import": "^2.31.0",
|
|
58
57
|
"eslint-plugin-node": "^11.1.0",
|
|
59
58
|
"eslint-plugin-prettier": "^5.1.3",
|
|
60
|
-
"eslint-plugin-promise": "^
|
|
61
|
-
"
|
|
62
|
-
"prettier": "^
|
|
59
|
+
"eslint-plugin-promise": "^7.2.1",
|
|
60
|
+
"prettier": "^3.5.3",
|
|
61
|
+
"prettier-linter-helpers": "^1.0.0",
|
|
62
|
+
"synckit": "^0.11.4",
|
|
63
63
|
"typescript": "^4.8.4",
|
|
64
64
|
"uint8arrays": "^4.0.2"
|
|
65
65
|
},
|
package/readme.md
CHANGED
|
@@ -109,7 +109,9 @@ Other but more expert options include:
|
|
|
109
109
|
* `certhttp2` and `privKeyhttp2`: For providing a different certificate for the http/2 as the http/2 implementation does not support certificate matching by fingerprints.
|
|
110
110
|
* `initialStreamFlowControlWindow`, `initialSessionFlowControlWindow`, `streamShouldAutoTuneReceiveWindow`, `sessionShouldAutoTuneReceiveWindow`, `streamFlowControlWindowSizeLimit`, `sessionFlowControlWindowSizeLimit`: As expert's option for tweaking the internal flow control.
|
|
111
111
|
|
|
112
|
-
The method `
|
|
112
|
+
The method `setRequestCallback(callback)` sets a callback, that inspects incoming headers and allows to change the incoming path header and also to throw an error if the session should not be opened.
|
|
113
|
+
It is also required for selecting the application level protocol.
|
|
114
|
+
In order to see how it is used, look into `test/fixtures/server.js` for a working example.
|
|
113
115
|
In general, the HTTP header is attached as the `header` property to the WebTransport Session object.
|
|
114
116
|
|
|
115
117
|
The method `updateCert(cert, privKey, http2only)` allows to change the certificate, while the server is running (not supported by all transports).
|