@fails-components/webtransport 1.0.8 → 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/{main/lib → lib}/features.d.ts.map +1 -1
- 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 +10 -3
- 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/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 +31 -5
- package/lib/types.ts +20 -4
- package/lib/webtransport.browser.js +14 -4
- package/lib/webtransportbase.js +14 -4
- package/package.json +1 -1
- package/readme.md +4 -3
- package/test/fixtures/certificate.js +1 -2
- package/test/fixtures/server.js +112 -7
- 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}/features.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
|
@@ -22,6 +22,7 @@ const log = logger(`webtransport:httpwtsession(${pid})`)
|
|
|
22
22
|
* @typedef {import('./dom').WebTransportCloseInfo} WebTransportCloseInfo
|
|
23
23
|
* @typedef {import('./dom').WebTransportBidirectionalStream} WebTransportBidirectionalStream
|
|
24
24
|
* @typedef {import('./dom').WebTransportSendStream} WebTransportSendStream
|
|
25
|
+
* @typedef {import('./dom').WebTransportSendStreamOptions} WebTransportSendStreamOptions
|
|
25
26
|
* @typedef {import('./dom').WebTransportReceiveStream} WebTransportReceiveStream
|
|
26
27
|
* @typedef {import('./dom').WebTransportDatagramDuplexStream} WebTransportDatagramDuplexStream
|
|
27
28
|
* @typedef {import('./dom').WebTransportReliabilityMode} WebTransportReliabilityMode
|
|
@@ -199,6 +200,9 @@ export class HttpWTSession {
|
|
|
199
200
|
this.objint = object
|
|
200
201
|
this.objint.jsobj = this
|
|
201
202
|
this.reliable = !!reliable
|
|
203
|
+
if (this.objint.sendInitialParameters) {
|
|
204
|
+
this.objint.sendInitialParameters()
|
|
205
|
+
}
|
|
202
206
|
}
|
|
203
207
|
}
|
|
204
208
|
|
|
@@ -339,9 +343,10 @@ export class HttpWTSession {
|
|
|
339
343
|
}
|
|
340
344
|
|
|
341
345
|
/**
|
|
346
|
+
* @param {WebTransportSendStreamOptions} [opts]
|
|
342
347
|
* @returns {Promise<WebTransportBidirectionalStream>}
|
|
343
348
|
*/
|
|
344
|
-
createBidirectionalStream() {
|
|
349
|
+
createBidirectionalStream(opts) {
|
|
345
350
|
if (this.objint == null) {
|
|
346
351
|
throw new Error('this.objint not set')
|
|
347
352
|
}
|
|
@@ -350,14 +355,25 @@ export class HttpWTSession {
|
|
|
350
355
|
this.resolveBiDi.push(resolve)
|
|
351
356
|
this.rejectBiDi.push(reject)
|
|
352
357
|
})
|
|
353
|
-
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
|
+
}
|
|
354
369
|
return prom
|
|
355
370
|
}
|
|
356
371
|
|
|
357
372
|
/**
|
|
358
|
-
|
|
373
|
+
* @param {WebTransportSendStreamOptions} [opts]
|
|
374
|
+
* @returns {Promise<WebTransportSendStream>}
|
|
359
375
|
*/
|
|
360
|
-
createUnidirectionalStream() {
|
|
376
|
+
createUnidirectionalStream(opts) {
|
|
361
377
|
if (this.objint == null) {
|
|
362
378
|
throw new Error('this.objint not set')
|
|
363
379
|
}
|
|
@@ -366,7 +382,17 @@ export class HttpWTSession {
|
|
|
366
382
|
this.resolveUniDi.push(resolve)
|
|
367
383
|
this.rejectUniDi.push(reject)
|
|
368
384
|
})
|
|
369
|
-
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
|
+
}
|
|
370
396
|
return prom
|
|
371
397
|
}
|
|
372
398
|
|
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
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
|
+
}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/* eslint-env mocha */
|
|
2
|
+
|
|
3
|
+
import { readCertHash } from './fixtures/read-cert-hash.js'
|
|
4
|
+
import WebTransport from './fixtures/webtransport.js'
|
|
5
|
+
import { expect } from './fixtures/chai.js'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @template T
|
|
9
|
+
* @typedef {import('../lib/types').Deferred<T>} Deferred<T>
|
|
10
|
+
*/
|
|
11
|
+
describe('streamlimits', function () {
|
|
12
|
+
this.timeout(6000) // for debugging remove before commit
|
|
13
|
+
let forceReliable = false
|
|
14
|
+
let adjustlimit = 1
|
|
15
|
+
if (process.env.USE_HTTP2 === 'true') {
|
|
16
|
+
forceReliable = true
|
|
17
|
+
adjustlimit = 0
|
|
18
|
+
}
|
|
19
|
+
const browser = process.env.BROWSER
|
|
20
|
+
/* const handshakemess =
|
|
21
|
+
browser !== 'firefox' ||
|
|
22
|
+
process.env.USE_POLYFILL === 'true' ||
|
|
23
|
+
process.env.USE_PONYFILL === 'true'
|
|
24
|
+
? 'Opening handshake failed.'
|
|
25
|
+
: 'WebTransport connection rejected' */
|
|
26
|
+
|
|
27
|
+
const dowaitUntilAvailable = browser !== 'chromium' // remove after implementation
|
|
28
|
+
|
|
29
|
+
/** @type {import('../lib/dom').WebTransport | undefined} */
|
|
30
|
+
let client
|
|
31
|
+
|
|
32
|
+
const wtOptions = {
|
|
33
|
+
serverCertificateHashes: [
|
|
34
|
+
{
|
|
35
|
+
algorithm: 'sha-256',
|
|
36
|
+
value: readCertHash(process.env.CERT_HASH)
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
forceReliable
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (process.env.NO_CERT_HASHES === 'true')
|
|
44
|
+
// @ts-ignore
|
|
45
|
+
delete wtOptions.serverCertificateHashes
|
|
46
|
+
|
|
47
|
+
// @ts-ignore
|
|
48
|
+
afterEach(async () => {
|
|
49
|
+
if (client != null) {
|
|
50
|
+
client.close()
|
|
51
|
+
client = undefined
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
if (dowaitUntilAvailable) {
|
|
56
|
+
it('should detect stream limit bidi outgoing with waitUntilAvailable = true', async () => {
|
|
57
|
+
client = new WebTransport(
|
|
58
|
+
`${process.env.SERVER_URL}/streamlimits_getbidis_wua`,
|
|
59
|
+
{ ...wtOptions }
|
|
60
|
+
)
|
|
61
|
+
await client.ready
|
|
62
|
+
const bidistreams = []
|
|
63
|
+
let numbidi = 0
|
|
64
|
+
for (let i = 0; i < 150; i++) {
|
|
65
|
+
const curstream = client.createBidirectionalStream({
|
|
66
|
+
waitUntilAvailable: true
|
|
67
|
+
})
|
|
68
|
+
bidistreams.push(curstream)
|
|
69
|
+
curstream
|
|
70
|
+
.then(() => {
|
|
71
|
+
numbidi++
|
|
72
|
+
})
|
|
73
|
+
.catch(() => {})
|
|
74
|
+
}
|
|
75
|
+
await client.createUnidirectionalStream({
|
|
76
|
+
waitUntilAvailable: true
|
|
77
|
+
})
|
|
78
|
+
expect(numbidi).to.equal(100 - adjustlimit)
|
|
79
|
+
await client.createUnidirectionalStream({
|
|
80
|
+
waitUntilAvailable: true
|
|
81
|
+
})
|
|
82
|
+
for (let i = 0; i < 50 + adjustlimit; i++) {
|
|
83
|
+
const curstream = await bidistreams.shift()
|
|
84
|
+
await curstream.readable.cancel()
|
|
85
|
+
await curstream.writable.close()
|
|
86
|
+
}
|
|
87
|
+
await Promise.allSettled(bidistreams)
|
|
88
|
+
await client.createUnidirectionalStream({
|
|
89
|
+
waitUntilAvailable: true
|
|
90
|
+
})
|
|
91
|
+
expect(numbidi).to.equal(150)
|
|
92
|
+
|
|
93
|
+
const result = await client.closed
|
|
94
|
+
expect(result).to.have.property('closeCode', 0)
|
|
95
|
+
expect(result).to.have.property('reason', '')
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
it('should detect stream limit bidi outgoing', async () => {
|
|
100
|
+
client = new WebTransport(
|
|
101
|
+
`${process.env.SERVER_URL}/streamlimits_getbidis`,
|
|
102
|
+
{ ...wtOptions }
|
|
103
|
+
)
|
|
104
|
+
await client.ready
|
|
105
|
+
const bidistreams = []
|
|
106
|
+
let numbidi = 0
|
|
107
|
+
let numfailed = 0
|
|
108
|
+
for (let i = 0; i < 150; i++) {
|
|
109
|
+
const curstream = client.createBidirectionalStream()
|
|
110
|
+
bidistreams.push(curstream)
|
|
111
|
+
curstream
|
|
112
|
+
.then(() => {
|
|
113
|
+
numbidi++
|
|
114
|
+
})
|
|
115
|
+
.catch(() => {
|
|
116
|
+
numfailed++
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
await Promise.allSettled(bidistreams)
|
|
120
|
+
expect(numbidi).to.equal(100 - adjustlimit)
|
|
121
|
+
expect(numfailed).to.equal(50 + adjustlimit)
|
|
122
|
+
numfailed = 0
|
|
123
|
+
for (let i = 0; i < 50 + adjustlimit; i++) {
|
|
124
|
+
const curstream = await bidistreams.shift()
|
|
125
|
+
await curstream.readable.cancel()
|
|
126
|
+
await curstream.writable.close()
|
|
127
|
+
}
|
|
128
|
+
// as close is not a save measure, that the limit is updated
|
|
129
|
+
// actually no save measure exist, waiting for a typical rtt could be a way
|
|
130
|
+
// to ensure that the update of maxstreams arrives
|
|
131
|
+
await new Promise((resolve) => setTimeout(resolve, 200))
|
|
132
|
+
|
|
133
|
+
for (let i = 0; i < 50 + adjustlimit; i++) {
|
|
134
|
+
const curstream = client.createBidirectionalStream()
|
|
135
|
+
bidistreams.push(curstream)
|
|
136
|
+
curstream
|
|
137
|
+
.then(() => {
|
|
138
|
+
numbidi++
|
|
139
|
+
})
|
|
140
|
+
.catch(() => {
|
|
141
|
+
numfailed++
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
await Promise.allSettled(bidistreams)
|
|
145
|
+
expect(numbidi).to.equal(150)
|
|
146
|
+
expect(numfailed).to.equal(0)
|
|
147
|
+
|
|
148
|
+
const result = await client.closed
|
|
149
|
+
expect(result).to.have.property('closeCode', 0)
|
|
150
|
+
expect(result).to.have.property('reason', '')
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
if (dowaitUntilAvailable) {
|
|
154
|
+
it('should detect stream limit unidi outgoing with waitUntilAvailable = true', async () => {
|
|
155
|
+
client = new WebTransport(
|
|
156
|
+
`${process.env.SERVER_URL}/streamlimits_getunidis_wua`,
|
|
157
|
+
{ ...wtOptions }
|
|
158
|
+
)
|
|
159
|
+
await client.ready
|
|
160
|
+
const unidistreams = []
|
|
161
|
+
let numunidi = 0
|
|
162
|
+
for (let i = 0; i < 150; i++) {
|
|
163
|
+
const curstream = client.createUnidirectionalStream({
|
|
164
|
+
waitUntilAvailable: true
|
|
165
|
+
})
|
|
166
|
+
unidistreams.push(curstream)
|
|
167
|
+
curstream
|
|
168
|
+
.then(() => {
|
|
169
|
+
numunidi++
|
|
170
|
+
})
|
|
171
|
+
.catch(() => {})
|
|
172
|
+
}
|
|
173
|
+
await client.createBidirectionalStream({
|
|
174
|
+
waitUntilAvailable: true
|
|
175
|
+
})
|
|
176
|
+
expect(numunidi).to.equal(100)
|
|
177
|
+
await client.createBidirectionalStream({
|
|
178
|
+
waitUntilAvailable: true
|
|
179
|
+
})
|
|
180
|
+
for (let i = 0; i < 50 + adjustlimit; i++) {
|
|
181
|
+
const curstream = await unidistreams.shift()
|
|
182
|
+
await curstream.close()
|
|
183
|
+
}
|
|
184
|
+
await Promise.allSettled(unidistreams)
|
|
185
|
+
await client.createBidirectionalStream({
|
|
186
|
+
waitUntilAvailable: true
|
|
187
|
+
})
|
|
188
|
+
expect(numunidi).to.equal(150)
|
|
189
|
+
|
|
190
|
+
const result = await client.closed
|
|
191
|
+
expect(result).to.have.property('closeCode', 0)
|
|
192
|
+
expect(result).to.have.property('reason', '')
|
|
193
|
+
})
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
it('should detect stream limit unidi outgoing', async () => {
|
|
197
|
+
client = new WebTransport(
|
|
198
|
+
`${process.env.SERVER_URL}/streamlimits_getunidis`,
|
|
199
|
+
{ ...wtOptions }
|
|
200
|
+
)
|
|
201
|
+
await client.ready
|
|
202
|
+
const unidistreams = []
|
|
203
|
+
let numunidi = 0
|
|
204
|
+
let numfailed = 0
|
|
205
|
+
for (let i = 0; i < 150; i++) {
|
|
206
|
+
const curstream = client.createUnidirectionalStream()
|
|
207
|
+
unidistreams.push(curstream)
|
|
208
|
+
curstream
|
|
209
|
+
.then(() => {
|
|
210
|
+
numunidi++
|
|
211
|
+
})
|
|
212
|
+
.catch(() => {
|
|
213
|
+
numfailed++
|
|
214
|
+
})
|
|
215
|
+
}
|
|
216
|
+
await Promise.allSettled(unidistreams)
|
|
217
|
+
expect(numunidi).to.equal(100)
|
|
218
|
+
expect(numfailed).to.equal(50)
|
|
219
|
+
numfailed = 0
|
|
220
|
+
for (let i = 0; i < 50 + adjustlimit; i++) {
|
|
221
|
+
const curstream = await unidistreams.shift()
|
|
222
|
+
await curstream.close()
|
|
223
|
+
}
|
|
224
|
+
// as close is not a save measure, that the limit is updated
|
|
225
|
+
// actually no save measure exist, waiting for a typical rtt could be a way
|
|
226
|
+
// to ensure that the update of maxstreams arrives
|
|
227
|
+
await new Promise((resolve) => setTimeout(resolve, 200))
|
|
228
|
+
for (let i = 0; i < 50; i++) {
|
|
229
|
+
const curstream = client.createUnidirectionalStream()
|
|
230
|
+
unidistreams.push(curstream)
|
|
231
|
+
curstream
|
|
232
|
+
.then(() => {
|
|
233
|
+
numunidi++
|
|
234
|
+
})
|
|
235
|
+
.catch(() => {
|
|
236
|
+
numfailed++
|
|
237
|
+
})
|
|
238
|
+
}
|
|
239
|
+
await Promise.allSettled(unidistreams)
|
|
240
|
+
expect(numunidi).to.equal(150)
|
|
241
|
+
expect(numfailed).to.equal(0)
|
|
242
|
+
|
|
243
|
+
const result = await client.closed
|
|
244
|
+
expect(result).to.have.property('closeCode', 0)
|
|
245
|
+
expect(result).to.have.property('reason', '')
|
|
246
|
+
})
|
|
247
|
+
})
|