@fails-components/webtransport 1.1.3 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/dom.d.ts +27 -10
- package/dist/lib/dom.d.ts.map +1 -1
- package/dist/lib/http2/browser/browser.d.ts +5 -2
- package/dist/lib/http2/browser/browser.d.ts.map +1 -1
- package/dist/lib/http2/browser/browserparser.d.ts.map +1 -1
- package/dist/lib/http2/node/capsuleparser.d.ts.map +1 -1
- package/dist/lib/http2/node/client.d.ts +3 -2
- package/dist/lib/http2/node/client.d.ts.map +1 -1
- package/dist/lib/http2/node/server.d.ts +10 -5
- package/dist/lib/http2/node/server.d.ts.map +1 -1
- package/dist/lib/http2/node/websocketparser.d.ts.map +1 -1
- package/dist/lib/http2/parserbase.d.ts +33 -1
- package/dist/lib/http2/parserbase.d.ts.map +1 -1
- package/dist/lib/http2/priorityscheduler.d.ts +167 -0
- package/dist/lib/http2/priorityscheduler.d.ts.map +1 -0
- package/dist/lib/http2/session.d.ts +25 -16
- package/dist/lib/http2/session.d.ts.map +1 -1
- package/dist/lib/http2/stream.d.ts +10 -0
- package/dist/lib/http2/stream.d.ts.map +1 -1
- package/dist/lib/http2/websocketcommon.d.ts.map +1 -1
- package/dist/lib/server.d.ts.map +1 -1
- package/dist/lib/session.d.ts +31 -17
- package/dist/lib/session.d.ts.map +1 -1
- package/dist/lib/stream.d.ts +13 -0
- package/dist/lib/stream.d.ts.map +1 -1
- package/dist/lib/types.d.ts +18 -15
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/webtransport.browser.d.ts +3 -2
- package/dist/lib/webtransport.browser.d.ts.map +1 -1
- package/dist/lib/webtransportbase.d.ts +1 -0
- package/dist/lib/webtransportbase.d.ts.map +1 -1
- package/eslint.config.js +20 -22
- package/lib/dom.ts +31 -13
- package/lib/http2/browser/browser.js +28 -13
- package/lib/http2/browser/browserparser.js +4 -1
- package/lib/http2/node/capsuleparser.js +4 -1
- package/lib/http2/node/client.js +38 -27
- package/lib/http2/node/server.js +56 -19
- package/lib/http2/node/websocketparser.js +5 -2
- package/lib/http2/parserbase.js +76 -7
- package/lib/http2/priorityscheduler.js +654 -0
- package/lib/http2/session.js +69 -20
- package/lib/http2/stream.js +60 -10
- package/lib/http2/websocketcommon.js +1 -1
- package/lib/server.js +0 -1
- package/lib/session.js +128 -64
- package/lib/stream.js +50 -8
- package/lib/types.ts +15 -8
- package/lib/webtransport.browser.js +77 -18
- package/lib/webtransportbase.js +7 -0
- package/old_test/echoserver.js +1 -1
- package/old_test/test.js +1 -1
- package/old_test/testsuite.js +6 -2
- package/package.json +7 -28
- package/readme.md +5 -3
- package/test/bidirectional-streams.spec.js +0 -150
- package/test/datagrams.spec.js +0 -104
- package/test/fixtures/certificate.js +0 -456
- package/test/fixtures/chai.js +0 -8
- package/test/fixtures/known-bytes.js +0 -44
- package/test/fixtures/p-timeout.js +0 -33
- package/test/fixtures/quiche.browser.js +0 -2
- package/test/fixtures/quiche.js +0 -1
- package/test/fixtures/read-cert-hash.js +0 -7
- package/test/fixtures/read-stream.js +0 -57
- package/test/fixtures/reader-value.js +0 -51
- package/test/fixtures/server.js +0 -467
- package/test/fixtures/webtransport.browser.js +0 -19
- package/test/fixtures/webtransport.js +0 -3
- package/test/fixtures/write-stream.js +0 -24
- package/test/index.js +0 -124
- package/test/pw-no-https-errors.json +0 -5
- package/test/session.spec.js +0 -199
- package/test/stream-limits.spec.js +0 -259
- package/test/unidirectional-streams.spec.js +0 -133
package/lib/stream.js
CHANGED
|
@@ -20,6 +20,8 @@ const log = logger(`webtransport:http3wtstream(${pid})`)
|
|
|
20
20
|
* @typedef {import('./dom').WebTransportReceiveStream} WebTransportReceiveStream
|
|
21
21
|
* @typedef {import('./dom').WebTransportSendStream} WebTransportSendStream
|
|
22
22
|
*
|
|
23
|
+
* @typedef {import('./dom').WebTransportSendGroup} WebTransportSendGroup
|
|
24
|
+
*
|
|
23
25
|
* @typedef {import('./session').HttpWTSession} HttpWTSession
|
|
24
26
|
*
|
|
25
27
|
* @typedef {import('stream/web').WritableStreamDefaultController} WritableStreamDefaultController
|
|
@@ -33,6 +35,8 @@ export class HttpWTStream {
|
|
|
33
35
|
* @param {object} args.transport
|
|
34
36
|
* @param {boolean} args.bidirectional
|
|
35
37
|
* @param {boolean} args.incoming
|
|
38
|
+
* @param {WebTransportSendGroup|undefined} args.sendGroup
|
|
39
|
+
* @param {bigint} args.sendOrder
|
|
36
40
|
*/
|
|
37
41
|
constructor(args) {
|
|
38
42
|
this.objint = args.object
|
|
@@ -43,6 +47,9 @@ export class HttpWTStream {
|
|
|
43
47
|
this.incoming = args.incoming
|
|
44
48
|
this.closed = false
|
|
45
49
|
|
|
50
|
+
this._sendGroup = args.sendGroup
|
|
51
|
+
this._sendOrder = args.sendOrder
|
|
52
|
+
|
|
46
53
|
if (this.objint.sendInitialParameters) {
|
|
47
54
|
this.objint.sendInitialParameters()
|
|
48
55
|
}
|
|
@@ -140,18 +147,15 @@ export class HttpWTStream {
|
|
|
140
147
|
wchunk = new Uint8Array(wchunk)
|
|
141
148
|
}
|
|
142
149
|
if (wchunk instanceof Uint8Array) {
|
|
150
|
+
if (wchunk.byteLength === 0) {
|
|
151
|
+
// or should we throw an error ?, Ask the W3C people!
|
|
152
|
+
return
|
|
153
|
+
}
|
|
143
154
|
// eslint-disable-next-line no-unused-vars
|
|
144
155
|
this.pendingoperation = new Promise((resolve, reject) => {
|
|
145
156
|
this.pendingres = resolve
|
|
146
157
|
})
|
|
147
|
-
this.
|
|
148
|
-
.waitForDatagramsSend()
|
|
149
|
-
.finally(() => {
|
|
150
|
-
this.objint.writeChunk(wchunk)
|
|
151
|
-
})
|
|
152
|
-
.catch((/** @type {any} */ err) => {
|
|
153
|
-
log.error(err)
|
|
154
|
-
})
|
|
158
|
+
this.objint.writeChunk(wchunk)
|
|
155
159
|
return this.pendingoperation
|
|
156
160
|
} else {
|
|
157
161
|
log.trace('chunk info:', chunk)
|
|
@@ -203,6 +207,36 @@ export class HttpWTStream {
|
|
|
203
207
|
bytesAcknowledged: 0n
|
|
204
208
|
})
|
|
205
209
|
}
|
|
210
|
+
Object.defineProperties(this.writable, {
|
|
211
|
+
sendOrder: {
|
|
212
|
+
get: () => {
|
|
213
|
+
return this._sendOrder
|
|
214
|
+
},
|
|
215
|
+
/**
|
|
216
|
+
* @param {bigint} value
|
|
217
|
+
*/
|
|
218
|
+
set: (value) => {
|
|
219
|
+
if (value !== this._sendOrder) {
|
|
220
|
+
this._sendOrder = args.sendOrder
|
|
221
|
+
this.updateSendOrderAndGroup()
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
sendGroup: {
|
|
226
|
+
get: () => {
|
|
227
|
+
return this._sendGroup
|
|
228
|
+
},
|
|
229
|
+
/**
|
|
230
|
+
* @param {WebTransportSendGroup} value
|
|
231
|
+
*/
|
|
232
|
+
set: (value) => {
|
|
233
|
+
if (value !== this._sendGroup) {
|
|
234
|
+
this._sendGroup = value
|
|
235
|
+
this.updateSendOrderAndGroup()
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
})
|
|
206
240
|
// @ts-ignore
|
|
207
241
|
this.parentobj.addSendStream(this.writable, this.writableController)
|
|
208
242
|
}
|
|
@@ -278,6 +312,14 @@ export class HttpWTStream {
|
|
|
278
312
|
return retObj
|
|
279
313
|
}
|
|
280
314
|
|
|
315
|
+
updateSendOrderAndGroup() {
|
|
316
|
+
this.objint.updateSendOrderAndGroup({
|
|
317
|
+
sendOrder: this._sendOrder,
|
|
318
|
+
// @ts-ignore
|
|
319
|
+
sendGroupId: this._sendGroup._sendGroupId
|
|
320
|
+
})
|
|
321
|
+
}
|
|
322
|
+
|
|
281
323
|
/**
|
|
282
324
|
* @param {import('./types').StreamRecvSignalEvent} args
|
|
283
325
|
* @returns {void}
|
package/lib/types.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type {
|
|
|
2
2
|
WebTransportSession,
|
|
3
3
|
WebTransportHash,
|
|
4
4
|
WebTransportOptions,
|
|
5
|
-
|
|
5
|
+
WebTransportSendStreamOptions
|
|
6
6
|
} from './dom'
|
|
7
7
|
import type { IncomingHttpHeaders, Http2Stream, ServerHttp2Stream } from 'http2'
|
|
8
8
|
import { ParserBase } from './http2/parserbase'
|
|
@@ -15,12 +15,13 @@ import { HttpClient } from './client'
|
|
|
15
15
|
export interface NativeHttpWTSession {
|
|
16
16
|
jsobj: WebTransportSessionEventHandler
|
|
17
17
|
sendInitialParameters?: () => void
|
|
18
|
-
writeDatagram: (chunk: Uint8Array) =>
|
|
19
|
-
orderUnidiStream: (opts:
|
|
20
|
-
orderBidiStream: (opts:
|
|
18
|
+
writeDatagram: (chunk: Uint8Array) => { code: 'success' | 'blocked' | 'internalError' | 'tooBig', message?: string}
|
|
19
|
+
orderUnidiStream: (opts: WebTransportSendStreamOptions) => boolean
|
|
20
|
+
orderBidiStream: (opts: WebTransportSendStreamOptions) => boolean
|
|
21
21
|
orderSessionStats: () => void
|
|
22
22
|
orderDatagramStats: () => void
|
|
23
23
|
notifySessionDraining: () => void
|
|
24
|
+
getMaxDatagramSize: () => number
|
|
24
25
|
close: (arg: { code: number; reason: string }) => void
|
|
25
26
|
}
|
|
26
27
|
|
|
@@ -38,6 +39,10 @@ export interface NativeHttpWTStream {
|
|
|
38
39
|
resetStream: (code: number) => void
|
|
39
40
|
writeChunk: (buf: Uint8Array) => void
|
|
40
41
|
streamFinal: () => void
|
|
42
|
+
updateSendOrderAndGroup: (args :{
|
|
43
|
+
sendOrder: bigint,
|
|
44
|
+
sendGroupId: bigint
|
|
45
|
+
}) => void
|
|
41
46
|
}
|
|
42
47
|
|
|
43
48
|
export interface NativeServerOptions {
|
|
@@ -79,6 +84,7 @@ export interface NativeClientOptions {
|
|
|
79
84
|
initialSessionFlowControlWindow?: number
|
|
80
85
|
sessionShouldAutoTuneReceiveWindow?: boolean
|
|
81
86
|
sessionFlowControlWindowSizeLimit?: number
|
|
87
|
+
protocols?: string[]
|
|
82
88
|
}
|
|
83
89
|
|
|
84
90
|
export interface FlowControlable {
|
|
@@ -110,7 +116,8 @@ export interface NativeFinishSessionRequest {
|
|
|
110
116
|
protocol: 'capsule' | 'websocket' | 'websocketoverhttp1' | 'http3'
|
|
111
117
|
head?: Buffer
|
|
112
118
|
userData?: object
|
|
113
|
-
transportPrivate?: object
|
|
119
|
+
transportPrivate?: object,
|
|
120
|
+
selectedProtocol?: string
|
|
114
121
|
}
|
|
115
122
|
|
|
116
123
|
export type Purpose =
|
|
@@ -150,6 +157,7 @@ export interface WebTransportStreamEventHandler {
|
|
|
150
157
|
|
|
151
158
|
export interface SessionReadyEvent {
|
|
152
159
|
object: NativeHttpWTSession
|
|
160
|
+
protocol?: string
|
|
153
161
|
}
|
|
154
162
|
|
|
155
163
|
export interface SessionCloseEvent {
|
|
@@ -179,21 +187,20 @@ export interface DatagramReceivedEvent {
|
|
|
179
187
|
datagram: Uint8Array
|
|
180
188
|
}
|
|
181
189
|
|
|
182
|
-
export interface DatagramSendEvent {}
|
|
183
|
-
|
|
184
190
|
export interface GoawayReceivedEvent {}
|
|
185
191
|
|
|
186
192
|
export interface NewStreamEvent {
|
|
187
193
|
stream: NativeHttpWTStream
|
|
188
194
|
bidirectional: boolean
|
|
189
195
|
incoming: boolean
|
|
196
|
+
sendGroupId?: bigint;
|
|
197
|
+
sendOrder: bigint;
|
|
190
198
|
}
|
|
191
199
|
|
|
192
200
|
export interface WebTransportSessionEventHandler {
|
|
193
201
|
onReady: (evt: SessionReadyEvent) => void
|
|
194
202
|
onClose: (evt: SessionCloseEvent) => void
|
|
195
203
|
onDatagramReceived: (evt: DatagramReceivedEvent) => void
|
|
196
|
-
onDatagramSend: (evt: DatagramSendEvent) => void
|
|
197
204
|
onGoAwayReceived: (evt: GoawayReceivedEvent) => void
|
|
198
205
|
onSessionStats: (evt: SessionStatsEvent) => void
|
|
199
206
|
onDatagramStats: (evt: DatagramStatsEvent) => void
|
|
@@ -3,6 +3,7 @@ import { HttpWTSession } from './session.js'
|
|
|
3
3
|
import { HttpClient } from './client.js'
|
|
4
4
|
import { Http2WebTransportBrowser } from './http2/browser/browser.js'
|
|
5
5
|
import { logger } from './utils.js'
|
|
6
|
+
import { WebTransportError } from './error'
|
|
6
7
|
|
|
7
8
|
const log = logger(`webtransport:browser()`)
|
|
8
9
|
|
|
@@ -13,7 +14,7 @@ const log = logger(`webtransport:browser()`)
|
|
|
13
14
|
* @typedef {import('./dom').WebTransportSendStream} WebTransportSendStream
|
|
14
15
|
* @typedef {import('./dom').WebTransportSendStreamOptions} WebTransportSendStreamOptions
|
|
15
16
|
* @typedef {import('./dom').WebTransportReceiveStream} WebTransportReceiveStream
|
|
16
|
-
* @typedef {import('./
|
|
17
|
+
* @typedef {import('./dom').WebTransportSendGroup} WebTransportSendGroup
|
|
17
18
|
*/
|
|
18
19
|
|
|
19
20
|
/**
|
|
@@ -215,7 +216,17 @@ export class WebTransportPolyfill {
|
|
|
215
216
|
}
|
|
216
217
|
/** @type {import('./dom').WebTransportDatagramDuplexStream} */
|
|
217
218
|
// @ts-ignore
|
|
218
|
-
this.datagrams = {
|
|
219
|
+
this.datagrams = {
|
|
220
|
+
// @ts-ignore
|
|
221
|
+
get writable() {
|
|
222
|
+
// @ts-ignore
|
|
223
|
+
if (!this.datagramwritablepolyfilled_) {
|
|
224
|
+
console.warn('datagrams.writable is deprecated')
|
|
225
|
+
}
|
|
226
|
+
// @ts-ignore
|
|
227
|
+
return (this.datagramwritablepolyfilled_ ||= this.createWritable())
|
|
228
|
+
}
|
|
229
|
+
}
|
|
219
230
|
// @ts-ignore
|
|
220
231
|
this.datagrams.readable = new ReadableStream({
|
|
221
232
|
// eslint-disable-next-line no-unused-vars
|
|
@@ -233,23 +244,67 @@ export class WebTransportPolyfill {
|
|
|
233
244
|
}
|
|
234
245
|
})
|
|
235
246
|
// @ts-ignore
|
|
236
|
-
this.datagrams.
|
|
237
|
-
//
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
this.datagramsWriter = this.curtransport.datagrams.writable.getWriter()
|
|
241
|
-
},
|
|
242
|
-
// eslint-disable-next-line no-unused-vars
|
|
243
|
-
write: async (chunk, controller) => {
|
|
244
|
-
await this.datagramsWriter.write(chunk)
|
|
245
|
-
},
|
|
246
|
-
abort: async (reason) => {
|
|
247
|
-
await this.datagramsWriter.abort(reason)
|
|
248
|
-
},
|
|
249
|
-
close: async () => {
|
|
250
|
-
await this.datagramsWriter.close()
|
|
247
|
+
this.datagrams.createWritable = (options) => {
|
|
248
|
+
// @ts-ignore Must not exist for older browser
|
|
249
|
+
if (this.curtransport.datagrams.createWritable) {
|
|
250
|
+
return this.curtransport.datagrams.createWritable(options)
|
|
251
251
|
}
|
|
252
|
-
|
|
252
|
+
// we need to fallback to the old default writable
|
|
253
|
+
// @ts-ignore
|
|
254
|
+
if (!this.curtransport.datagrams.writable) {
|
|
255
|
+
throw new WebTransportError('No way to send out datagrams')
|
|
256
|
+
}
|
|
257
|
+
let sendOrder = options?.sendOrder
|
|
258
|
+
let sendGroup = options?.sendGroup
|
|
259
|
+
const retWritable = new WritableStream({
|
|
260
|
+
// eslint-disable-next-line no-unused-vars
|
|
261
|
+
start: async (controller) => {
|
|
262
|
+
await this.ready
|
|
263
|
+
if (!this.datagramsWriter) {
|
|
264
|
+
this.datagramsWriter =
|
|
265
|
+
// @ts-ignore
|
|
266
|
+
this.curtransport.datagrams.writable.getWriter()
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
// eslint-disable-next-line no-unused-vars
|
|
270
|
+
write: async (chunk, controller) => {
|
|
271
|
+
await this.datagramsWriter.write(chunk)
|
|
272
|
+
},
|
|
273
|
+
abort: async (reason) => {
|
|
274
|
+
await this.datagramsWriter.abort(reason)
|
|
275
|
+
},
|
|
276
|
+
close: async () => {
|
|
277
|
+
await this.datagramsWriter.close()
|
|
278
|
+
}
|
|
279
|
+
})
|
|
280
|
+
Object.defineProperties(retWritable, {
|
|
281
|
+
sendOrder: {
|
|
282
|
+
get: () => {
|
|
283
|
+
return sendOrder
|
|
284
|
+
},
|
|
285
|
+
/**
|
|
286
|
+
* @param {number} value
|
|
287
|
+
*/
|
|
288
|
+
set: (value) => {
|
|
289
|
+
sendOrder = value
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
sendGroup: {
|
|
293
|
+
get: () => {
|
|
294
|
+
return sendGroup
|
|
295
|
+
},
|
|
296
|
+
/**
|
|
297
|
+
* @param {WebTransportSendGroup} value
|
|
298
|
+
*/
|
|
299
|
+
set: (value) => {
|
|
300
|
+
if (value !== sendGroup) {
|
|
301
|
+
sendGroup = value
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
})
|
|
306
|
+
return retWritable
|
|
307
|
+
}
|
|
253
308
|
this.incomingBidirectionalStreams = new ReadableStream({
|
|
254
309
|
// eslint-disable-next-line no-unused-vars
|
|
255
310
|
start: async (controller) => {
|
|
@@ -300,6 +355,10 @@ export class WebTransportPolyfill {
|
|
|
300
355
|
return true
|
|
301
356
|
}
|
|
302
357
|
|
|
358
|
+
get protocol() {
|
|
359
|
+
return this.curtransport?.protocol || undefined
|
|
360
|
+
}
|
|
361
|
+
|
|
303
362
|
getStats() {
|
|
304
363
|
// @ts-ignore
|
|
305
364
|
return this.curtransport.getStats()
|
package/lib/webtransportbase.js
CHANGED
package/old_test/echoserver.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { Http3Server } from '../lib/index.js'
|
|
6
6
|
import { runEchoServer } from './testsuite.js'
|
|
7
7
|
import { existsSync, readFileSync, writeFile } from 'node:fs'
|
|
8
|
-
import { generateWebTransportCertificate } from '
|
|
8
|
+
import { generateWebTransportCertificate } from '../../test/fixtures/certificate.js'
|
|
9
9
|
|
|
10
10
|
let certificate = null
|
|
11
11
|
|
package/old_test/test.js
CHANGED
package/old_test/testsuite.js
CHANGED
|
@@ -70,7 +70,9 @@ export async function unidirectionalEchoTest(session) {
|
|
|
70
70
|
*/
|
|
71
71
|
export async function datagramEchoTest(session) {
|
|
72
72
|
try {
|
|
73
|
-
|
|
73
|
+
const writable =
|
|
74
|
+
session.datagrams.writable || session.datagrams.createWritable()
|
|
75
|
+
session.datagrams.readable.pipeTo(writable)
|
|
74
76
|
} catch (error) {
|
|
75
77
|
console.log('datagram echo exited with', error)
|
|
76
78
|
}
|
|
@@ -287,7 +289,9 @@ export async function echoTestsConnection(transport) {
|
|
|
287
289
|
console.log('TEST 3: finish')
|
|
288
290
|
console.log('TEST 4: start')
|
|
289
291
|
console.log('finally test datagrams')
|
|
290
|
-
const
|
|
292
|
+
const dwritable =
|
|
293
|
+
transport.datagrams.writable || transport.datagrams.createWritable()
|
|
294
|
+
const datawrite = await dwritable.getWriter()
|
|
291
295
|
const data7 = new Uint8Array([83, 84, 85])
|
|
292
296
|
const data8 = new Uint8Array([86, 87, 88])
|
|
293
297
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fails-components/webtransport",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "A component to add webtransport support (server and client) to node.js using libquiche",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -21,21 +21,9 @@
|
|
|
21
21
|
"types": "./dist/lib/index.types.d.ts",
|
|
22
22
|
"scripts": {
|
|
23
23
|
"start": "node test/echoserver.js",
|
|
24
|
-
"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",
|
|
25
|
-
"test:node": "node test/index.js node http3",
|
|
26
|
-
"test:node:http2": "node test/index.js node http2",
|
|
27
|
-
"test:chromium": "node test/index.js chromium http3",
|
|
28
|
-
"test:chromium:http2:polyfill": "node test/index.js chromium http2 polyfill",
|
|
29
|
-
"test:chromium:http2:ponyfill": "node test/index.js chromium http2 ponyfill",
|
|
30
|
-
"test:firefox": "node test/index.js firefox http3",
|
|
31
|
-
"test:firefox:http2:polyfill": "node test/index.js firefox http2 polyfill",
|
|
32
|
-
"test:firefox:http2:ponyfill": "node test/index.js firefox http2 ponyfill",
|
|
33
|
-
"test:webkit": "node test/index.js webkit http3",
|
|
34
|
-
"test:webkit:http2:polyfill": "node test/index.js webkit http2 polyfill",
|
|
35
|
-
"test:webkit:http2:ponyfill": "node test/index.js webkit http2 ponyfill",
|
|
36
24
|
"oldtest": "node old_test/test.js",
|
|
37
25
|
"oldtesthttp2": "node old_test/test.js http2",
|
|
38
|
-
"lint": "eslint lib
|
|
26
|
+
"lint": "eslint lib old_test"
|
|
39
27
|
},
|
|
40
28
|
"repository": {
|
|
41
29
|
"type": "git",
|
|
@@ -63,22 +51,15 @@
|
|
|
63
51
|
"@types/dirty-chai": "^2.0.2",
|
|
64
52
|
"@types/mocha": "^10.0.0",
|
|
65
53
|
"@types/node": "^18.15.3",
|
|
66
|
-
"chai": "^4.3.6",
|
|
67
|
-
"chai-as-promised": "^7.1.1",
|
|
68
|
-
"dirty-chai": "^2.0.1",
|
|
69
54
|
"eslint": "^9.3.0",
|
|
70
55
|
"eslint-config-prettier": "^9.1.0",
|
|
71
|
-
"eslint-
|
|
72
|
-
"eslint-plugin-import": "^2.25.2",
|
|
56
|
+
"eslint-plugin-import": "^2.31.0",
|
|
73
57
|
"eslint-plugin-node": "^11.1.0",
|
|
74
58
|
"eslint-plugin-prettier": "^5.1.3",
|
|
75
|
-
"eslint-plugin-promise": "^
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"node-forge": "^1.3.1",
|
|
80
|
-
"playwright-test": "^12.3.4",
|
|
81
|
-
"prettier": "^3.2.5",
|
|
59
|
+
"eslint-plugin-promise": "^7.2.1",
|
|
60
|
+
"prettier": "^3.5.3",
|
|
61
|
+
"prettier-linter-helpers": "^1.0.0",
|
|
62
|
+
"synckit": "^0.11.4",
|
|
82
63
|
"typescript": "^4.8.4",
|
|
83
64
|
"uint8arrays": "^4.0.2"
|
|
84
65
|
},
|
|
@@ -88,8 +69,6 @@
|
|
|
88
69
|
]
|
|
89
70
|
},
|
|
90
71
|
"browser": {
|
|
91
|
-
"./test/fixtures/webtransport.js": "./test/fixtures/webtransport.browser.js",
|
|
92
|
-
"./test/fixtures/quiche.js": "./test/fixtures/quiche.browser.js",
|
|
93
72
|
"./lib/webstreams.js": "./lib/webstreams.browser.js"
|
|
94
73
|
}
|
|
95
74
|
}
|
package/readme.md
CHANGED
|
@@ -72,8 +72,8 @@ The package `webtransport-transport-http3-quiche` provides prebuild binaries for
|
|
|
72
72
|
Other platforms may be possible via cross-compiling in the GitHub actions, if someone needs this, PRs are welcome.
|
|
73
73
|
|
|
74
74
|
Of course, you can also build the binary on your system.
|
|
75
|
-
If you are running the compiling install as root, you need to use
|
|
76
|
-
Installing the package without prebuild requires a full building environment including clang-9
|
|
75
|
+
If you are running the compiling install as root, you need to use `--unsafe-perm` as a flag.
|
|
76
|
+
Installing the package without prebuild requires a full building environment including `clang-9`, `perl6`, `python`, `golang`, `ninja-build`, and `icu`. See the `Dockerfile` or `Dockerfile.development` for required Debian packages.
|
|
77
77
|
This should work for Windows, Linux and Mac OS X.
|
|
78
78
|
(You may want to check out the building dependencies (especially for Windows) for BoringSSl, zlib, abseil on their respective websites).
|
|
79
79
|
|
|
@@ -109,7 +109,9 @@ Other but more expert options include:
|
|
|
109
109
|
* `certhttp2` and `privKeyhttp2`: For providing a different certificate for the http/2 as the http/2 implementation does not support certificate matching by fingerprints.
|
|
110
110
|
* `initialStreamFlowControlWindow`, `initialSessionFlowControlWindow`, `streamShouldAutoTuneReceiveWindow`, `sessionShouldAutoTuneReceiveWindow`, `streamFlowControlWindowSizeLimit`, `sessionFlowControlWindowSizeLimit`: As expert's option for tweaking the internal flow control.
|
|
111
111
|
|
|
112
|
-
The method `
|
|
112
|
+
The method `setRequestCallback(callback)` sets a callback, that inspects incoming headers and allows to change the incoming path header and also to throw an error if the session should not be opened.
|
|
113
|
+
It is also required for selecting the application level protocol.
|
|
114
|
+
In order to see how it is used, look into `test/fixtures/server.js` for a working example.
|
|
113
115
|
In general, the HTTP header is attached as the `header` property to the WebTransport Session object.
|
|
114
116
|
|
|
115
117
|
The method `updateCert(cert, privKey, http2only)` allows to change the certificate, while the server is running (not supported by all transports).
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
/* eslint-env mocha */
|
|
2
|
-
|
|
3
|
-
import { getReaderValue } from './fixtures/reader-value.js'
|
|
4
|
-
import { expect } from './fixtures/chai.js'
|
|
5
|
-
import { readStream } from './fixtures/read-stream.js'
|
|
6
|
-
import { writeStream } from './fixtures/write-stream.js'
|
|
7
|
-
import { readCertHash } from './fixtures/read-cert-hash.js'
|
|
8
|
-
import WebTransport from './fixtures/webtransport.js'
|
|
9
|
-
import { quicheLoaded } from './fixtures/quiche.js'
|
|
10
|
-
import * as ui8 from 'uint8arrays'
|
|
11
|
-
import {
|
|
12
|
-
KNOWN_BYTES,
|
|
13
|
-
KNOWN_BYTES_LENGTH,
|
|
14
|
-
KNOWN_BYTES_LONG,
|
|
15
|
-
KNOWN_BYTES_LONG_LENGTH
|
|
16
|
-
} from './fixtures/known-bytes.js'
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @template T
|
|
20
|
-
* @typedef {import('../lib/types').Deferred<T>} Deferred<T>
|
|
21
|
-
*/
|
|
22
|
-
describe('bidirectional streams', function () {
|
|
23
|
-
let forceReliable = false
|
|
24
|
-
if (process.env.USE_HTTP2 === 'true') forceReliable = true
|
|
25
|
-
/** @type {import('../lib/dom').WebTransport | undefined} */
|
|
26
|
-
let client
|
|
27
|
-
|
|
28
|
-
const wtOptions = {
|
|
29
|
-
serverCertificateHashes: [
|
|
30
|
-
{
|
|
31
|
-
algorithm: 'sha-256',
|
|
32
|
-
value: readCertHash(process.env.CERT_HASH)
|
|
33
|
-
}
|
|
34
|
-
],
|
|
35
|
-
// @ts-ignore
|
|
36
|
-
forceReliable
|
|
37
|
-
}
|
|
38
|
-
if (process.env.NO_CERT_HASHES === 'true')
|
|
39
|
-
// @ts-ignore
|
|
40
|
-
delete wtOptions.serverCertificateHashes
|
|
41
|
-
|
|
42
|
-
// @ts-ignore
|
|
43
|
-
beforeEach(async () => {
|
|
44
|
-
if (
|
|
45
|
-
process.env.USE_HTTP2 !== 'true' &&
|
|
46
|
-
process.env.USE_PONYFILL !== 'true' &&
|
|
47
|
-
process.env.USE_POLYFILL !== 'true'
|
|
48
|
-
) {
|
|
49
|
-
await quicheLoaded
|
|
50
|
-
}
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
// @ts-ignore
|
|
54
|
-
afterEach(async () => {
|
|
55
|
-
if (client != null) {
|
|
56
|
-
client.close()
|
|
57
|
-
client = undefined
|
|
58
|
-
}
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it('sends and receives data over an outgoing bidirectional stream', async () => {
|
|
62
|
-
// client context - connects to the server, opens a bidi stream, sends some data and reads the response
|
|
63
|
-
client = new WebTransport(
|
|
64
|
-
`${process.env.SERVER_URL}/bidirectional_client_initiated_echo`,
|
|
65
|
-
wtOptions
|
|
66
|
-
)
|
|
67
|
-
await client.ready
|
|
68
|
-
|
|
69
|
-
const stream = await client.createBidirectionalStream()
|
|
70
|
-
await writeStream(stream.writable, KNOWN_BYTES)
|
|
71
|
-
|
|
72
|
-
const output = await readStream(stream.readable, KNOWN_BYTES_LENGTH)
|
|
73
|
-
expect(ui8.concat(KNOWN_BYTES)).to.deep.equal(
|
|
74
|
-
ui8.concat(output),
|
|
75
|
-
'Did not receive the same bytes we sent'
|
|
76
|
-
)
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
it('sends and receives data over an outgoing bidirectional stream with big buffers', async () => {
|
|
80
|
-
// client context - connects to the server, opens a bidi stream, sends some data and reads the response
|
|
81
|
-
client = new WebTransport(
|
|
82
|
-
`${process.env.SERVER_URL}/bidirectional_client_initiated_echo`,
|
|
83
|
-
wtOptions
|
|
84
|
-
)
|
|
85
|
-
await client.ready
|
|
86
|
-
|
|
87
|
-
const stream = await client.createBidirectionalStream()
|
|
88
|
-
await writeStream(stream.writable, KNOWN_BYTES_LONG)
|
|
89
|
-
|
|
90
|
-
const output = await readStream(stream.readable, KNOWN_BYTES_LONG_LENGTH)
|
|
91
|
-
const send = ui8.concat(KNOWN_BYTES_LONG)
|
|
92
|
-
const received = ui8.concat(output)
|
|
93
|
-
let failure = 0
|
|
94
|
-
for (let i = 0; i < Math.max(send.byteLength, received.byteLength); i++) {
|
|
95
|
-
if (send[i] !== received[i] && failure < 100) {
|
|
96
|
-
console.log('d: ', i, ' ,', send[i], ', ', received[i])
|
|
97
|
-
failure++
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
expect(ui8.concat(KNOWN_BYTES_LONG)).to.deep.equal(
|
|
102
|
-
ui8.concat(output),
|
|
103
|
-
'Did not receive the same bytes we sent'
|
|
104
|
-
)
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
it('sends and receives data over an incoming bidirectional stream', async () => {
|
|
108
|
-
// client context - waits for the server to open a bidi stream then pipes it back to them
|
|
109
|
-
client = new WebTransport(
|
|
110
|
-
`${process.env.SERVER_URL}/bidirectional_server_initiated_echo`,
|
|
111
|
-
wtOptions
|
|
112
|
-
)
|
|
113
|
-
await client.ready
|
|
114
|
-
|
|
115
|
-
const bidiStream = await getReaderValue(client.incomingBidirectionalStreams)
|
|
116
|
-
|
|
117
|
-
// redirect input to output
|
|
118
|
-
try {
|
|
119
|
-
await bidiStream.readable.pipeTo(bidiStream.writable)
|
|
120
|
-
} catch (error) {
|
|
121
|
-
console.log('Pipe to error (ignore)', error) // Actually all you can get is, that the fin is catched
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// the remote will close the session
|
|
125
|
-
const result = await client.closed
|
|
126
|
-
|
|
127
|
-
// should receive the default close info
|
|
128
|
-
expect(result).to.have.property('reason', '')
|
|
129
|
-
expect(result).to.have.property('closeCode', 0)
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
it('receives data from server and checks receiving stream fin', async () => {
|
|
133
|
-
// client context - waits for the server to open a bidi stream then pipes it back to them
|
|
134
|
-
client = new WebTransport(
|
|
135
|
-
`${process.env.SERVER_URL}/bidirectional_server_fin_send`,
|
|
136
|
-
wtOptions
|
|
137
|
-
)
|
|
138
|
-
await client.ready
|
|
139
|
-
|
|
140
|
-
const bidiStream = await getReaderValue(client.incomingBidirectionalStreams)
|
|
141
|
-
const reader = bidiStream.readable.getReader()
|
|
142
|
-
|
|
143
|
-
while (true) {
|
|
144
|
-
const res = await reader.read()
|
|
145
|
-
if (res.done) {
|
|
146
|
-
break
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
})
|
|
150
|
-
})
|