@fails-components/webtransport 1.0.6 → 1.0.9
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/client.d.ts.map +1 -0
- package/dist/{main/lib → lib}/dom.d.ts +10 -2
- package/dist/lib/dom.d.ts.map +1 -0
- package/dist/lib/error.d.ts.map +1 -0
- package/dist/lib/features.d.ts +2 -0
- package/dist/lib/features.d.ts.map +1 -0
- package/dist/{main/lib → lib}/http2/browser/browser.d.ts +2 -0
- package/dist/lib/http2/browser/browser.d.ts.map +1 -0
- package/dist/lib/http2/browser/browserparser.d.ts.map +1 -0
- package/dist/{main/lib → lib}/http2/flowcontroller.d.ts +1 -1
- package/dist/lib/http2/flowcontroller.d.ts.map +1 -0
- package/dist/{main/lib → lib}/http2/node/capsuleparser.d.ts +1 -1
- package/dist/lib/http2/node/capsuleparser.d.ts.map +1 -0
- package/dist/{main/lib → lib}/http2/node/client.d.ts +2 -0
- package/dist/lib/http2/node/client.d.ts.map +1 -0
- package/dist/{main/test → lib/http2/node}/index.d.ts.map +1 -1
- package/dist/{main/lib → lib}/http2/node/server.d.ts +3 -0
- package/dist/lib/http2/node/server.d.ts.map +1 -0
- package/dist/{main/lib → lib}/http2/node/websocketparser.d.ts +4 -2
- package/dist/lib/http2/node/websocketparser.d.ts.map +1 -0
- package/dist/{main/lib → lib}/http2/parserbase.d.ts +26 -9
- package/dist/lib/http2/parserbase.d.ts.map +1 -0
- package/dist/lib/http2/parserbasehttp2.d.ts.map +1 -0
- package/dist/{main/lib → lib}/http2/session.d.ts +43 -6
- package/dist/lib/http2/session.d.ts.map +1 -0
- package/dist/{main/lib → lib}/http2/stream.d.ts +29 -7
- package/dist/lib/http2/stream.d.ts.map +1 -0
- package/dist/lib/http2/streamidmanager.d.ts +72 -0
- package/dist/lib/http2/streamidmanager.d.ts.map +1 -0
- package/dist/lib/http2/websocketcommon.d.ts.map +1 -0
- package/dist/lib/index.browser.d.ts.map +1 -0
- package/dist/lib/index.node.d.ts.map +1 -0
- package/dist/lib/server.d.ts.map +1 -0
- package/dist/{main/lib → lib}/session.d.ts +11 -4
- package/dist/lib/session.d.ts.map +1 -0
- package/dist/lib/stream.d.ts.map +1 -0
- package/dist/{main/lib → lib}/types.d.ts +26 -4
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/webstreams.browser.d.ts.map +1 -0
- package/dist/lib/webstreams.d.ts.map +1 -0
- package/dist/{main/lib → lib}/webtransport.browser.d.ts +12 -2
- package/dist/lib/webtransport.browser.d.ts.map +1 -0
- package/dist/lib/webtransport.node.d.ts.map +1 -0
- package/dist/{main/lib → lib}/webtransportbase.d.ts +14 -2
- package/dist/lib/webtransportbase.d.ts.map +1 -0
- package/lib/dom.ts +12 -2
- package/lib/features.js +16 -0
- package/lib/http2/browser/browser.js +12 -3
- package/lib/http2/browser/browserparser.js +36 -36
- package/lib/http2/flowcontroller.js +2 -2
- package/lib/http2/node/capsuleparser.js +58 -51
- package/lib/http2/node/client.js +12 -3
- package/lib/http2/node/server.js +53 -16
- package/lib/http2/node/websocketparser.js +69 -59
- package/lib/http2/parserbase.js +87 -12
- package/lib/http2/session.js +109 -34
- package/lib/http2/stream.js +65 -10
- package/lib/http2/streamidmanager.js +316 -0
- package/lib/session.js +47 -15
- package/lib/stream.js +46 -39
- package/lib/types.ts +20 -4
- package/lib/webtransport.browser.js +14 -4
- package/lib/webtransportbase.js +14 -4
- package/package.json +5 -2
- package/readme.md +4 -3
- package/test/fixtures/certificate.js +1 -2
- package/test/fixtures/server.js +112 -7
- package/test/fixtures/webtransport.browser.js +1 -1
- package/test/index.js +1 -1
- package/test/stream-limits.spec.js +247 -0
- package/tsconfig.json +2 -7
- package/dist/main/lib/client.d.ts.map +0 -1
- package/dist/main/lib/dom.d.ts.map +0 -1
- package/dist/main/lib/error.d.ts.map +0 -1
- package/dist/main/lib/http2/browser/browser.d.ts.map +0 -1
- package/dist/main/lib/http2/browser/browserparser.d.ts.map +0 -1
- package/dist/main/lib/http2/flowcontroller.d.ts.map +0 -1
- package/dist/main/lib/http2/node/capsuleparser.d.ts.map +0 -1
- package/dist/main/lib/http2/node/client.d.ts.map +0 -1
- package/dist/main/lib/http2/node/index.d.ts.map +0 -1
- package/dist/main/lib/http2/node/server.d.ts.map +0 -1
- package/dist/main/lib/http2/node/websocketparser.d.ts.map +0 -1
- package/dist/main/lib/http2/parserbase.d.ts.map +0 -1
- package/dist/main/lib/http2/parserbasehttp2.d.ts.map +0 -1
- package/dist/main/lib/http2/session.d.ts.map +0 -1
- package/dist/main/lib/http2/stream.d.ts.map +0 -1
- package/dist/main/lib/http2/websocketcommon.d.ts.map +0 -1
- package/dist/main/lib/index.browser.d.ts.map +0 -1
- package/dist/main/lib/index.node.d.ts.map +0 -1
- package/dist/main/lib/server.d.ts.map +0 -1
- package/dist/main/lib/session.d.ts.map +0 -1
- package/dist/main/lib/stream.d.ts.map +0 -1
- package/dist/main/lib/types.d.ts.map +0 -1
- package/dist/main/lib/utils.d.ts.map +0 -1
- package/dist/main/lib/webstreams.browser.d.ts.map +0 -1
- package/dist/main/lib/webstreams.d.ts.map +0 -1
- package/dist/main/lib/webtransport.browser.d.ts.map +0 -1
- package/dist/main/lib/webtransport.node.d.ts.map +0 -1
- package/dist/main/lib/webtransportbase.d.ts.map +0 -1
- package/dist/main/test/bidirectional-streams.spec.d.ts +0 -5
- package/dist/main/test/bidirectional-streams.spec.d.ts.map +0 -1
- package/dist/main/test/datagrams.spec.d.ts +0 -5
- package/dist/main/test/datagrams.spec.d.ts.map +0 -1
- package/dist/main/test/fixtures/certificate.d.ts +0 -21
- package/dist/main/test/fixtures/certificate.d.ts.map +0 -1
- package/dist/main/test/fixtures/chai.d.ts +0 -2
- package/dist/main/test/fixtures/chai.d.ts.map +0 -1
- package/dist/main/test/fixtures/known-bytes.d.ts +0 -8
- package/dist/main/test/fixtures/known-bytes.d.ts.map +0 -1
- package/dist/main/test/fixtures/p-timeout.d.ts +0 -8
- package/dist/main/test/fixtures/p-timeout.d.ts.map +0 -1
- package/dist/main/test/fixtures/read-cert-hash.d.ts +0 -6
- package/dist/main/test/fixtures/read-cert-hash.d.ts.map +0 -1
- package/dist/main/test/fixtures/read-stream.d.ts +0 -18
- package/dist/main/test/fixtures/read-stream.d.ts.map +0 -1
- package/dist/main/test/fixtures/reader-value.d.ts +0 -21
- package/dist/main/test/fixtures/reader-value.d.ts.map +0 -1
- package/dist/main/test/fixtures/server.d.ts +0 -5
- package/dist/main/test/fixtures/server.d.ts.map +0 -1
- package/dist/main/test/fixtures/webtransport.browser.d.ts +0 -4
- package/dist/main/test/fixtures/webtransport.browser.d.ts.map +0 -1
- package/dist/main/test/fixtures/webtransport.d.ts +0 -3
- package/dist/main/test/fixtures/webtransport.d.ts.map +0 -1
- package/dist/main/test/fixtures/write-stream.d.ts +0 -10
- package/dist/main/test/fixtures/write-stream.d.ts.map +0 -1
- package/dist/main/test/index.d.ts +0 -2
- package/dist/main/test/session.spec.d.ts +0 -5
- package/dist/main/test/session.spec.d.ts.map +0 -1
- package/dist/main/test/unidirectional-streams.spec.d.ts +0 -2
- package/dist/main/test/unidirectional-streams.spec.d.ts.map +0 -1
- package/dist/main/tsconfig.tsbuildinfo +0 -1
- package/dist/transports/http3-quiche/lib/clientsocket.d.ts +0 -19
- package/dist/transports/http3-quiche/lib/clientsocket.d.ts.map +0 -1
- package/dist/transports/http3-quiche/lib/index.d.ts +0 -11
- package/dist/transports/http3-quiche/lib/index.d.ts.map +0 -1
- package/dist/transports/http3-quiche/lib/serversocket.d.ts +0 -12
- package/dist/transports/http3-quiche/lib/serversocket.d.ts.map +0 -1
- package/dist/transports/http3-quiche/lib/socket.d.ts +0 -19
- package/dist/transports/http3-quiche/lib/socket.d.ts.map +0 -1
- package/dist/transports/http3-quiche/lib/types.d.ts +0 -21
- package/dist/transports/http3-quiche/lib/types.d.ts.map +0 -1
- package/dist/transports/http3-quiche/lib/utils.d.ts +0 -6
- package/dist/transports/http3-quiche/lib/utils.d.ts.map +0 -1
- /package/dist/{main/lib → lib}/client.d.ts +0 -0
- /package/dist/{main/lib → lib}/error.d.ts +0 -0
- /package/dist/{main/lib → lib}/http2/browser/browserparser.d.ts +0 -0
- /package/dist/{main/lib → lib}/http2/node/index.d.ts +0 -0
- /package/dist/{main/lib → lib}/http2/parserbasehttp2.d.ts +0 -0
- /package/dist/{main/lib → lib}/http2/websocketcommon.d.ts +0 -0
- /package/dist/{main/lib → lib}/index.browser.d.ts +0 -0
- /package/dist/{main/lib → lib}/index.node.d.ts +0 -0
- /package/dist/{main/lib → lib}/server.d.ts +0 -0
- /package/dist/{main/lib → lib}/stream.d.ts +0 -0
- /package/dist/{main/lib → lib}/utils.d.ts +0 -0
- /package/dist/{main/lib → lib}/webstreams.browser.d.ts +0 -0
- /package/dist/{main/lib → lib}/webstreams.d.ts +0 -0
- /package/dist/{main/lib → lib}/webtransport.node.d.ts +0 -0
package/lib/session.js
CHANGED
|
@@ -2,6 +2,7 @@ import { ReadableStream, WritableStream } from './webstreams.js'
|
|
|
2
2
|
import { HttpWTStream } from './stream.js'
|
|
3
3
|
import { WebTransportError } from './error.js'
|
|
4
4
|
import { logger } from './utils.js'
|
|
5
|
+
import { canByteStream } from './features.js'
|
|
5
6
|
|
|
6
7
|
const pid = typeof process !== 'undefined' ? process.pid : 0
|
|
7
8
|
const log = logger(`webtransport:httpwtsession(${pid})`)
|
|
@@ -21,6 +22,7 @@ const log = logger(`webtransport:httpwtsession(${pid})`)
|
|
|
21
22
|
* @typedef {import('./dom').WebTransportCloseInfo} WebTransportCloseInfo
|
|
22
23
|
* @typedef {import('./dom').WebTransportBidirectionalStream} WebTransportBidirectionalStream
|
|
23
24
|
* @typedef {import('./dom').WebTransportSendStream} WebTransportSendStream
|
|
25
|
+
* @typedef {import('./dom').WebTransportSendStreamOptions} WebTransportSendStreamOptions
|
|
24
26
|
* @typedef {import('./dom').WebTransportReceiveStream} WebTransportReceiveStream
|
|
25
27
|
* @typedef {import('./dom').WebTransportDatagramDuplexStream} WebTransportDatagramDuplexStream
|
|
26
28
|
* @typedef {import('./dom').WebTransportReliabilityMode} WebTransportReliabilityMode
|
|
@@ -113,19 +115,23 @@ export class HttpWTSession {
|
|
|
113
115
|
this.writeDatagramRej = []
|
|
114
116
|
/** @type {Array<Promise<void>>} */
|
|
115
117
|
this.writeDatagramProm = []
|
|
116
|
-
|
|
118
|
+
const readableopts = {
|
|
119
|
+
start: (
|
|
120
|
+
/** @type {import("stream/web").ReadableByteStreamController} */ controller
|
|
121
|
+
) => {
|
|
122
|
+
this.incomDatagramController = controller
|
|
123
|
+
},
|
|
124
|
+
type: 'bytes'
|
|
125
|
+
}
|
|
126
|
+
if (!canByteStream) {
|
|
127
|
+
// @ts-ignore
|
|
128
|
+
delete readableopts.type
|
|
129
|
+
}
|
|
117
130
|
/** @type {WebTransportDatagramDuplexStream} */
|
|
118
131
|
this.datagrams = {
|
|
119
132
|
/** @type {ReadableStream<Uint8Array>} */
|
|
120
133
|
// @ts-ignore
|
|
121
|
-
readable: new ReadableStream(
|
|
122
|
-
start: (
|
|
123
|
-
/** @type {import("stream/web").ReadableByteStreamController} */ controller
|
|
124
|
-
) => {
|
|
125
|
-
this.incomDatagramController = controller
|
|
126
|
-
},
|
|
127
|
-
type: 'bytes'
|
|
128
|
-
}),
|
|
134
|
+
readable: new ReadableStream(readableopts),
|
|
129
135
|
writable: new WritableStream({
|
|
130
136
|
start: (controller) => {
|
|
131
137
|
this.outgoDatagramController = controller
|
|
@@ -194,6 +200,9 @@ export class HttpWTSession {
|
|
|
194
200
|
this.objint = object
|
|
195
201
|
this.objint.jsobj = this
|
|
196
202
|
this.reliable = !!reliable
|
|
203
|
+
if (this.objint.sendInitialParameters) {
|
|
204
|
+
this.objint.sendInitialParameters()
|
|
205
|
+
}
|
|
197
206
|
}
|
|
198
207
|
}
|
|
199
208
|
|
|
@@ -334,9 +343,10 @@ export class HttpWTSession {
|
|
|
334
343
|
}
|
|
335
344
|
|
|
336
345
|
/**
|
|
346
|
+
* @param {WebTransportSendStreamOptions} [opts]
|
|
337
347
|
* @returns {Promise<WebTransportBidirectionalStream>}
|
|
338
348
|
*/
|
|
339
|
-
createBidirectionalStream() {
|
|
349
|
+
createBidirectionalStream(opts) {
|
|
340
350
|
if (this.objint == null) {
|
|
341
351
|
throw new Error('this.objint not set')
|
|
342
352
|
}
|
|
@@ -345,14 +355,25 @@ export class HttpWTSession {
|
|
|
345
355
|
this.resolveBiDi.push(resolve)
|
|
346
356
|
this.rejectBiDi.push(reject)
|
|
347
357
|
})
|
|
348
|
-
this.objint.orderBidiStream(
|
|
358
|
+
const notblocked = this.objint.orderBidiStream({
|
|
359
|
+
sendGroup: opts?.sendGroup || null, // maybe replace, when implemented
|
|
360
|
+
sendOrder: opts?.sendOrder || 0,
|
|
361
|
+
waitUntilAvailable: opts?.waitUntilAvailable || false
|
|
362
|
+
})
|
|
363
|
+
if (!notblocked) {
|
|
364
|
+
const rej = this.rejectBiDi.pop()
|
|
365
|
+
this.resolveBiDi.pop()
|
|
366
|
+
if (rej)
|
|
367
|
+
rej(new DOMException('No streams available', 'QuotaExceededError'))
|
|
368
|
+
}
|
|
349
369
|
return prom
|
|
350
370
|
}
|
|
351
371
|
|
|
352
372
|
/**
|
|
353
|
-
|
|
373
|
+
* @param {WebTransportSendStreamOptions} [opts]
|
|
374
|
+
* @returns {Promise<WebTransportSendStream>}
|
|
354
375
|
*/
|
|
355
|
-
createUnidirectionalStream() {
|
|
376
|
+
createUnidirectionalStream(opts) {
|
|
356
377
|
if (this.objint == null) {
|
|
357
378
|
throw new Error('this.objint not set')
|
|
358
379
|
}
|
|
@@ -361,7 +382,17 @@ export class HttpWTSession {
|
|
|
361
382
|
this.resolveUniDi.push(resolve)
|
|
362
383
|
this.rejectUniDi.push(reject)
|
|
363
384
|
})
|
|
364
|
-
this.objint.orderUnidiStream(
|
|
385
|
+
const notblocked = this.objint.orderUnidiStream({
|
|
386
|
+
sendGroup: opts?.sendGroup || null, // maybe replace, when implemented
|
|
387
|
+
sendOrder: opts?.sendOrder || 0,
|
|
388
|
+
waitUntilAvailable: opts?.waitUntilAvailable || false
|
|
389
|
+
})
|
|
390
|
+
if (!notblocked) {
|
|
391
|
+
const rej = this.rejectUniDi.pop()
|
|
392
|
+
this.resolveUniDi.pop()
|
|
393
|
+
if (rej)
|
|
394
|
+
rej(new DOMException('No streams available', 'QuotaExceededError'))
|
|
395
|
+
}
|
|
365
396
|
return prom
|
|
366
397
|
}
|
|
367
398
|
|
|
@@ -548,8 +579,9 @@ export class HttpWTSession {
|
|
|
548
579
|
)
|
|
549
580
|
destview.set(args.datagram)
|
|
550
581
|
byob.respond(args.datagram.byteLength)
|
|
582
|
+
} else {
|
|
583
|
+
this.incomDatagramController.enqueue(new Uint8Array(args.datagram))
|
|
551
584
|
}
|
|
552
|
-
this.incomDatagramController.enqueue(new Uint8Array(args.datagram))
|
|
553
585
|
}
|
|
554
586
|
|
|
555
587
|
/**
|
package/lib/stream.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ReadableStream, WritableStream } from './webstreams.js'
|
|
2
2
|
import { logger } from './utils.js'
|
|
3
3
|
import { WebTransportError } from './error.js'
|
|
4
|
+
import { canByteStream } from './features.js'
|
|
4
5
|
|
|
5
6
|
const pid = typeof process !== 'undefined' ? process.pid : 0
|
|
6
7
|
const log = logger(`webtransport:http3wtstream(${pid})`)
|
|
@@ -60,48 +61,54 @@ export class HttpWTStream {
|
|
|
60
61
|
this.pendingresRead = null
|
|
61
62
|
|
|
62
63
|
if (this.bidirectional || this.incoming) {
|
|
64
|
+
const readableopts = {
|
|
65
|
+
start: (
|
|
66
|
+
/** @type {import("stream/web").ReadableByteStreamController} */ controller
|
|
67
|
+
) => {
|
|
68
|
+
this.readableController = controller
|
|
69
|
+
this.objint.startReading()
|
|
70
|
+
},
|
|
71
|
+
pull: async (
|
|
72
|
+
/** @type {import("stream/web").ReadableByteStreamController} */ controller
|
|
73
|
+
) => {
|
|
74
|
+
if (this.readableclosed) {
|
|
75
|
+
return Promise.resolve()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
this.pendingoperationRead = new Promise((resolve, reject) => {
|
|
79
|
+
this.pendingresRead = resolve
|
|
80
|
+
})
|
|
81
|
+
this.objint.startReading()
|
|
82
|
+
await this.pendingoperationRead
|
|
83
|
+
},
|
|
84
|
+
cancel: (/** @type {{ code: number; }} */ reason) => {
|
|
85
|
+
/** @type {Promise<void>} */
|
|
86
|
+
const promise = new Promise((resolve, reject) => {
|
|
87
|
+
this.cancelres = resolve
|
|
88
|
+
})
|
|
89
|
+
let code = 0
|
|
90
|
+
if (reason && reason.code) {
|
|
91
|
+
if (reason.code < 0) code = 0
|
|
92
|
+
else if (reason.code > 255) code = 255
|
|
93
|
+
else code = reason.code
|
|
94
|
+
}
|
|
95
|
+
this.readableclosed = true
|
|
96
|
+
this.objint.stopSending(code)
|
|
97
|
+
return promise
|
|
98
|
+
},
|
|
99
|
+
type: 'bytes',
|
|
100
|
+
autoAllocateChunkSize: 4096 // lets take this as buffer size
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!canByteStream) {
|
|
104
|
+
// @ts-ignore
|
|
105
|
+
delete readableopts.type
|
|
106
|
+
}
|
|
63
107
|
/** @type {WebTransportReceiveStream} */
|
|
64
108
|
// @ts-expect-error `getStats` property is missing from ReadableStream
|
|
65
109
|
this.readable = new ReadableStream(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
/** @type {import("stream/web").ReadableByteStreamController} */ controller
|
|
69
|
-
) => {
|
|
70
|
-
this.readableController = controller
|
|
71
|
-
this.objint.startReading()
|
|
72
|
-
},
|
|
73
|
-
pull: async (
|
|
74
|
-
/** @type {import("stream/web").ReadableByteStreamController} */ controller
|
|
75
|
-
) => {
|
|
76
|
-
if (this.readableclosed) {
|
|
77
|
-
return Promise.resolve()
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
this.pendingoperationRead = new Promise((resolve, reject) => {
|
|
81
|
-
this.pendingresRead = resolve
|
|
82
|
-
})
|
|
83
|
-
this.objint.startReading()
|
|
84
|
-
await this.pendingoperationRead
|
|
85
|
-
},
|
|
86
|
-
cancel: (/** @type {{ code: number; }} */ reason) => {
|
|
87
|
-
/** @type {Promise<void>} */
|
|
88
|
-
const promise = new Promise((resolve, reject) => {
|
|
89
|
-
this.cancelres = resolve
|
|
90
|
-
})
|
|
91
|
-
let code = 0
|
|
92
|
-
if (reason && reason.code) {
|
|
93
|
-
if (reason.code < 0) code = 0
|
|
94
|
-
else if (reason.code > 255) code = 255
|
|
95
|
-
else code = reason.code
|
|
96
|
-
}
|
|
97
|
-
this.readableclosed = true
|
|
98
|
-
this.objint.stopSending(code)
|
|
99
|
-
return promise
|
|
100
|
-
},
|
|
101
|
-
type: 'bytes',
|
|
102
|
-
autoAllocateChunkSize: 4096 // lets take this as buffer size
|
|
103
|
-
}
|
|
104
|
-
// TODO fix stretegy
|
|
110
|
+
// @ts-ignore
|
|
111
|
+
readableopts
|
|
105
112
|
)
|
|
106
113
|
this.readable.getStats = () => {
|
|
107
114
|
return Promise.resolve({
|
package/lib/types.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
WebTransportSession,
|
|
3
3
|
WebTransportHash,
|
|
4
|
-
WebTransportOptions
|
|
4
|
+
WebTransportOptions,
|
|
5
|
+
WebTransportSendGroup
|
|
5
6
|
} from './dom'
|
|
6
7
|
import type { IncomingHttpHeaders, Http2Stream } from 'http2'
|
|
7
8
|
import { ParserBase } from './http2/parserbase'
|
|
@@ -15,8 +16,8 @@ export interface NativeHttpWTSession {
|
|
|
15
16
|
jsobj: WebTransportSessionEventHandler
|
|
16
17
|
sendInitialParameters?: () => void
|
|
17
18
|
writeDatagram: (chunk: Uint8Array) => void
|
|
18
|
-
orderUnidiStream: () =>
|
|
19
|
-
orderBidiStream: ()
|
|
19
|
+
orderUnidiStream: (opts:{sendGroup: WebTransportSendGroup|null, sendOrder: number, waitUntilAvailable: boolean}) => boolean
|
|
20
|
+
orderBidiStream: (opts:{sendGroup: WebTransportSendGroup|null, sendOrder: number, waitUntilAvailable: boolean}) => boolean
|
|
20
21
|
orderSessionStats: () => void
|
|
21
22
|
orderDatagramStats: () => void
|
|
22
23
|
notifySessionDraining: () => void
|
|
@@ -47,12 +48,18 @@ export interface NativeServerOptions {
|
|
|
47
48
|
certhttp2?: string // if http2 has a different cert
|
|
48
49
|
privKey: string
|
|
49
50
|
privKeyhttp2?: string // if http2 has a different cert
|
|
51
|
+
initialBidirectionalSendStreams?: number
|
|
52
|
+
initialBidirectionalReceiveStreams?: number
|
|
53
|
+
initialUnidirectionalSendStreams?: number
|
|
54
|
+
initialUnidirectionalReceiveStreams?: number
|
|
50
55
|
initialStreamFlowControlWindow?: number
|
|
51
56
|
streamShouldAutoTuneReceiveWindow?: boolean
|
|
52
57
|
streamFlowControlWindowSizeLimit?: number
|
|
53
58
|
initialSessionFlowControlWindow?: number
|
|
54
59
|
sessionShouldAutoTuneReceiveWindow?: boolean
|
|
55
60
|
sessionFlowControlWindowSizeLimit?: number
|
|
61
|
+
initialBidirectionalStreams?: number
|
|
62
|
+
initialUnidirectionalStreams?: number
|
|
56
63
|
}
|
|
57
64
|
|
|
58
65
|
export interface NativeClientOptions {
|
|
@@ -62,6 +69,10 @@ export interface NativeClientOptions {
|
|
|
62
69
|
localPort: number
|
|
63
70
|
allowPooling: boolean
|
|
64
71
|
forceIpv6: boolean
|
|
72
|
+
initialBidirectionalSendStreams?: number
|
|
73
|
+
initialBidirectionalReceiveStreams?: number
|
|
74
|
+
initialUnidirectionalSendStreams?: number
|
|
75
|
+
initialUnidirectionalReceiveStreams?: number
|
|
65
76
|
initialStreamFlowControlWindow?: number
|
|
66
77
|
streamShouldAutoTuneReceiveWindow?: boolean
|
|
67
78
|
streamFlowControlWindowSizeLimit?: number
|
|
@@ -78,6 +89,11 @@ export interface FlowControlable {
|
|
|
78
89
|
smoothedRtt: () => number
|
|
79
90
|
}
|
|
80
91
|
|
|
92
|
+
export interface StreamIdClient {
|
|
93
|
+
canSendMaxStreams: () => boolean
|
|
94
|
+
sendMaxStreams: (maxStreams: bigint, unidirectional: boolean) => void
|
|
95
|
+
}
|
|
96
|
+
|
|
81
97
|
export interface ReadBuffer {
|
|
82
98
|
buffer?: Uint8Array
|
|
83
99
|
readBytes?: number
|
|
@@ -330,6 +346,6 @@ export interface ParserWebsocketInit extends ParserInit {
|
|
|
330
346
|
}
|
|
331
347
|
|
|
332
348
|
export interface ReadDataInt {
|
|
333
|
-
data: Uint8Array
|
|
349
|
+
data: Uint8Array|undefined
|
|
334
350
|
fin: boolean
|
|
335
351
|
}
|
|
@@ -10,6 +10,8 @@ const log = logger(`webtransport:browser()`)
|
|
|
10
10
|
* @typedef {import('./dom').WebTransport} WebTransport
|
|
11
11
|
* @typedef {import('./dom').WebTransportCloseInfo} WebTransportCloseInfo
|
|
12
12
|
* @typedef {import('./dom').WebTransportBidirectionalStream} WebTransportBidirectionalStream
|
|
13
|
+
* @typedef {import('./dom').WebTransportSendStream} WebTransportSendStream
|
|
14
|
+
* @typedef {import('./dom').WebTransportSendStreamOptions} WebTransportSendStreamOptions
|
|
13
15
|
* @typedef {import('./dom').WebTransportReceiveStream} WebTransportReceiveStream
|
|
14
16
|
* @typedef {import('./error').WebTransportError} WebTransportError
|
|
15
17
|
*/
|
|
@@ -307,13 +309,21 @@ export class WebTransportPolyfill {
|
|
|
307
309
|
this.curtransport.close(closeinfo)
|
|
308
310
|
}
|
|
309
311
|
|
|
310
|
-
|
|
312
|
+
/**
|
|
313
|
+
* @param {WebTransportSendStreamOptions} [opts]
|
|
314
|
+
* @returns {Promise<WebTransportBidirectionalStream>}
|
|
315
|
+
*/
|
|
316
|
+
async createBidirectionalStream(opts) {
|
|
311
317
|
await this.ready
|
|
312
|
-
return await this.curtransport.createBidirectionalStream()
|
|
318
|
+
return await this.curtransport.createBidirectionalStream(opts)
|
|
313
319
|
}
|
|
314
320
|
|
|
315
|
-
|
|
321
|
+
/**
|
|
322
|
+
* @param {WebTransportSendStreamOptions} [opts]
|
|
323
|
+
* @returns {Promise<WebTransportSendStream>}
|
|
324
|
+
*/
|
|
325
|
+
async createUnidirectionalStream(opts) {
|
|
316
326
|
await this.ready
|
|
317
|
-
return await this.curtransport.createUnidirectionalStream()
|
|
327
|
+
return await this.curtransport.createUnidirectionalStream(opts)
|
|
318
328
|
}
|
|
319
329
|
}
|
package/lib/webtransportbase.js
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* @typedef {import('./dom.js').WebTransportCloseInfo} WebTransportCloseInfo
|
|
5
5
|
* @typedef {import('./dom.js').WebTransportBidirectionalStream} WebTransportBidirectionalStream
|
|
6
6
|
* @typedef {import('./dom.js').WebTransportReceiveStream} WebTransportReceiveStream
|
|
7
|
+
* @typedef {import('./dom.js').WebTransportSendStream} WebTransportSendStream
|
|
8
|
+
* @typedef {import('./dom.js').WebTransportSendStreamOptions} WebTransportSendStreamOptions
|
|
7
9
|
* @typedef {import('./session.js').HttpWTSession} HttpWTSession
|
|
8
10
|
* @typedef { import('./session.js').HttpClient} HttpClient
|
|
9
11
|
*/
|
|
@@ -119,7 +121,11 @@ export class WebTransportBase {
|
|
|
119
121
|
return session.close(closeinfo)
|
|
120
122
|
}
|
|
121
123
|
|
|
122
|
-
|
|
124
|
+
/**
|
|
125
|
+
* @param {WebTransportSendStreamOptions} [opts]
|
|
126
|
+
* @returns {Promise<WebTransportBidirectionalStream>}
|
|
127
|
+
*/
|
|
128
|
+
createBidirectionalStream(opts) {
|
|
123
129
|
const session = this.sessionint
|
|
124
130
|
|
|
125
131
|
if (!session) {
|
|
@@ -127,10 +133,14 @@ export class WebTransportBase {
|
|
|
127
133
|
throw new Error('Http3WTSession was undefined')
|
|
128
134
|
}
|
|
129
135
|
|
|
130
|
-
return session.createBidirectionalStream()
|
|
136
|
+
return session.createBidirectionalStream(opts)
|
|
131
137
|
}
|
|
132
138
|
|
|
133
|
-
|
|
139
|
+
/**
|
|
140
|
+
* @param {WebTransportSendStreamOptions} [opts]
|
|
141
|
+
* @returns {Promise<WebTransportSendStream>}
|
|
142
|
+
*/
|
|
143
|
+
createUnidirectionalStream(opts) {
|
|
134
144
|
const session = this.sessionint
|
|
135
145
|
|
|
136
146
|
if (!session) {
|
|
@@ -138,6 +148,6 @@ export class WebTransportBase {
|
|
|
138
148
|
throw new Error('Http3WTSession was undefined')
|
|
139
149
|
}
|
|
140
150
|
|
|
141
|
-
return session.createUnidirectionalStream()
|
|
151
|
+
return session.createUnidirectionalStream(opts)
|
|
142
152
|
}
|
|
143
153
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fails-components/webtransport",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "A component to add webtransport support (server and client) to node.js using libquiche",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"types": "./dist/lib/index.d.ts",
|
|
16
16
|
"scripts": {
|
|
17
17
|
"start": "node test/echoserver.js",
|
|
18
|
-
"test": "npm run test:node && npm run test:node:http2 && npm run test:chromium && npm run test:chromium:http2:polyfill && npm run test:chromium:http2:ponyfill && npm run test:firefox && npm run test:firefox:http2:polyfill && npm run test:
|
|
18
|
+
"test": "npm run test:node && npm run test:node:http2 && npm run test:chromium && npm run test:chromium:http2:polyfill && npm run test:chromium:http2:ponyfill && npm run test:firefox:http2:polyfill && npm run test:firefox:http2:ponyfill && npm run test:webkit:http2:polyfill && npm run test:webkit:http2:ponyfill",
|
|
19
19
|
"test:node": "node test/index.js node http3",
|
|
20
20
|
"test:node:http2": "node test/index.js node http2",
|
|
21
21
|
"test:chromium": "node test/index.js chromium http3",
|
|
@@ -24,6 +24,9 @@
|
|
|
24
24
|
"test:firefox": "node test/index.js firefox http3",
|
|
25
25
|
"test:firefox:http2:polyfill": "node test/index.js firefox http2 polyfill",
|
|
26
26
|
"test:firefox:http2:ponyfill": "node test/index.js firefox http2 ponyfill",
|
|
27
|
+
"test:webkit": "node test/index.js webkit http3",
|
|
28
|
+
"test:webkit:http2:polyfill": "node test/index.js webkit http2 polyfill",
|
|
29
|
+
"test:webkit:http2:ponyfill": "node test/index.js webkit http2 ponyfill",
|
|
27
30
|
"oldtest": "node old_test/test.js",
|
|
28
31
|
"oldtesthttp2": "node old_test/test.js http2",
|
|
29
32
|
"lint": "eslint lib test old_test"
|
package/readme.md
CHANGED
|
@@ -23,8 +23,6 @@ Note, that the client implementation only supports certificate checking via `cer
|
|
|
23
23
|
It may be possible in the future to also support normal HTTP/3 with not so much effort, however, there is no intention from the author to implement this since it will not be needed by FAILS. However, PR requests are welcome and will be supported by advice from the author.
|
|
24
24
|
The package for the HTTP/3 should be considered as a duct tape-style solution until a bulletproof native support of HTTP/3 and WebTransport is provided by node itself.
|
|
25
25
|
|
|
26
|
-
If you need a ponyfill check out the sister package [https://github.com/fails-components/webtransport-ponyfill-websocket/](https://github.com/fails-components/webtransport-ponyfill-websocket/), which provides a mapping of the Webtransport interfaces to Websocket connections.
|
|
27
|
-
|
|
28
26
|
## Changes for Version 1.x.x
|
|
29
27
|
|
|
30
28
|
The interface for version 1.x.x is not changed compared to 0.x.x.
|
|
@@ -37,12 +35,15 @@ Note, that it is only partially implemented and also some http2 features require
|
|
|
37
35
|
Use for the server side either `HttpServer` for http/2 and http/3 support (including WebTransport over WebSocket), Http3Server for http/3 only and Http2Server for http/2 only.
|
|
38
36
|
For the client side pass the options `forceReliable`, `requireUnreliable` etc. to force/select a type of transport.
|
|
39
37
|
|
|
40
|
-
**Note, that the http/2 webtransport protocol (not supported by any browser yet), is implemented without the support of receiving initial settings, which can cause a problem with the initial flow control of the WebTransport streams. This is a current limitation in node.js. Note, that for sending the required initial setting you need a very recent (
|
|
38
|
+
**Note, that the http/2 webtransport protocol (not supported by any browser yet), is implemented without the support of receiving initial settings, which can cause a problem with the initial flow control of the WebTransport streams. This is a current limitation in node.js, but a patch to add support will soon be part of new node versions. Note, that for sending the required initial setting you need a very recent version (>=21.6.1) of node.js.** This limitation does not apply to the polyfill/ponyfill and the webtransport over websocket protocol.
|
|
39
|
+
|
|
40
|
+
The current proposal for the WebTransport over WebSocket protocol can be found [here] (https://datatracker.ietf.org/doc/draft-richter-webtransport-websocket/).
|
|
41
41
|
|
|
42
42
|
### Ponyfill/Polyfill
|
|
43
43
|
Together with an experimental http/2 implementation of WebTransport, the underlying http/2 capsule protocol had been mapped to the WebSocket protocol, so that the packages can also be used as a ponyfill/polyfill on the browser side.
|
|
44
44
|
Please use `WebTransportPonyfill` for a WebSocket only or `WebTransportPolyfill` as a replacement for `WebTransport`, which automatically falls back to the browser's implementation, if the corresponding features are natively supported in the browser.
|
|
45
45
|
|
|
46
|
+
The used WebSocket protocol is currently proprietary and described in detail [here](https://martenrichter.github.io/draft-ietf-webtransport-websocket/draft-richter-webtransport-websocket.html).
|
|
46
47
|
|
|
47
48
|
## Installation and usage
|
|
48
49
|
|
|
@@ -381,7 +381,7 @@ export async function generateWebTransportCertificate(attrs, options) {
|
|
|
381
381
|
options.extensions || [
|
|
382
382
|
{
|
|
383
383
|
name: 'basicConstraints',
|
|
384
|
-
cA:
|
|
384
|
+
cA: false
|
|
385
385
|
},
|
|
386
386
|
{
|
|
387
387
|
name: 'keyUsage',
|
|
@@ -428,7 +428,6 @@ export async function generateWebTransportCertificate(attrs, options) {
|
|
|
428
428
|
cert.signature = await cert.signature
|
|
429
429
|
|
|
430
430
|
const pemcert = pki.certificateToPem(cert)
|
|
431
|
-
|
|
432
431
|
const x509cert = new X509Certificate(pemcert)
|
|
433
432
|
|
|
434
433
|
const certhash = Buffer.from(
|
package/test/fixtures/server.js
CHANGED
|
@@ -39,7 +39,7 @@ export async function createServer() {
|
|
|
39
39
|
} else {
|
|
40
40
|
server = new Http3Server({
|
|
41
41
|
/* port: 8080,
|
|
42
|
-
|
|
42
|
+
host: '0.0.0.0', */
|
|
43
43
|
port: 0,
|
|
44
44
|
host: '127.0.0.1',
|
|
45
45
|
secret: 'mysecret',
|
|
@@ -48,10 +48,15 @@ export async function createServer() {
|
|
|
48
48
|
})
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
let adjustlimit = 1
|
|
52
|
+
if (process.env.USE_HTTP2 === 'true') {
|
|
53
|
+
adjustlimit = 0
|
|
54
|
+
}
|
|
55
|
+
|
|
51
56
|
server.ready
|
|
52
57
|
.then(async () => {
|
|
53
58
|
// set up listeners for the different server paths used by the tests
|
|
54
|
-
|
|
59
|
+
console.log('server ready')
|
|
55
60
|
await Promise.all(
|
|
56
61
|
[
|
|
57
62
|
// echo server, initiated by remote
|
|
@@ -162,6 +167,104 @@ export async function createServer() {
|
|
|
162
167
|
}
|
|
163
168
|
},
|
|
164
169
|
|
|
170
|
+
// receive 100+ bidi streams and block
|
|
171
|
+
async () => {
|
|
172
|
+
for await (const session of getReaderStream(
|
|
173
|
+
server.sessionStream('/streamlimits_getbidis_wua')
|
|
174
|
+
)) {
|
|
175
|
+
try {
|
|
176
|
+
await session.ready
|
|
177
|
+
const bidistreams = []
|
|
178
|
+
while (bidistreams.length < 100 - adjustlimit) {
|
|
179
|
+
bidistreams.push(
|
|
180
|
+
await getReaderValue(session.incomingBidirectionalStreams)
|
|
181
|
+
)
|
|
182
|
+
}
|
|
183
|
+
await getReaderValue(session.incomingUnidirectionalStreams)
|
|
184
|
+
await getReaderValue(session.incomingUnidirectionalStreams)
|
|
185
|
+
for (let i = 0; i < 50 + adjustlimit; i++) {
|
|
186
|
+
/* const curstream = */ bidistreams.shift()
|
|
187
|
+
// await curstream.writable.close() // canceled by client
|
|
188
|
+
}
|
|
189
|
+
while (bidistreams.length < 100 - adjustlimit) {
|
|
190
|
+
bidistreams.push(
|
|
191
|
+
await getReaderValue(session.incomingBidirectionalStreams)
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
|
+
await getReaderValue(session.incomingUnidirectionalStreams)
|
|
195
|
+
await session.close()
|
|
196
|
+
} catch (error) {
|
|
197
|
+
// do not crash server, if a problem occurs...
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
// receive 100+ bidi streams and do not block
|
|
202
|
+
async () => {
|
|
203
|
+
for await (const session of getReaderStream(
|
|
204
|
+
server.sessionStream('/streamlimits_getbidis')
|
|
205
|
+
)) {
|
|
206
|
+
try {
|
|
207
|
+
await session.ready
|
|
208
|
+
const bidistreams = []
|
|
209
|
+
while (bidistreams.length < 150) {
|
|
210
|
+
bidistreams.push(
|
|
211
|
+
await getReaderValue(session.incomingBidirectionalStreams)
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
await session.close()
|
|
215
|
+
} catch (error) {
|
|
216
|
+
// do not crash server, if a problem occurs...
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
async () => {
|
|
221
|
+
for await (const session of getReaderStream(
|
|
222
|
+
server.sessionStream('/streamlimits_getunidis_wua')
|
|
223
|
+
)) {
|
|
224
|
+
try {
|
|
225
|
+
await session.ready
|
|
226
|
+
const unidistreams = []
|
|
227
|
+
while (unidistreams.length < 100 - adjustlimit) {
|
|
228
|
+
unidistreams.push(
|
|
229
|
+
await getReaderValue(session.incomingUnidirectionalStreams)
|
|
230
|
+
)
|
|
231
|
+
}
|
|
232
|
+
await getReaderValue(session.incomingBidirectionalStreams)
|
|
233
|
+
await getReaderValue(session.incomingBidirectionalStreams)
|
|
234
|
+
for (let i = 0; i < 50 + adjustlimit; i++) {
|
|
235
|
+
unidistreams.shift()
|
|
236
|
+
}
|
|
237
|
+
while (unidistreams.length < 100 - adjustlimit) {
|
|
238
|
+
unidistreams.push(
|
|
239
|
+
await getReaderValue(session.incomingUnidirectionalStreams)
|
|
240
|
+
)
|
|
241
|
+
}
|
|
242
|
+
await getReaderValue(session.incomingBidirectionalStreams)
|
|
243
|
+
await session.close()
|
|
244
|
+
} catch (error) {
|
|
245
|
+
// do not crash server, if a problem occurs...
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
// receive 100+ unidi streams and do not block
|
|
250
|
+
async () => {
|
|
251
|
+
for await (const session of getReaderStream(
|
|
252
|
+
server.sessionStream('/streamlimits_getunidis')
|
|
253
|
+
)) {
|
|
254
|
+
try {
|
|
255
|
+
await session.ready
|
|
256
|
+
const unidistreams = []
|
|
257
|
+
while (unidistreams.length < 150) {
|
|
258
|
+
unidistreams.push(
|
|
259
|
+
await getReaderValue(session.incomingUnidirectionalStreams)
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
await session.close()
|
|
263
|
+
} catch (error) {
|
|
264
|
+
// do not crash server, if a problem occurs...
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
},
|
|
165
268
|
// cleanly close remote sessions
|
|
166
269
|
async () => {
|
|
167
270
|
for await (const session of getReaderStream(
|
|
@@ -281,8 +384,10 @@ if (process.send)
|
|
|
281
384
|
address: `https://${address.host}:${address.port}`,
|
|
282
385
|
certificate: certificate.fingerprint
|
|
283
386
|
})
|
|
284
|
-
else
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
387
|
+
else {
|
|
388
|
+
console.error('No IPC channel')
|
|
389
|
+
console.log({
|
|
390
|
+
address: `https://${address.host}:${address.port}`,
|
|
391
|
+
certificate: certificate.fingerprint
|
|
392
|
+
})
|
|
393
|
+
}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
/** @type {import('../../lib/dom').WebTransport} */
|
|
7
7
|
// @ts-ignore
|
|
8
8
|
// eslint-disable-next-line no-undef
|
|
9
|
-
let webtransport = WebTransport
|
|
9
|
+
let webtransport = globalThis.WebTransport
|
|
10
10
|
if (process.env.USE_POLYFILL === 'true') {
|
|
11
11
|
// @ts-ignore
|
|
12
12
|
webtransport = WebTransportPolyfill
|
package/test/index.js
CHANGED
|
@@ -70,7 +70,7 @@ async function runTests(certificate, serverAddress) {
|
|
|
70
70
|
})
|
|
71
71
|
|
|
72
72
|
await tests
|
|
73
|
-
} else if (env === 'chromium' || env === 'firefox') {
|
|
73
|
+
} else if (env === 'chromium' || env === 'firefox' || env === 'webkit') {
|
|
74
74
|
command = 'playwright-test'
|
|
75
75
|
const otheropts = []
|
|
76
76
|
if (polyfill || ponyfill || env === 'firefox')
|