@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.
Files changed (75) hide show
  1. package/dist/lib/dom.d.ts +27 -10
  2. package/dist/lib/dom.d.ts.map +1 -1
  3. package/dist/lib/http2/browser/browser.d.ts +5 -2
  4. package/dist/lib/http2/browser/browser.d.ts.map +1 -1
  5. package/dist/lib/http2/browser/browserparser.d.ts.map +1 -1
  6. package/dist/lib/http2/node/capsuleparser.d.ts.map +1 -1
  7. package/dist/lib/http2/node/client.d.ts +3 -2
  8. package/dist/lib/http2/node/client.d.ts.map +1 -1
  9. package/dist/lib/http2/node/server.d.ts +10 -5
  10. package/dist/lib/http2/node/server.d.ts.map +1 -1
  11. package/dist/lib/http2/node/websocketparser.d.ts.map +1 -1
  12. package/dist/lib/http2/parserbase.d.ts +33 -1
  13. package/dist/lib/http2/parserbase.d.ts.map +1 -1
  14. package/dist/lib/http2/priorityscheduler.d.ts +167 -0
  15. package/dist/lib/http2/priorityscheduler.d.ts.map +1 -0
  16. package/dist/lib/http2/session.d.ts +25 -16
  17. package/dist/lib/http2/session.d.ts.map +1 -1
  18. package/dist/lib/http2/stream.d.ts +10 -0
  19. package/dist/lib/http2/stream.d.ts.map +1 -1
  20. package/dist/lib/http2/websocketcommon.d.ts.map +1 -1
  21. package/dist/lib/server.d.ts.map +1 -1
  22. package/dist/lib/session.d.ts +31 -17
  23. package/dist/lib/session.d.ts.map +1 -1
  24. package/dist/lib/stream.d.ts +13 -0
  25. package/dist/lib/stream.d.ts.map +1 -1
  26. package/dist/lib/types.d.ts +18 -15
  27. package/dist/lib/types.d.ts.map +1 -1
  28. package/dist/lib/webtransport.browser.d.ts +3 -2
  29. package/dist/lib/webtransport.browser.d.ts.map +1 -1
  30. package/dist/lib/webtransportbase.d.ts +1 -0
  31. package/dist/lib/webtransportbase.d.ts.map +1 -1
  32. package/eslint.config.js +20 -22
  33. package/lib/dom.ts +31 -13
  34. package/lib/http2/browser/browser.js +28 -13
  35. package/lib/http2/browser/browserparser.js +4 -1
  36. package/lib/http2/node/capsuleparser.js +4 -1
  37. package/lib/http2/node/client.js +38 -27
  38. package/lib/http2/node/server.js +56 -19
  39. package/lib/http2/node/websocketparser.js +5 -2
  40. package/lib/http2/parserbase.js +76 -7
  41. package/lib/http2/priorityscheduler.js +654 -0
  42. package/lib/http2/session.js +69 -20
  43. package/lib/http2/stream.js +60 -10
  44. package/lib/http2/websocketcommon.js +1 -1
  45. package/lib/server.js +0 -1
  46. package/lib/session.js +128 -64
  47. package/lib/stream.js +50 -8
  48. package/lib/types.ts +15 -8
  49. package/lib/webtransport.browser.js +77 -18
  50. package/lib/webtransportbase.js +7 -0
  51. package/old_test/echoserver.js +1 -1
  52. package/old_test/test.js +1 -1
  53. package/old_test/testsuite.js +6 -2
  54. package/package.json +7 -28
  55. package/readme.md +5 -3
  56. package/test/bidirectional-streams.spec.js +0 -150
  57. package/test/datagrams.spec.js +0 -104
  58. package/test/fixtures/certificate.js +0 -456
  59. package/test/fixtures/chai.js +0 -8
  60. package/test/fixtures/known-bytes.js +0 -44
  61. package/test/fixtures/p-timeout.js +0 -33
  62. package/test/fixtures/quiche.browser.js +0 -2
  63. package/test/fixtures/quiche.js +0 -1
  64. package/test/fixtures/read-cert-hash.js +0 -7
  65. package/test/fixtures/read-stream.js +0 -57
  66. package/test/fixtures/reader-value.js +0 -51
  67. package/test/fixtures/server.js +0 -467
  68. package/test/fixtures/webtransport.browser.js +0 -19
  69. package/test/fixtures/webtransport.js +0 -3
  70. package/test/fixtures/write-stream.js +0 -24
  71. package/test/index.js +0 -124
  72. package/test/pw-no-https-errors.json +0 -5
  73. package/test/session.spec.js +0 -199
  74. package/test/stream-limits.spec.js +0 -259
  75. package/test/unidirectional-streams.spec.js +0 -133
package/test/index.js DELETED
@@ -1,124 +0,0 @@
1
- import { execa } from 'execa'
2
-
3
- /**
4
- * Run server as separate process so we can kill it without
5
- * getting stuck waiting for the custom event loop to end.
6
- */
7
- async function startServer() {
8
- let http2 = false
9
- if (process.argv[3] === 'http2') http2 = true
10
- // eslint-disable-next-line no-unused-vars
11
- return new Promise((resolve, reject) => {
12
- let foundAddress = false
13
-
14
- const server = execa('node', ['./test/fixtures/server.js'], {
15
- stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
16
- env: {
17
- USE_HTTP2: http2 ? 'true' : 'false'
18
- }
19
- })
20
- server.on('message', (data) => {
21
- if (!foundAddress) {
22
- foundAddress = true
23
-
24
- resolve(data)
25
- }
26
- })
27
- })
28
- }
29
-
30
- /**
31
- * @param {string} certificate
32
- * @param {string} serverAddress
33
- */
34
- async function runTests(certificate, serverAddress) {
35
- const env = process.argv[2]
36
- let http2 = false
37
- if (process.argv[3] === 'http2') http2 = true
38
- let polyfill = false
39
- let ponyfill = false
40
- let slice = 4
41
- if (process.argv.length > 3 && process.argv[4] === 'polyfill') {
42
- polyfill = true
43
- slice++
44
- if (env === 'node') throw new Error('Polyfill not supported on node')
45
- }
46
- if (process.argv.length > 3 && process.argv[4] === 'ponyfill') {
47
- ponyfill = true
48
- slice++
49
- if (env === 'node') throw new Error('Ponyfill not supported on node')
50
- }
51
- /** @type {string} */
52
- let command = ''
53
- /** @type {string[]} */
54
- let args = []
55
-
56
- if (env === 'node') {
57
- command = 'mocha'
58
- args = [
59
- process.env.CI ? '--no-colors' : '--colors',
60
- './test/*.spec.js',
61
- ...process.argv.slice(4)
62
- ]
63
- const tests = execa(command, args, {
64
- env: {
65
- DEBUG_COLORS: process.env.CI ? '' : 'true',
66
- CERT_HASH: certificate,
67
- SERVER_URL: serverAddress,
68
- USE_HTTP2: http2 ? 'true' : 'false'
69
- },
70
- stdio: ['inherit', 'inherit', 'inherit']
71
- })
72
-
73
- await tests
74
- } else if (env === 'chromium' || env === 'firefox' || env === 'webkit') {
75
- command = 'playwright-test'
76
- const otheropts = []
77
- if (polyfill || ponyfill || env === 'firefox')
78
- otheropts.push('--config', './test/pw-no-https-errors.json')
79
- args = [
80
- './test/*.spec.js',
81
- '-b',
82
- env /* the browser */,
83
- ...otheropts,
84
- ...process.argv.slice(slice)
85
- ]
86
- const tests = execa(command, args, {
87
- env: {
88
- DEBUG_COLORS: process.env.CI ? '' : 'true',
89
- CERT_HASH: certificate,
90
- SERVER_URL: serverAddress,
91
- USE_HTTP2: http2 ? 'true' : 'false',
92
- USE_POLYFILL: polyfill ? 'true' : 'false',
93
- USE_PONYFILL: ponyfill ? 'true' : 'false',
94
- NO_CERT_HASHES:
95
- env === 'firefox' && !ponyfill && !polyfill ? 'true' : 'false',
96
- BROWSER: env
97
- },
98
- stdio: ['inherit', 'inherit', 'inherit']
99
- })
100
-
101
- await tests
102
- }
103
- }
104
-
105
- let success = true
106
-
107
- try {
108
- const { address, certificate } = await startServer()
109
-
110
- await runTests(certificate, address)
111
- } catch (/** @type {any} */ err) {
112
- if (err.command == null) {
113
- // was not an execa error
114
- throw err
115
- }
116
-
117
- if (err.failed || err.timedOut || err.isCancelled || err.isKilled) {
118
- console.log('Error cause mocha process', err)
119
- success = false
120
- }
121
- } finally {
122
- // this will cause the server process to exit too as it is a child of this process
123
- process.exit(success ? 0 : 1)
124
- }
@@ -1,5 +0,0 @@
1
- {
2
- "browserContextOptions": {
3
- "ignoreHTTPSErrors": true
4
- }
5
- }
@@ -1,199 +0,0 @@
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
- import { quicheLoaded } from './fixtures/quiche.js'
7
- import { getReaderValue } from './fixtures/reader-value.js'
8
- import { readStringFromStream } from './fixtures/read-stream.js'
9
-
10
- /**
11
- * @template T
12
- * @typedef {import('../lib/types').Deferred<T>} Deferred<T>
13
- */
14
-
15
- describe('session', function () {
16
- let forceReliable = false
17
- if (process.env.USE_HTTP2 === 'true') forceReliable = true
18
- const browser = process.env.BROWSER
19
- const handshakemess =
20
- browser !== 'firefox' ||
21
- process.env.USE_POLYFILL === 'true' ||
22
- process.env.USE_PONYFILL === 'true'
23
- ? 'Opening handshake failed.'
24
- : 'WebTransport connection rejected'
25
-
26
- /** @type {import('../lib/dom').WebTransport | undefined} */
27
- let client
28
-
29
- const wtOptions = {
30
- serverCertificateHashes: [
31
- {
32
- algorithm: 'sha-256',
33
- value: readCertHash(process.env.CERT_HASH)
34
- }
35
- ],
36
- // @ts-ignore
37
- forceReliable
38
- }
39
-
40
- if (process.env.NO_CERT_HASHES === 'true')
41
- // @ts-ignore
42
- delete wtOptions.serverCertificateHashes
43
-
44
- // @ts-ignore
45
- beforeEach(async () => {
46
- if (
47
- process.env.USE_HTTP2 !== 'true' &&
48
- process.env.USE_PONYFILL !== 'true' &&
49
- process.env.USE_POLYFILL !== 'true'
50
- ) {
51
- await quicheLoaded
52
- }
53
- })
54
-
55
- // @ts-ignore
56
- afterEach(async () => {
57
- if (client != null) {
58
- client.close()
59
- client = undefined
60
- }
61
- })
62
-
63
- it('should detect session closure', async () => {
64
- client = new WebTransport(
65
- `${process.env.SERVER_URL}/session_close`,
66
- wtOptions
67
- )
68
- await client.ready
69
-
70
- const result = await client.closed
71
- expect(result).to.have.property('closeCode', 0)
72
- expect(result).to.have.property('reason', '')
73
- })
74
-
75
- it('should detect session closure with close info', async () => {
76
- // client context - connects to the server, sends some datagrams and reads the response
77
- client = new WebTransport(
78
- `${process.env.SERVER_URL}/session_close_with_reason`,
79
- wtOptions
80
- )
81
- await client.ready
82
-
83
- const result = await client.closed
84
- expect(result).to.have.property('closeCode', 7)
85
- expect(result).to.have.property('reason', 'this is the reason')
86
- })
87
-
88
- it('should parse user data', async () => {
89
- client = new WebTransport(
90
- `${process.env.SERVER_URL}/session_with_userdata?foo=bar`,
91
- wtOptions
92
- )
93
- await client.ready
94
-
95
- const stream = await getReaderValue(client.incomingUnidirectionalStreams)
96
- const string = await readStringFromStream(stream)
97
- const userData = JSON.parse(string)
98
- expect(userData).to.have.property('search', '?foo=bar')
99
- })
100
-
101
- if (browser === 'firefox') this.timeout(31000) // really firefox?
102
- it('should error when connecting to a server that does not exist', async () => {
103
- client = new WebTransport(`https://127.0.0.1:39821`, {
104
- quicConnectTimeout: 100,
105
- webTransportConnectTimeout: 100,
106
- ...wtOptions
107
- })
108
-
109
- const [closedResult, readyResult] = await Promise.all([
110
- client.closed.catch((err) => err),
111
- client.ready.catch((err) => err)
112
- ])
113
-
114
- expect(closedResult)
115
- .to.be.a('WebTransportError')
116
- .with.property('message', handshakemess)
117
- expect(readyResult)
118
- .to.be.a('WebTransportError')
119
- .with.property('message', handshakemess)
120
- })
121
-
122
- it('should error when connecting to a path that does not exist', async () => {
123
- client = new WebTransport(
124
- `${process.env.SERVER_URL}/non_existant`,
125
- wtOptions
126
- )
127
-
128
- const [closedResult, readyResult] = await Promise.all([
129
- client.closed.catch((err) => err),
130
- client.ready.catch((err) => err)
131
- ])
132
-
133
- expect(closedResult)
134
- .to.be.a('WebTransportError')
135
- .with.property('message', handshakemess)
136
- expect(readyResult)
137
- .to.be.a('WebTransportError')
138
- .with.property('message', handshakemess)
139
- })
140
-
141
- if (
142
- process.env.USE_POLYFILL !== 'true' &&
143
- process.env.USE_PONYFILL !== 'true' &&
144
- wtOptions.serverCertificateHashes
145
- ) {
146
- // deactivated in polyfill case, no test necessary
147
- it('should error when connecting with a bad certificate', async () => {
148
- client = new WebTransport(`${process.env.SERVER_URL}/session_close`, {
149
- serverCertificateHashes: [
150
- {
151
- algorithm: 'sha-256',
152
- value: readCertHash(process.env.CERT_HASH + ':DE:AD:BE:EF')
153
- }
154
- ],
155
- // @ts-ignore
156
- forceReliable
157
- })
158
-
159
- const [closedResult, readyResult] = await Promise.all([
160
- client.closed.catch((err) => err),
161
- client.ready.catch((err) => err)
162
- ])
163
-
164
- expect(closedResult)
165
- .to.be.a('WebTransportError')
166
- .with.property('message', handshakemess)
167
- expect(readyResult)
168
- .to.be.a('WebTransportError')
169
- .with.property('message', handshakemess)
170
- })
171
-
172
- it('should error when connecting with the wrong certificate', async () => {
173
- client = new WebTransport(`${process.env.SERVER_URL}/session_close`, {
174
- serverCertificateHashes: [
175
- {
176
- algorithm: 'sha-256',
177
- value: readCertHash(
178
- 'DE:AD:BE:EF:' + process.env.CERT_HASH?.substring(12)
179
- )
180
- }
181
- ],
182
- // @ts-ignore
183
- forceReliable
184
- })
185
-
186
- const [closedResult, readyResult] = await Promise.all([
187
- client.closed.catch((err) => err),
188
- client.ready.catch((err) => err)
189
- ])
190
-
191
- expect(closedResult)
192
- .to.be.a('WebTransportError')
193
- .with.property('message', handshakemess)
194
- expect(readyResult)
195
- .to.be.a('WebTransportError')
196
- .with.property('message', handshakemess)
197
- })
198
- }
199
- })
@@ -1,259 +0,0 @@
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
- import { quicheLoaded } from './fixtures/quiche.js'
7
-
8
- /**
9
- * @template T
10
- * @typedef {import('../lib/types').Deferred<T>} Deferred<T>
11
- */
12
- describe('streamlimits', function () {
13
- this.timeout(6000) // for debugging remove before commit
14
- let forceReliable = false
15
- let adjustlimit = 1
16
- if (process.env.USE_HTTP2 === 'true') {
17
- forceReliable = true
18
- adjustlimit = 0
19
- }
20
- const browser = process.env.BROWSER
21
- /* const handshakemess =
22
- browser !== 'firefox' ||
23
- process.env.USE_POLYFILL === 'true' ||
24
- process.env.USE_PONYFILL === 'true'
25
- ? 'Opening handshake failed.'
26
- : 'WebTransport connection rejected' */
27
-
28
- const dowaitUntilAvailable = browser !== 'chromium' // remove after implementation
29
-
30
- /** @type {import('../lib/dom').WebTransport | undefined} */
31
- let client
32
-
33
- const wtOptions = {
34
- serverCertificateHashes: [
35
- {
36
- algorithm: 'sha-256',
37
- value: readCertHash(process.env.CERT_HASH)
38
- }
39
- ],
40
- // @ts-ignore
41
- forceReliable
42
- }
43
-
44
- if (process.env.NO_CERT_HASHES === 'true')
45
- // @ts-ignore
46
- delete wtOptions.serverCertificateHashes
47
-
48
- // @ts-ignore
49
- beforeEach(async () => {
50
- if (
51
- process.env.USE_HTTP2 !== 'true' &&
52
- process.env.USE_PONYFILL !== 'true' &&
53
- process.env.USE_POLYFILL !== 'true'
54
- ) {
55
- await quicheLoaded
56
- }
57
- })
58
-
59
- // @ts-ignore
60
- afterEach(async () => {
61
- if (client != null) {
62
- client.close()
63
- client = undefined
64
- }
65
- })
66
-
67
- if (dowaitUntilAvailable) {
68
- it('should detect stream limit bidi outgoing with waitUntilAvailable = true', async () => {
69
- client = new WebTransport(
70
- `${process.env.SERVER_URL}/streamlimits_getbidis_wua`,
71
- { ...wtOptions }
72
- )
73
- await client.ready
74
- const bidistreams = []
75
- let numbidi = 0
76
- for (let i = 0; i < 150; i++) {
77
- const curstream = client.createBidirectionalStream({
78
- waitUntilAvailable: true
79
- })
80
- bidistreams.push(curstream)
81
- curstream
82
- .then(() => {
83
- numbidi++
84
- })
85
- .catch(() => {})
86
- }
87
- await client.createUnidirectionalStream({
88
- waitUntilAvailable: true
89
- })
90
- expect(numbidi).to.equal(100 - adjustlimit)
91
- await client.createUnidirectionalStream({
92
- waitUntilAvailable: true
93
- })
94
- for (let i = 0; i < 50 + adjustlimit; i++) {
95
- const curstream = await bidistreams.shift()
96
- await curstream.readable.cancel()
97
- await curstream.writable.close()
98
- }
99
- await Promise.allSettled(bidistreams)
100
- await client.createUnidirectionalStream({
101
- waitUntilAvailable: true
102
- })
103
- expect(numbidi).to.equal(150)
104
-
105
- const result = await client.closed
106
- expect(result).to.have.property('closeCode', 0)
107
- expect(result).to.have.property('reason', '')
108
- })
109
- }
110
-
111
- it('should detect stream limit bidi outgoing', async () => {
112
- client = new WebTransport(
113
- `${process.env.SERVER_URL}/streamlimits_getbidis`,
114
- { ...wtOptions }
115
- )
116
- await client.ready
117
- const bidistreams = []
118
- let numbidi = 0
119
- let numfailed = 0
120
- for (let i = 0; i < 150; i++) {
121
- const curstream = client.createBidirectionalStream()
122
- bidistreams.push(curstream)
123
- curstream
124
- .then(() => {
125
- numbidi++
126
- })
127
- .catch(() => {
128
- numfailed++
129
- })
130
- }
131
- await Promise.allSettled(bidistreams)
132
- expect(numbidi).to.equal(100 - adjustlimit)
133
- expect(numfailed).to.equal(50 + adjustlimit)
134
- numfailed = 0
135
- for (let i = 0; i < 50 + adjustlimit; i++) {
136
- const curstream = await bidistreams.shift()
137
- await curstream.readable.cancel()
138
- await curstream.writable.close()
139
- }
140
- // as close is not a save measure, that the limit is updated
141
- // actually no save measure exist, waiting for a typical rtt could be a way
142
- // to ensure that the update of maxstreams arrives
143
- await new Promise((resolve) => setTimeout(resolve, 200))
144
-
145
- for (let i = 0; i < 50 + adjustlimit; i++) {
146
- const curstream = client.createBidirectionalStream()
147
- bidistreams.push(curstream)
148
- curstream
149
- .then(() => {
150
- numbidi++
151
- })
152
- .catch(() => {
153
- numfailed++
154
- })
155
- }
156
- await Promise.allSettled(bidistreams)
157
- expect(numbidi).to.equal(150)
158
- expect(numfailed).to.equal(0)
159
-
160
- const result = await client.closed
161
- expect(result).to.have.property('closeCode', 0)
162
- expect(result).to.have.property('reason', '')
163
- })
164
-
165
- if (dowaitUntilAvailable) {
166
- it('should detect stream limit unidi outgoing with waitUntilAvailable = true', async () => {
167
- client = new WebTransport(
168
- `${process.env.SERVER_URL}/streamlimits_getunidis_wua`,
169
- { ...wtOptions }
170
- )
171
- await client.ready
172
- const unidistreams = []
173
- let numunidi = 0
174
- for (let i = 0; i < 150; i++) {
175
- const curstream = client.createUnidirectionalStream({
176
- waitUntilAvailable: true
177
- })
178
- unidistreams.push(curstream)
179
- curstream
180
- .then(() => {
181
- numunidi++
182
- })
183
- .catch(() => {})
184
- }
185
- await client.createBidirectionalStream({
186
- waitUntilAvailable: true
187
- })
188
- expect(numunidi).to.equal(100)
189
- await client.createBidirectionalStream({
190
- waitUntilAvailable: true
191
- })
192
- for (let i = 0; i < 50 + adjustlimit; i++) {
193
- const curstream = await unidistreams.shift()
194
- await curstream.close()
195
- }
196
- await Promise.allSettled(unidistreams)
197
- await client.createBidirectionalStream({
198
- waitUntilAvailable: true
199
- })
200
- expect(numunidi).to.equal(150)
201
-
202
- const result = await client.closed
203
- expect(result).to.have.property('closeCode', 0)
204
- expect(result).to.have.property('reason', '')
205
- })
206
- }
207
-
208
- it('should detect stream limit unidi outgoing', async () => {
209
- client = new WebTransport(
210
- `${process.env.SERVER_URL}/streamlimits_getunidis`,
211
- { ...wtOptions }
212
- )
213
- await client.ready
214
- const unidistreams = []
215
- let numunidi = 0
216
- let numfailed = 0
217
- for (let i = 0; i < 150; i++) {
218
- const curstream = client.createUnidirectionalStream()
219
- unidistreams.push(curstream)
220
- curstream
221
- .then(() => {
222
- numunidi++
223
- })
224
- .catch(() => {
225
- numfailed++
226
- })
227
- }
228
- await Promise.allSettled(unidistreams)
229
- expect(numunidi).to.equal(100)
230
- expect(numfailed).to.equal(50)
231
- numfailed = 0
232
- for (let i = 0; i < 50 + adjustlimit; i++) {
233
- const curstream = await unidistreams.shift()
234
- await curstream.close()
235
- }
236
- // as close is not a save measure, that the limit is updated
237
- // actually no save measure exist, waiting for a typical rtt could be a way
238
- // to ensure that the update of maxstreams arrives
239
- await new Promise((resolve) => setTimeout(resolve, 200))
240
- for (let i = 0; i < 50; i++) {
241
- const curstream = client.createUnidirectionalStream()
242
- unidistreams.push(curstream)
243
- curstream
244
- .then(() => {
245
- numunidi++
246
- })
247
- .catch(() => {
248
- numfailed++
249
- })
250
- }
251
- await Promise.allSettled(unidistreams)
252
- expect(numunidi).to.equal(150)
253
- expect(numfailed).to.equal(0)
254
-
255
- const result = await client.closed
256
- expect(result).to.have.property('closeCode', 0)
257
- expect(result).to.have.property('reason', '')
258
- })
259
- })