@fails-components/webtransport 0.3.1 → 1.0.1
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/lib/client.js +81 -40
- package/lib/dom.ts +7 -5
- package/lib/http2/browser/browser.js +168 -0
- package/lib/http2/browser/browserparser.js +248 -0
- package/lib/http2/flowcontroller.js +371 -0
- package/lib/http2/node/capsuleparser.js +291 -0
- package/lib/http2/node/client.js +239 -0
- package/lib/http2/node/index.js +2 -0
- package/lib/http2/node/server.js +499 -0
- package/lib/http2/node/websocketparser.js +829 -0
- package/lib/http2/parserbase.js +139 -0
- package/lib/http2/parserbasehttp2.js +128 -0
- package/lib/http2/session.js +225 -0
- package/lib/http2/stream.js +354 -0
- package/lib/http2/websocketcommon.js +1 -0
- package/lib/{index.js → index.browser.js} +6 -10
- package/lib/index.node.js +27 -0
- package/lib/server.js +252 -69
- package/lib/session.js +31 -68
- package/lib/stream.js +103 -179
- package/lib/types.ts +174 -87
- package/lib/utils.js +2 -1
- package/lib/webstreams.browser.js +6 -0
- package/lib/webstreams.js +7 -0
- package/lib/webtransport.browser.js +284 -0
- package/lib/webtransport.node.js +137 -0
- package/lib/{webtransport.js → webtransportbase.js} +47 -41
- package/old_test/test.js +31 -29
- package/old_test/testsuite.js +1 -1
- package/package.json +18 -17
- package/readme.md +94 -30
- package/test/bidirectional-streams.spec.js +51 -9
- package/test/datagrams.spec.js +8 -2
- package/test/fixtures/known-bytes.js +29 -0
- package/test/fixtures/read-stream.js +1 -1
- package/test/fixtures/reader-value.js +1 -1
- package/test/fixtures/server.js +24 -10
- package/test/fixtures/webtransport.browser.js +20 -2
- package/test/fixtures/webtransport.js +1 -1
- package/test/index.js +33 -6
- package/test/pw-no-https-errors.json +5 -0
- package/test/session.spec.js +71 -52
- package/test/unidirectional-streams.spec.js +20 -4
- package/CMakeLists.txt +0 -991
- package/LICENSE.chromium +0 -27
- package/LICENSE.envoy +0 -207
- package/build.js +0 -313
- package/dist/lib/client.d.ts +0 -78
- package/dist/lib/client.d.ts.map +0 -1
- package/dist/lib/dom.d.ts +0 -87
- package/dist/lib/dom.d.ts.map +0 -1
- package/dist/lib/error.d.ts +0 -8
- package/dist/lib/error.d.ts.map +0 -1
- package/dist/lib/event-loop.d.ts +0 -33
- package/dist/lib/event-loop.d.ts.map +0 -1
- package/dist/lib/index.d.ts +0 -79
- package/dist/lib/index.d.ts.map +0 -1
- package/dist/lib/native.d.ts +0 -2
- package/dist/lib/native.d.ts.map +0 -1
- package/dist/lib/server.d.ts +0 -92
- package/dist/lib/server.d.ts.map +0 -1
- package/dist/lib/session.d.ts +0 -298
- package/dist/lib/session.d.ts.map +0 -1
- package/dist/lib/stream.d.ts +0 -135
- package/dist/lib/stream.d.ts.map +0 -1
- package/dist/lib/transport.d.ts +0 -34
- package/dist/lib/transport.d.ts.map +0 -1
- package/dist/lib/types.d.ts +0 -212
- package/dist/lib/types.d.ts.map +0 -1
- package/dist/lib/utils.d.ts +0 -11
- package/dist/lib/utils.d.ts.map +0 -1
- package/dist/lib/webtransport.d.ts +0 -47
- package/dist/lib/webtransport.d.ts.map +0 -1
- package/dist/test/bidirectional-streams.spec.d.ts +0 -5
- package/dist/test/bidirectional-streams.spec.d.ts.map +0 -1
- package/dist/test/datagrams.spec.d.ts +0 -5
- package/dist/test/datagrams.spec.d.ts.map +0 -1
- package/dist/test/event-loop.node.d.ts +0 -2
- package/dist/test/event-loop.node.d.ts.map +0 -1
- package/dist/test/fixtures/certificate.d.ts +0 -21
- package/dist/test/fixtures/certificate.d.ts.map +0 -1
- package/dist/test/fixtures/chai.d.ts +0 -2
- package/dist/test/fixtures/chai.d.ts.map +0 -1
- package/dist/test/fixtures/known-bytes.d.ts +0 -6
- package/dist/test/fixtures/known-bytes.d.ts.map +0 -1
- package/dist/test/fixtures/p-timeout.d.ts +0 -8
- package/dist/test/fixtures/p-timeout.d.ts.map +0 -1
- package/dist/test/fixtures/read-cert-hash.d.ts +0 -6
- package/dist/test/fixtures/read-cert-hash.d.ts.map +0 -1
- package/dist/test/fixtures/read-stream.d.ts +0 -19
- package/dist/test/fixtures/read-stream.d.ts.map +0 -1
- package/dist/test/fixtures/reader-value.d.ts +0 -22
- package/dist/test/fixtures/reader-value.d.ts.map +0 -1
- package/dist/test/fixtures/server.d.ts +0 -5
- package/dist/test/fixtures/server.d.ts.map +0 -1
- package/dist/test/fixtures/webtransport.browser.d.ts +0 -3
- package/dist/test/fixtures/webtransport.browser.d.ts.map +0 -1
- package/dist/test/fixtures/webtransport.d.ts +0 -3
- package/dist/test/fixtures/webtransport.d.ts.map +0 -1
- package/dist/test/fixtures/write-stream.d.ts +0 -10
- package/dist/test/fixtures/write-stream.d.ts.map +0 -1
- package/dist/test/index.d.ts +0 -2
- package/dist/test/index.d.ts.map +0 -1
- package/dist/test/session.spec.d.ts +0 -5
- package/dist/test/session.spec.d.ts.map +0 -1
- package/dist/test/unidirectional-streams.spec.d.ts +0 -2
- package/dist/test/unidirectional-streams.spec.d.ts.map +0 -1
- package/failslogolicensereadme.txt +0 -4
- package/lib/event-loop.js +0 -88
- package/lib/native.js +0 -28
- package/lib/transport.js +0 -82
- package/platform/icufix/fakedata.cpp +0 -8
- package/platform/quiche/quic/core/io/socket_win.inc +0 -3
- package/platform/quiche_platform_impl/quiche_bug_tracker_impl.h +0 -7
- package/platform/quiche_platform_impl/quiche_client_stats_impl.h +0 -7
- package/platform/quiche_platform_impl/quiche_command_line_flags_impl.h +0 -7
- package/platform/quiche_platform_impl/quiche_containers_impl.h +0 -7
- package/platform/quiche_platform_impl/quiche_event_loop_impl.h +0 -7
- package/platform/quiche_platform_impl/quiche_export_impl.h +0 -6
- package/platform/quiche_platform_impl/quiche_flag_utils_impl.h +0 -11
- package/platform/quiche_platform_impl/quiche_flags_impl.h +0 -8
- package/platform/quiche_platform_impl/quiche_iovec_impl.h +0 -10
- package/platform/quiche_platform_impl/quiche_logging_impl.h +0 -21
- package/platform/quiche_platform_impl/quiche_mem_slice_impl.h +0 -2
- package/platform/quiche_platform_impl/quiche_mutex_impl.h +0 -8
- package/platform/quiche_platform_impl/quiche_prefetch_impl.h +0 -11
- package/platform/quiche_platform_impl/quiche_reference_counted_impl.h +0 -16
- package/platform/quiche_platform_impl/quiche_server_stats_impl.h +0 -7
- package/platform/quiche_platform_impl/quiche_stack_trace_impl.h +0 -12
- package/platform/quiche_platform_impl/quiche_stream_buffer_allocator_impl.h +0 -8
- package/platform/quiche_platform_impl/quiche_testvalue_impl.h +0 -1
- package/platform/quiche_platform_impl/quiche_thread_local_impl.h +0 -6
- package/platform/quiche_platform_impl/quiche_time_utils_impl.h +0 -13
- package/platform/quiche_platform_impl/quiche_udp_socket_platform_impl.h +0 -39
- package/src/http3backendresponse.cc +0 -36
- package/src/http3backendresponse.h +0 -109
- package/src/http3client.cc +0 -1529
- package/src/http3client.h +0 -557
- package/src/http3clientsession.cc +0 -65
- package/src/http3clientsession.h +0 -60
- package/src/http3clientstream.cc +0 -52
- package/src/http3clientstream.h +0 -42
- package/src/http3dispatcher.cc +0 -62
- package/src/http3dispatcher.h +0 -57
- package/src/http3eventloop.cc +0 -1107
- package/src/http3eventloop.h +0 -316
- package/src/http3server.cc +0 -514
- package/src/http3server.h +0 -151
- package/src/http3serverbackend.cc +0 -105
- package/src/http3serverbackend.h +0 -98
- package/src/http3serversession.cc +0 -123
- package/src/http3serversession.h +0 -95
- package/src/http3serverstream.cc +0 -463
- package/src/http3serverstream.h +0 -114
- package/src/http3sessioncache.cc +0 -85
- package/src/http3sessioncache.h +0 -59
- package/src/http3wtsessionvisitor.cc +0 -46
- package/src/http3wtsessionvisitor.h +0 -397
- package/src/http3wtstreamvisitor.cc +0 -155
- package/src/http3wtstreamvisitor.h +0 -404
- package/test/event-loop.node.js +0 -24
- package/tsconfig.json +0 -39
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { connect, constants as http2constants } from 'node:http2'
|
|
2
|
+
import { Http2WebTransportSession } from '../session.js'
|
|
3
|
+
import { Http2CapsuleParser } from './capsuleparser.js'
|
|
4
|
+
import { logger } from '../../utils.js'
|
|
5
|
+
|
|
6
|
+
const log = logger(`webtransport:http2:node:client(${process?.pid})`)
|
|
7
|
+
|
|
8
|
+
export class Http2WebTransportClient {
|
|
9
|
+
/**
|
|
10
|
+
* @param {import('../../types.js').NativeClientOptions} args
|
|
11
|
+
*/
|
|
12
|
+
constructor(args) {
|
|
13
|
+
let port = args?.port
|
|
14
|
+
if (typeof port === 'undefined') port = 443
|
|
15
|
+
this.port = Number(port)
|
|
16
|
+
this.hostname = args?.host || 'localhost'
|
|
17
|
+
this.serverCertificateHashes = args?.serverCertificateHashes || undefined
|
|
18
|
+
this.localPort = Number(args?.localPort) || undefined
|
|
19
|
+
this.allowPooling = args?.allowPooling || false
|
|
20
|
+
this.forceIpv6 = args?.forceIpv6 || false
|
|
21
|
+
this.initialStreamFlowControlWindow =
|
|
22
|
+
args?.initialStreamFlowControlWindow || 16 * 1024 // 16 KB
|
|
23
|
+
this.initialSessionFlowControlWindow =
|
|
24
|
+
args?.initialSessionFlowControlWindow || 16 * 1024 // 16 KB
|
|
25
|
+
|
|
26
|
+
this.streamShouldAutoTuneReceiveWindow =
|
|
27
|
+
args.streamShouldAutoTuneReceiveWindow || false
|
|
28
|
+
this.streamFlowControlWindowSizeLimit =
|
|
29
|
+
args?.streamFlowControlWindowSizeLimit || 6 * 1024 * 1024
|
|
30
|
+
|
|
31
|
+
this.sessionShouldAutoTuneReceiveWindow =
|
|
32
|
+
args.sessionShouldAutoTuneReceiveWindow || false
|
|
33
|
+
this.sessionFlowControlWindowSizeLimit =
|
|
34
|
+
args?.sessionFlowControlWindowSizeLimit || 15 * 1024 * 1024
|
|
35
|
+
/** @type {import('../../session.js').HttpClient} */
|
|
36
|
+
// @ts-ignore
|
|
37
|
+
this.jsobj = undefined // the transport will set this
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
createTransport() {
|
|
41
|
+
/**
|
|
42
|
+
* @param {import('node:tls').PeerCertificate} cert
|
|
43
|
+
* */
|
|
44
|
+
const webTransportVerifier = (cert) => {
|
|
45
|
+
if (
|
|
46
|
+
this.serverCertificateHashes &&
|
|
47
|
+
this.serverCertificateHashes.some((el) => {
|
|
48
|
+
if (el.algorithm !== 'sha-256') return false
|
|
49
|
+
const cbytes = cert.fingerprint256
|
|
50
|
+
.split(':')
|
|
51
|
+
.map((el) => parseInt(el, 16))
|
|
52
|
+
const val = Buffer.isBuffer(el.value)
|
|
53
|
+
? el.value
|
|
54
|
+
: new Uint8Array(
|
|
55
|
+
ArrayBuffer.isView(el.value) ? el.value.buffer : el.value
|
|
56
|
+
)
|
|
57
|
+
if (cbytes.length !== val.byteLength) return false
|
|
58
|
+
for (let i = 0; i < val.byteLength; i++) {
|
|
59
|
+
if (val[i] !== cbytes[i]) return false
|
|
60
|
+
}
|
|
61
|
+
const curdate = new Date()
|
|
62
|
+
|
|
63
|
+
if (
|
|
64
|
+
new Date(cert.valid_from) > curdate ||
|
|
65
|
+
new Date(cert.valid_to) < curdate
|
|
66
|
+
)
|
|
67
|
+
return false
|
|
68
|
+
|
|
69
|
+
const difference =
|
|
70
|
+
new Date(cert.valid_to).getTime() -
|
|
71
|
+
new Date(cert.valid_from).getTime()
|
|
72
|
+
if (difference > 1000 * 60 * 60 * 24 * 14) return false // no more than 14 days spec says.
|
|
73
|
+
return true
|
|
74
|
+
})
|
|
75
|
+
)
|
|
76
|
+
return true
|
|
77
|
+
else return false
|
|
78
|
+
}
|
|
79
|
+
const http2Options = {
|
|
80
|
+
settings: {
|
|
81
|
+
enableConnectProtocol: true,
|
|
82
|
+
customSettings: {
|
|
83
|
+
0x2b60: 1, // SETTINGS_WEBTRANSPORT_MAX_SESSIONS, TODO fix number
|
|
84
|
+
0x2b61: this.initialSessionFlowControlWindow, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_DATA
|
|
85
|
+
0x2b62: this.initialStreamFlowControlWindow, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAM_DATA_UNI
|
|
86
|
+
0x2b63: this.initialStreamFlowControlWindow, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAM_DATA_BIDI
|
|
87
|
+
0x2b64: 0xffffff, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_UNI
|
|
88
|
+
0x2b65: 0xffffff // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_BIDI
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
localPort: this.localPort,
|
|
92
|
+
// TODO: REMOVE BEFORE RELEASE; UNSAFE SETTING
|
|
93
|
+
rejectUnauthorized: !this.serverCertificateHashes
|
|
94
|
+
}
|
|
95
|
+
if (this.serverCertificateHashes)
|
|
96
|
+
// @ts-ignore
|
|
97
|
+
http2Options.checkServerIdentity = webTransportVerifier
|
|
98
|
+
|
|
99
|
+
// @ts-ignore
|
|
100
|
+
this.clientInt = connect(
|
|
101
|
+
'https://' + this.hostname + ':' + this.port,
|
|
102
|
+
http2Options
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
let rtt = 100
|
|
106
|
+
let adjust = 1
|
|
107
|
+
// ok we got a session and want to measure RTT
|
|
108
|
+
let pingsender = setInterval(() => {
|
|
109
|
+
if (this.clientInt && !this.clientInt.closed) {
|
|
110
|
+
this.clientInt.ping((err, duration, payload) => {
|
|
111
|
+
if (!err) {
|
|
112
|
+
rtt = adjust * duration + (1 - adjust) * rtt
|
|
113
|
+
adjust = 0.2
|
|
114
|
+
// @ts-ignore
|
|
115
|
+
this.clientInt.WTrtt = rtt
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
} else {
|
|
119
|
+
clearInterval(pingsender)
|
|
120
|
+
// @ts-ignore
|
|
121
|
+
pingsender = undefined
|
|
122
|
+
}
|
|
123
|
+
}, 1000)
|
|
124
|
+
|
|
125
|
+
this.clientInt.on('close', () => {
|
|
126
|
+
if (pingsender) clearInterval(pingsender)
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
let authfail = false
|
|
130
|
+
this.clientInt.socket.on('secureConnect', () => {
|
|
131
|
+
/** @type {import('node:tls').TLSSocket} */
|
|
132
|
+
// @ts-ignore
|
|
133
|
+
const oursocket = this.clientInt?.socket
|
|
134
|
+
if (!oursocket) throw new Error('Can not get http2 TLSSocket')
|
|
135
|
+
// @ts-ignore
|
|
136
|
+
if (!oursocket.authorized) {
|
|
137
|
+
// ok last hope we have hashes
|
|
138
|
+
if (this.serverCertificateHashes) {
|
|
139
|
+
if (!webTransportVerifier(oursocket.getPeerCertificate())) {
|
|
140
|
+
this.clientInt?.destroy(
|
|
141
|
+
undefined,
|
|
142
|
+
http2constants.NGHTTP2_REFUSED_STREAM
|
|
143
|
+
)
|
|
144
|
+
log('Certificate hash does not match')
|
|
145
|
+
authfail = true
|
|
146
|
+
this.jsobj.onClientConnected({
|
|
147
|
+
success: false
|
|
148
|
+
})
|
|
149
|
+
} else {
|
|
150
|
+
oursocket.authorized = true
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
this.clientInt?.destroy(
|
|
154
|
+
new Error('Certificate not authorized'),
|
|
155
|
+
http2constants.NGHTTP2_REFUSED_STREAM
|
|
156
|
+
)
|
|
157
|
+
authfail = true
|
|
158
|
+
log('Certificate not authorized')
|
|
159
|
+
this.jsobj.onClientConnected({
|
|
160
|
+
success: false
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
let connected = false
|
|
166
|
+
this.clientInt.on('connect', (session, socket) => {
|
|
167
|
+
if (!authfail) {
|
|
168
|
+
connected = true
|
|
169
|
+
this.jsobj.onClientConnected({
|
|
170
|
+
success: true
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
})
|
|
174
|
+
this.clientInt.on('error', (error) => {
|
|
175
|
+
log('http2 client error:', error)
|
|
176
|
+
if (!connected && !authfail) {
|
|
177
|
+
this.jsobj.onClientConnected({
|
|
178
|
+
success: false
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
})
|
|
182
|
+
this.clientInt.on('remoteSettings', (settings) => {
|
|
183
|
+
if (settings.enableConnectProtocol && this.clientInt) {
|
|
184
|
+
// if (settings.webtansportmaxsessions)
|
|
185
|
+
// eslint-disable-next-line no-lone-blocks
|
|
186
|
+
{
|
|
187
|
+
const retObj = {}
|
|
188
|
+
this.jsobj.onClientWebTransportSupport(retObj)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* @param {string} path
|
|
196
|
+
*/
|
|
197
|
+
openWTSession(path) {
|
|
198
|
+
if (!this.clientInt) throw new Error('clientInt not present')
|
|
199
|
+
|
|
200
|
+
const stream = this.clientInt.request({
|
|
201
|
+
':method': 'CONNECT',
|
|
202
|
+
':protocol': 'webtransport',
|
|
203
|
+
':scheme': 'https',
|
|
204
|
+
':path': path,
|
|
205
|
+
authority: this.hostname,
|
|
206
|
+
origin: this.hostname
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
const retObj = {
|
|
210
|
+
header: stream.sentHeaders,
|
|
211
|
+
session: new Http2WebTransportSession({
|
|
212
|
+
stream,
|
|
213
|
+
isclient: true,
|
|
214
|
+
createParser: (/** @type {Http2WebTransportSession} */ nativesession) =>
|
|
215
|
+
new Http2CapsuleParser({
|
|
216
|
+
stream,
|
|
217
|
+
nativesession,
|
|
218
|
+
isclient: true,
|
|
219
|
+
initialStreamSendWindowOffset: this.initialStreamFlowControlWindow,
|
|
220
|
+
initialStreamReceiveWindowOffset:
|
|
221
|
+
this.initialStreamFlowControlWindow,
|
|
222
|
+
streamShouldAutoTuneReceiveWindow:
|
|
223
|
+
this.streamShouldAutoTuneReceiveWindow,
|
|
224
|
+
streamReceiveWindowSizeLimit: this.streamFlowControlWindowSizeLimit
|
|
225
|
+
}),
|
|
226
|
+
sendWindowOffset: this.sessionFlowControlWindowSizeLimit,
|
|
227
|
+
receiveWindowOffset: this.sessionFlowControlWindowSizeLimit,
|
|
228
|
+
shouldAutoTuneReceiveWindow: this.sessionShouldAutoTuneReceiveWindow,
|
|
229
|
+
receiveWindowSizeLimit: this.sessionFlowControlWindowSizeLimit
|
|
230
|
+
}),
|
|
231
|
+
reliable: true
|
|
232
|
+
}
|
|
233
|
+
this.jsobj.onHttpWTSessionVisitor(retObj)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
closeClient() {
|
|
237
|
+
if (this.clientInt) this.clientInt.close()
|
|
238
|
+
}
|
|
239
|
+
}
|