@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.
Files changed (158) hide show
  1. package/dist/lib/client.d.ts.map +1 -0
  2. package/dist/{main/lib → lib}/dom.d.ts +10 -2
  3. package/dist/lib/dom.d.ts.map +1 -0
  4. package/dist/lib/error.d.ts.map +1 -0
  5. package/dist/lib/features.d.ts +2 -0
  6. package/dist/lib/features.d.ts.map +1 -0
  7. package/dist/{main/lib → lib}/http2/browser/browser.d.ts +2 -0
  8. package/dist/lib/http2/browser/browser.d.ts.map +1 -0
  9. package/dist/lib/http2/browser/browserparser.d.ts.map +1 -0
  10. package/dist/{main/lib → lib}/http2/flowcontroller.d.ts +1 -1
  11. package/dist/lib/http2/flowcontroller.d.ts.map +1 -0
  12. package/dist/{main/lib → lib}/http2/node/capsuleparser.d.ts +1 -1
  13. package/dist/lib/http2/node/capsuleparser.d.ts.map +1 -0
  14. package/dist/{main/lib → lib}/http2/node/client.d.ts +2 -0
  15. package/dist/lib/http2/node/client.d.ts.map +1 -0
  16. package/dist/{main/test → lib/http2/node}/index.d.ts.map +1 -1
  17. package/dist/{main/lib → lib}/http2/node/server.d.ts +3 -0
  18. package/dist/lib/http2/node/server.d.ts.map +1 -0
  19. package/dist/{main/lib → lib}/http2/node/websocketparser.d.ts +4 -2
  20. package/dist/lib/http2/node/websocketparser.d.ts.map +1 -0
  21. package/dist/{main/lib → lib}/http2/parserbase.d.ts +26 -9
  22. package/dist/lib/http2/parserbase.d.ts.map +1 -0
  23. package/dist/lib/http2/parserbasehttp2.d.ts.map +1 -0
  24. package/dist/{main/lib → lib}/http2/session.d.ts +43 -6
  25. package/dist/lib/http2/session.d.ts.map +1 -0
  26. package/dist/{main/lib → lib}/http2/stream.d.ts +29 -7
  27. package/dist/lib/http2/stream.d.ts.map +1 -0
  28. package/dist/lib/http2/streamidmanager.d.ts +72 -0
  29. package/dist/lib/http2/streamidmanager.d.ts.map +1 -0
  30. package/dist/lib/http2/websocketcommon.d.ts.map +1 -0
  31. package/dist/lib/index.browser.d.ts.map +1 -0
  32. package/dist/lib/index.node.d.ts.map +1 -0
  33. package/dist/lib/server.d.ts.map +1 -0
  34. package/dist/{main/lib → lib}/session.d.ts +11 -4
  35. package/dist/lib/session.d.ts.map +1 -0
  36. package/dist/lib/stream.d.ts.map +1 -0
  37. package/dist/{main/lib → lib}/types.d.ts +26 -4
  38. package/dist/lib/types.d.ts.map +1 -0
  39. package/dist/lib/utils.d.ts.map +1 -0
  40. package/dist/lib/webstreams.browser.d.ts.map +1 -0
  41. package/dist/lib/webstreams.d.ts.map +1 -0
  42. package/dist/{main/lib → lib}/webtransport.browser.d.ts +12 -2
  43. package/dist/lib/webtransport.browser.d.ts.map +1 -0
  44. package/dist/lib/webtransport.node.d.ts.map +1 -0
  45. package/dist/{main/lib → lib}/webtransportbase.d.ts +14 -2
  46. package/dist/lib/webtransportbase.d.ts.map +1 -0
  47. package/lib/dom.ts +12 -2
  48. package/lib/features.js +16 -0
  49. package/lib/http2/browser/browser.js +12 -3
  50. package/lib/http2/browser/browserparser.js +36 -36
  51. package/lib/http2/flowcontroller.js +2 -2
  52. package/lib/http2/node/capsuleparser.js +58 -51
  53. package/lib/http2/node/client.js +12 -3
  54. package/lib/http2/node/server.js +53 -16
  55. package/lib/http2/node/websocketparser.js +69 -59
  56. package/lib/http2/parserbase.js +87 -12
  57. package/lib/http2/session.js +109 -34
  58. package/lib/http2/stream.js +65 -10
  59. package/lib/http2/streamidmanager.js +316 -0
  60. package/lib/session.js +47 -15
  61. package/lib/stream.js +46 -39
  62. package/lib/types.ts +20 -4
  63. package/lib/webtransport.browser.js +14 -4
  64. package/lib/webtransportbase.js +14 -4
  65. package/package.json +5 -2
  66. package/readme.md +4 -3
  67. package/test/fixtures/certificate.js +1 -2
  68. package/test/fixtures/server.js +112 -7
  69. package/test/fixtures/webtransport.browser.js +1 -1
  70. package/test/index.js +1 -1
  71. package/test/stream-limits.spec.js +247 -0
  72. package/tsconfig.json +2 -7
  73. package/dist/main/lib/client.d.ts.map +0 -1
  74. package/dist/main/lib/dom.d.ts.map +0 -1
  75. package/dist/main/lib/error.d.ts.map +0 -1
  76. package/dist/main/lib/http2/browser/browser.d.ts.map +0 -1
  77. package/dist/main/lib/http2/browser/browserparser.d.ts.map +0 -1
  78. package/dist/main/lib/http2/flowcontroller.d.ts.map +0 -1
  79. package/dist/main/lib/http2/node/capsuleparser.d.ts.map +0 -1
  80. package/dist/main/lib/http2/node/client.d.ts.map +0 -1
  81. package/dist/main/lib/http2/node/index.d.ts.map +0 -1
  82. package/dist/main/lib/http2/node/server.d.ts.map +0 -1
  83. package/dist/main/lib/http2/node/websocketparser.d.ts.map +0 -1
  84. package/dist/main/lib/http2/parserbase.d.ts.map +0 -1
  85. package/dist/main/lib/http2/parserbasehttp2.d.ts.map +0 -1
  86. package/dist/main/lib/http2/session.d.ts.map +0 -1
  87. package/dist/main/lib/http2/stream.d.ts.map +0 -1
  88. package/dist/main/lib/http2/websocketcommon.d.ts.map +0 -1
  89. package/dist/main/lib/index.browser.d.ts.map +0 -1
  90. package/dist/main/lib/index.node.d.ts.map +0 -1
  91. package/dist/main/lib/server.d.ts.map +0 -1
  92. package/dist/main/lib/session.d.ts.map +0 -1
  93. package/dist/main/lib/stream.d.ts.map +0 -1
  94. package/dist/main/lib/types.d.ts.map +0 -1
  95. package/dist/main/lib/utils.d.ts.map +0 -1
  96. package/dist/main/lib/webstreams.browser.d.ts.map +0 -1
  97. package/dist/main/lib/webstreams.d.ts.map +0 -1
  98. package/dist/main/lib/webtransport.browser.d.ts.map +0 -1
  99. package/dist/main/lib/webtransport.node.d.ts.map +0 -1
  100. package/dist/main/lib/webtransportbase.d.ts.map +0 -1
  101. package/dist/main/test/bidirectional-streams.spec.d.ts +0 -5
  102. package/dist/main/test/bidirectional-streams.spec.d.ts.map +0 -1
  103. package/dist/main/test/datagrams.spec.d.ts +0 -5
  104. package/dist/main/test/datagrams.spec.d.ts.map +0 -1
  105. package/dist/main/test/fixtures/certificate.d.ts +0 -21
  106. package/dist/main/test/fixtures/certificate.d.ts.map +0 -1
  107. package/dist/main/test/fixtures/chai.d.ts +0 -2
  108. package/dist/main/test/fixtures/chai.d.ts.map +0 -1
  109. package/dist/main/test/fixtures/known-bytes.d.ts +0 -8
  110. package/dist/main/test/fixtures/known-bytes.d.ts.map +0 -1
  111. package/dist/main/test/fixtures/p-timeout.d.ts +0 -8
  112. package/dist/main/test/fixtures/p-timeout.d.ts.map +0 -1
  113. package/dist/main/test/fixtures/read-cert-hash.d.ts +0 -6
  114. package/dist/main/test/fixtures/read-cert-hash.d.ts.map +0 -1
  115. package/dist/main/test/fixtures/read-stream.d.ts +0 -18
  116. package/dist/main/test/fixtures/read-stream.d.ts.map +0 -1
  117. package/dist/main/test/fixtures/reader-value.d.ts +0 -21
  118. package/dist/main/test/fixtures/reader-value.d.ts.map +0 -1
  119. package/dist/main/test/fixtures/server.d.ts +0 -5
  120. package/dist/main/test/fixtures/server.d.ts.map +0 -1
  121. package/dist/main/test/fixtures/webtransport.browser.d.ts +0 -4
  122. package/dist/main/test/fixtures/webtransport.browser.d.ts.map +0 -1
  123. package/dist/main/test/fixtures/webtransport.d.ts +0 -3
  124. package/dist/main/test/fixtures/webtransport.d.ts.map +0 -1
  125. package/dist/main/test/fixtures/write-stream.d.ts +0 -10
  126. package/dist/main/test/fixtures/write-stream.d.ts.map +0 -1
  127. package/dist/main/test/index.d.ts +0 -2
  128. package/dist/main/test/session.spec.d.ts +0 -5
  129. package/dist/main/test/session.spec.d.ts.map +0 -1
  130. package/dist/main/test/unidirectional-streams.spec.d.ts +0 -2
  131. package/dist/main/test/unidirectional-streams.spec.d.ts.map +0 -1
  132. package/dist/main/tsconfig.tsbuildinfo +0 -1
  133. package/dist/transports/http3-quiche/lib/clientsocket.d.ts +0 -19
  134. package/dist/transports/http3-quiche/lib/clientsocket.d.ts.map +0 -1
  135. package/dist/transports/http3-quiche/lib/index.d.ts +0 -11
  136. package/dist/transports/http3-quiche/lib/index.d.ts.map +0 -1
  137. package/dist/transports/http3-quiche/lib/serversocket.d.ts +0 -12
  138. package/dist/transports/http3-quiche/lib/serversocket.d.ts.map +0 -1
  139. package/dist/transports/http3-quiche/lib/socket.d.ts +0 -19
  140. package/dist/transports/http3-quiche/lib/socket.d.ts.map +0 -1
  141. package/dist/transports/http3-quiche/lib/types.d.ts +0 -21
  142. package/dist/transports/http3-quiche/lib/types.d.ts.map +0 -1
  143. package/dist/transports/http3-quiche/lib/utils.d.ts +0 -6
  144. package/dist/transports/http3-quiche/lib/utils.d.ts.map +0 -1
  145. /package/dist/{main/lib → lib}/client.d.ts +0 -0
  146. /package/dist/{main/lib → lib}/error.d.ts +0 -0
  147. /package/dist/{main/lib → lib}/http2/browser/browserparser.d.ts +0 -0
  148. /package/dist/{main/lib → lib}/http2/node/index.d.ts +0 -0
  149. /package/dist/{main/lib → lib}/http2/parserbasehttp2.d.ts +0 -0
  150. /package/dist/{main/lib → lib}/http2/websocketcommon.d.ts +0 -0
  151. /package/dist/{main/lib → lib}/index.browser.d.ts +0 -0
  152. /package/dist/{main/lib → lib}/index.node.d.ts +0 -0
  153. /package/dist/{main/lib → lib}/server.d.ts +0 -0
  154. /package/dist/{main/lib → lib}/stream.d.ts +0 -0
  155. /package/dist/{main/lib → lib}/utils.d.ts +0 -0
  156. /package/dist/{main/lib → lib}/webstreams.browser.d.ts +0 -0
  157. /package/dist/{main/lib → lib}/webstreams.d.ts +0 -0
  158. /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
- *@returns {Promise<WebTransportSendStream>}
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
- start: (
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: () => void
19
- orderBidiStream: () => void
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
- async createBidirectionalStream() {
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
- async createUnidirectionalStream() {
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
  }
@@ -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
- createBidirectionalStream() {
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
- createUnidirectionalStream() {
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.6",
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:firefox:http2:ponyfill",
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 (unreleased) version of node.js.** This limitation does not apply to the polyfill/ponyfill and the websocket protocol.
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: true
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(
@@ -39,7 +39,7 @@ export async function createServer() {
39
39
  } else {
40
40
  server = new Http3Server({
41
41
  /* port: 8080,
42
- host: '0.0.0.0', */
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 console.error('No IPC channel')
285
- /* console.log({
286
- address: `https://${address.host}:${address.port}`,
287
- certificate: certificate.fingerprint
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')