@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.
Files changed (162) hide show
  1. package/lib/client.js +81 -40
  2. package/lib/dom.ts +7 -5
  3. package/lib/http2/browser/browser.js +168 -0
  4. package/lib/http2/browser/browserparser.js +248 -0
  5. package/lib/http2/flowcontroller.js +371 -0
  6. package/lib/http2/node/capsuleparser.js +291 -0
  7. package/lib/http2/node/client.js +239 -0
  8. package/lib/http2/node/index.js +2 -0
  9. package/lib/http2/node/server.js +499 -0
  10. package/lib/http2/node/websocketparser.js +829 -0
  11. package/lib/http2/parserbase.js +139 -0
  12. package/lib/http2/parserbasehttp2.js +128 -0
  13. package/lib/http2/session.js +225 -0
  14. package/lib/http2/stream.js +354 -0
  15. package/lib/http2/websocketcommon.js +1 -0
  16. package/lib/{index.js → index.browser.js} +6 -10
  17. package/lib/index.node.js +27 -0
  18. package/lib/server.js +252 -69
  19. package/lib/session.js +31 -68
  20. package/lib/stream.js +103 -179
  21. package/lib/types.ts +174 -87
  22. package/lib/utils.js +2 -1
  23. package/lib/webstreams.browser.js +6 -0
  24. package/lib/webstreams.js +7 -0
  25. package/lib/webtransport.browser.js +284 -0
  26. package/lib/webtransport.node.js +137 -0
  27. package/lib/{webtransport.js → webtransportbase.js} +47 -41
  28. package/old_test/test.js +31 -29
  29. package/old_test/testsuite.js +1 -1
  30. package/package.json +18 -17
  31. package/readme.md +94 -30
  32. package/test/bidirectional-streams.spec.js +51 -9
  33. package/test/datagrams.spec.js +8 -2
  34. package/test/fixtures/known-bytes.js +29 -0
  35. package/test/fixtures/read-stream.js +1 -1
  36. package/test/fixtures/reader-value.js +1 -1
  37. package/test/fixtures/server.js +24 -10
  38. package/test/fixtures/webtransport.browser.js +20 -2
  39. package/test/fixtures/webtransport.js +1 -1
  40. package/test/index.js +33 -6
  41. package/test/pw-no-https-errors.json +5 -0
  42. package/test/session.spec.js +71 -52
  43. package/test/unidirectional-streams.spec.js +20 -4
  44. package/CMakeLists.txt +0 -991
  45. package/LICENSE.chromium +0 -27
  46. package/LICENSE.envoy +0 -207
  47. package/build.js +0 -313
  48. package/dist/lib/client.d.ts +0 -78
  49. package/dist/lib/client.d.ts.map +0 -1
  50. package/dist/lib/dom.d.ts +0 -87
  51. package/dist/lib/dom.d.ts.map +0 -1
  52. package/dist/lib/error.d.ts +0 -8
  53. package/dist/lib/error.d.ts.map +0 -1
  54. package/dist/lib/event-loop.d.ts +0 -33
  55. package/dist/lib/event-loop.d.ts.map +0 -1
  56. package/dist/lib/index.d.ts +0 -79
  57. package/dist/lib/index.d.ts.map +0 -1
  58. package/dist/lib/native.d.ts +0 -2
  59. package/dist/lib/native.d.ts.map +0 -1
  60. package/dist/lib/server.d.ts +0 -92
  61. package/dist/lib/server.d.ts.map +0 -1
  62. package/dist/lib/session.d.ts +0 -298
  63. package/dist/lib/session.d.ts.map +0 -1
  64. package/dist/lib/stream.d.ts +0 -135
  65. package/dist/lib/stream.d.ts.map +0 -1
  66. package/dist/lib/transport.d.ts +0 -34
  67. package/dist/lib/transport.d.ts.map +0 -1
  68. package/dist/lib/types.d.ts +0 -212
  69. package/dist/lib/types.d.ts.map +0 -1
  70. package/dist/lib/utils.d.ts +0 -11
  71. package/dist/lib/utils.d.ts.map +0 -1
  72. package/dist/lib/webtransport.d.ts +0 -47
  73. package/dist/lib/webtransport.d.ts.map +0 -1
  74. package/dist/test/bidirectional-streams.spec.d.ts +0 -5
  75. package/dist/test/bidirectional-streams.spec.d.ts.map +0 -1
  76. package/dist/test/datagrams.spec.d.ts +0 -5
  77. package/dist/test/datagrams.spec.d.ts.map +0 -1
  78. package/dist/test/event-loop.node.d.ts +0 -2
  79. package/dist/test/event-loop.node.d.ts.map +0 -1
  80. package/dist/test/fixtures/certificate.d.ts +0 -21
  81. package/dist/test/fixtures/certificate.d.ts.map +0 -1
  82. package/dist/test/fixtures/chai.d.ts +0 -2
  83. package/dist/test/fixtures/chai.d.ts.map +0 -1
  84. package/dist/test/fixtures/known-bytes.d.ts +0 -6
  85. package/dist/test/fixtures/known-bytes.d.ts.map +0 -1
  86. package/dist/test/fixtures/p-timeout.d.ts +0 -8
  87. package/dist/test/fixtures/p-timeout.d.ts.map +0 -1
  88. package/dist/test/fixtures/read-cert-hash.d.ts +0 -6
  89. package/dist/test/fixtures/read-cert-hash.d.ts.map +0 -1
  90. package/dist/test/fixtures/read-stream.d.ts +0 -19
  91. package/dist/test/fixtures/read-stream.d.ts.map +0 -1
  92. package/dist/test/fixtures/reader-value.d.ts +0 -22
  93. package/dist/test/fixtures/reader-value.d.ts.map +0 -1
  94. package/dist/test/fixtures/server.d.ts +0 -5
  95. package/dist/test/fixtures/server.d.ts.map +0 -1
  96. package/dist/test/fixtures/webtransport.browser.d.ts +0 -3
  97. package/dist/test/fixtures/webtransport.browser.d.ts.map +0 -1
  98. package/dist/test/fixtures/webtransport.d.ts +0 -3
  99. package/dist/test/fixtures/webtransport.d.ts.map +0 -1
  100. package/dist/test/fixtures/write-stream.d.ts +0 -10
  101. package/dist/test/fixtures/write-stream.d.ts.map +0 -1
  102. package/dist/test/index.d.ts +0 -2
  103. package/dist/test/index.d.ts.map +0 -1
  104. package/dist/test/session.spec.d.ts +0 -5
  105. package/dist/test/session.spec.d.ts.map +0 -1
  106. package/dist/test/unidirectional-streams.spec.d.ts +0 -2
  107. package/dist/test/unidirectional-streams.spec.d.ts.map +0 -1
  108. package/failslogolicensereadme.txt +0 -4
  109. package/lib/event-loop.js +0 -88
  110. package/lib/native.js +0 -28
  111. package/lib/transport.js +0 -82
  112. package/platform/icufix/fakedata.cpp +0 -8
  113. package/platform/quiche/quic/core/io/socket_win.inc +0 -3
  114. package/platform/quiche_platform_impl/quiche_bug_tracker_impl.h +0 -7
  115. package/platform/quiche_platform_impl/quiche_client_stats_impl.h +0 -7
  116. package/platform/quiche_platform_impl/quiche_command_line_flags_impl.h +0 -7
  117. package/platform/quiche_platform_impl/quiche_containers_impl.h +0 -7
  118. package/platform/quiche_platform_impl/quiche_event_loop_impl.h +0 -7
  119. package/platform/quiche_platform_impl/quiche_export_impl.h +0 -6
  120. package/platform/quiche_platform_impl/quiche_flag_utils_impl.h +0 -11
  121. package/platform/quiche_platform_impl/quiche_flags_impl.h +0 -8
  122. package/platform/quiche_platform_impl/quiche_iovec_impl.h +0 -10
  123. package/platform/quiche_platform_impl/quiche_logging_impl.h +0 -21
  124. package/platform/quiche_platform_impl/quiche_mem_slice_impl.h +0 -2
  125. package/platform/quiche_platform_impl/quiche_mutex_impl.h +0 -8
  126. package/platform/quiche_platform_impl/quiche_prefetch_impl.h +0 -11
  127. package/platform/quiche_platform_impl/quiche_reference_counted_impl.h +0 -16
  128. package/platform/quiche_platform_impl/quiche_server_stats_impl.h +0 -7
  129. package/platform/quiche_platform_impl/quiche_stack_trace_impl.h +0 -12
  130. package/platform/quiche_platform_impl/quiche_stream_buffer_allocator_impl.h +0 -8
  131. package/platform/quiche_platform_impl/quiche_testvalue_impl.h +0 -1
  132. package/platform/quiche_platform_impl/quiche_thread_local_impl.h +0 -6
  133. package/platform/quiche_platform_impl/quiche_time_utils_impl.h +0 -13
  134. package/platform/quiche_platform_impl/quiche_udp_socket_platform_impl.h +0 -39
  135. package/src/http3backendresponse.cc +0 -36
  136. package/src/http3backendresponse.h +0 -109
  137. package/src/http3client.cc +0 -1529
  138. package/src/http3client.h +0 -557
  139. package/src/http3clientsession.cc +0 -65
  140. package/src/http3clientsession.h +0 -60
  141. package/src/http3clientstream.cc +0 -52
  142. package/src/http3clientstream.h +0 -42
  143. package/src/http3dispatcher.cc +0 -62
  144. package/src/http3dispatcher.h +0 -57
  145. package/src/http3eventloop.cc +0 -1107
  146. package/src/http3eventloop.h +0 -316
  147. package/src/http3server.cc +0 -514
  148. package/src/http3server.h +0 -151
  149. package/src/http3serverbackend.cc +0 -105
  150. package/src/http3serverbackend.h +0 -98
  151. package/src/http3serversession.cc +0 -123
  152. package/src/http3serversession.h +0 -95
  153. package/src/http3serverstream.cc +0 -463
  154. package/src/http3serverstream.h +0 -114
  155. package/src/http3sessioncache.cc +0 -85
  156. package/src/http3sessioncache.h +0 -59
  157. package/src/http3wtsessionvisitor.cc +0 -46
  158. package/src/http3wtsessionvisitor.h +0 -397
  159. package/src/http3wtstreamvisitor.cc +0 -155
  160. package/src/http3wtstreamvisitor.h +0 -404
  161. package/test/event-loop.node.js +0 -24
  162. package/tsconfig.json +0 -39
@@ -0,0 +1,499 @@
1
+ import { createSecureServer, constants } from 'node:http2'
2
+ import { Http2WebTransportSession } from '../session.js'
3
+ import { Http2CapsuleParser } from './capsuleparser.js'
4
+ import { WebSocketParser } from './websocketparser.js'
5
+ import { log } from 'node:console'
6
+ import { webcrypto as crypto } from 'crypto'
7
+ import { supportedVersions } from '../websocketcommon.js'
8
+ import { clearInterval } from 'node:timers'
9
+
10
+ export class Http2WebTransportServer {
11
+ /**
12
+ * @param {import('../../types.js').NativeServerOptions} args
13
+ */
14
+ constructor(args) {
15
+ let port = args?.port
16
+ if (typeof port === 'undefined') port = 443
17
+ this.port = Number(port)
18
+ this.secret = args?.secret
19
+ if (!this.secret) throw new Error('No secret set for Http2Server')
20
+ this.host = args?.host || 'localhost'
21
+ const cert = args?.certhttp2 ? args?.certhttp2 : args?.cert
22
+ if (!cert) throw new Error('No cert set for Http2Server')
23
+ const key = args?.privKeyhttp2 ? args?.privKeyhttp2 : args?.privKey
24
+ if (!key) throw new Error('No privKey set for Http2Server')
25
+ // this.maxConnections = args?.maxConnections
26
+ this.initialStreamFlowControlWindow =
27
+ args?.initialStreamFlowControlWindow || 16 * 1024 // 16 KB
28
+ this.initialSessionFlowControlWindow =
29
+ args?.initialSessionFlowControlWindow || 16 * 1024 // 16 KB
30
+
31
+ this.streamShouldAutoTuneReceiveWindow =
32
+ args.streamShouldAutoTuneReceiveWindow || false
33
+ this.streamFlowControlWindowSizeLimit =
34
+ args?.streamFlowControlWindowSizeLimit || 6 * 1024 * 1024
35
+
36
+ this.sessionShouldAutoTuneReceiveWindow =
37
+ args.sessionShouldAutoTuneReceiveWindow || false
38
+ this.sessionFlowControlWindowSizeLimit =
39
+ args?.sessionFlowControlWindowSizeLimit || 15 * 1024 * 1024
40
+
41
+ /** @type {Record<string, boolean>} */
42
+ this.paths = {}
43
+ this.hasrequesthandler = false
44
+ /** @type {import('../../session.js').HttpServer} */
45
+ // @ts-ignore
46
+ this.jsobj = undefined // the transport will set this
47
+
48
+ // @ts-ignore
49
+ this.serverInt = createSecureServer({
50
+ key,
51
+ cert,
52
+ allowHTTP1: true /* Chromium uses http2 only, if there is already an existing http2 connection */,
53
+ settings: {
54
+ enableConnectProtocol: true,
55
+ customSettings: {
56
+ 0x2b60: 1, // SETTINGS_WEBTRANSPORT_MAX_SESSIONS, TODO fix number
57
+ 0x2b61: this.initialSessionFlowControlWindow, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_DATA
58
+ 0x2b62: this.initialStreamFlowControlWindow, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAM_DATA_UNI
59
+ 0x2b63: this.initialStreamFlowControlWindow, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAM_DATA_BIDI
60
+ 0x2b64: 0xffffff, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_UNI
61
+ 0x2b65: 0xffffff // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_BIDI
62
+ }
63
+ }
64
+ })
65
+
66
+ this.serverInt.on('listening', () => {
67
+ const addr = this.serverInt.address()
68
+ const retObj = {
69
+ // @ts-ignore
70
+ port: addr?.port,
71
+ // @ts-ignore
72
+ host: addr?.address
73
+ }
74
+ // @ts-ignore
75
+ this.jsobj.onServerListening(retObj)
76
+ })
77
+
78
+ this.serverInt.on('error', () => {
79
+ const retObj = {}
80
+ // @ts-ignore
81
+ this.jsobj.onServerError(retObj)
82
+ /* TODO (stream) => {
83
+ stream.close(constants.NGHTTP2_CONNECT_ERROR)
84
+ }) */
85
+ })
86
+
87
+ this.serverInt.on('session', (session) => {
88
+ let rtt = 100
89
+ let adjust = 1
90
+ // ok we got a session and want to measure RTT
91
+ let pingsender = setInterval(() => {
92
+ if (!session.closed)
93
+ session.ping((err, duration, payload) => {
94
+ if (!err) {
95
+ rtt = adjust * duration + (1 - adjust) * rtt
96
+ adjust = 0.2
97
+ // @ts-ignore
98
+ session.WTrtt = rtt
99
+ }
100
+ })
101
+ else {
102
+ clearInterval(pingsender)
103
+ // @ts-ignore
104
+ pingsender = undefined
105
+ }
106
+ }, 1000)
107
+
108
+ session.on('close', () => {
109
+ if (pingsender) clearInterval(pingsender)
110
+ })
111
+ })
112
+
113
+ this.serverInt.on('close', () => {
114
+ const retObj = {}
115
+ // @ts-ignore
116
+ this.jsobj.onServerClose(retObj)
117
+ })
118
+
119
+ this.serverInt.on(
120
+ 'upgrade',
121
+ (request, stream /* actually a socket */, head) => {
122
+ let path = request.url
123
+ const header = request.headers
124
+ if (!path) {
125
+ stream.destroy()
126
+ return
127
+ }
128
+ const websocketProt = this.checkProtocolHeader(header)
129
+ if (!websocketProt) {
130
+ stream.destroy()
131
+ return
132
+ }
133
+ while (path.length > 1 && path[0] === '/' && path[1] === '/') {
134
+ path = path?.slice(1)
135
+ }
136
+ if (this.paths[path]) {
137
+ this.sendHttp1Headers({ stream, header, protocol: websocketProt })
138
+ .then(() => {
139
+ const retObj = {
140
+ session: new Http2WebTransportSession({
141
+ stream,
142
+ isclient: false,
143
+ createParser: (
144
+ /** @type {Http2WebTransportSession} */ nativesession
145
+ ) => {
146
+ const parse = (this.capsParser = new WebSocketParser({
147
+ stream,
148
+ nativesession,
149
+ isclient: false,
150
+ initialStreamSendWindowOffset:
151
+ this.initialStreamFlowControlWindow,
152
+ initialStreamReceiveWindowOffset:
153
+ this.initialStreamFlowControlWindow,
154
+ streamShouldAutoTuneReceiveWindow:
155
+ this.streamShouldAutoTuneReceiveWindow,
156
+ streamReceiveWindowSizeLimit:
157
+ this.streamFlowControlWindowSizeLimit
158
+ }))
159
+ if (head.byteLength > 0) parse.parseData(head)
160
+ return parse
161
+ },
162
+ sendWindowOffset: this.sessionFlowControlWindowSizeLimit,
163
+ receiveWindowOffset: this.sessionFlowControlWindowSizeLimit,
164
+ shouldAutoTuneReceiveWindow:
165
+ this.sessionShouldAutoTuneReceiveWindow,
166
+ receiveWindowSizeLimit: this.sessionFlowControlWindowSizeLimit
167
+ }),
168
+ path,
169
+ header,
170
+ reliable: true,
171
+ object: this // My server
172
+ }
173
+ this.jsobj.onHttpWTSessionVisitor(retObj)
174
+ })
175
+ .catch((error) => {
176
+ log('Problem sendHttp1Header', error)
177
+ stream.destroy()
178
+ })
179
+ } else if (this.hasrequesthandler) {
180
+ stream.head = head
181
+
182
+ const retObj = {
183
+ header,
184
+ session: stream,
185
+ protocol: 'websocketoverhttp1',
186
+ head
187
+ }
188
+ this.jsobj.onSessionRequest(retObj)
189
+ } else {
190
+ stream.destroy()
191
+ }
192
+ }
193
+ )
194
+
195
+ this.serverInt.on('stream', (stream, header) => {
196
+ if (header[':method'] !== 'CONNECT') {
197
+ // Only accept CONNECT requests
198
+ stream.respond({
199
+ ':status': '406'
200
+ })
201
+ stream.close(constants.NGHTTP2_REFUSED_STREAM)
202
+ return
203
+ }
204
+ /**
205
+ * @type {string|undefined}
206
+ */
207
+ let websocketProt
208
+ if (
209
+ header[':protocol'] === 'websocket' &&
210
+ header['Sec-WebSocket-Protocol']
211
+ ) {
212
+ websocketProt = this.checkProtocolHeader(header)
213
+ }
214
+ if (header[':protocol'] !== 'webtransport' && !websocketProt) {
215
+ stream.respond({
216
+ ':status': '406'
217
+ })
218
+ stream.close(constants.NGHTTP2_REFUSED_STREAM)
219
+ return
220
+ }
221
+ if (!header[':path']) {
222
+ stream.respond({
223
+ ':status': '406'
224
+ })
225
+ stream.close(constants.NGHTTP2_REFUSED_STREAM)
226
+ return
227
+ }
228
+ const path = header[':path']
229
+ if (this.paths[path]) {
230
+ const retObj = {
231
+ session: new Http2WebTransportSession({
232
+ stream,
233
+ isclient: false,
234
+ createParser: (
235
+ /** @type {Http2WebTransportSession} */ nativesession
236
+ ) => {
237
+ if (!websocketProt) {
238
+ return new Http2CapsuleParser({
239
+ stream,
240
+ nativesession,
241
+ isclient: false,
242
+ initialStreamSendWindowOffset:
243
+ this.initialStreamFlowControlWindow,
244
+ initialStreamReceiveWindowOffset:
245
+ this.initialStreamFlowControlWindow,
246
+ streamShouldAutoTuneReceiveWindow:
247
+ this.streamShouldAutoTuneReceiveWindow,
248
+ streamReceiveWindowSizeLimit:
249
+ this.streamFlowControlWindowSizeLimit
250
+ })
251
+ } else {
252
+ return (this.capsParser = new WebSocketParser({
253
+ stream,
254
+ nativesession,
255
+ isclient: false,
256
+ initialStreamSendWindowOffset:
257
+ this.initialStreamFlowControlWindow,
258
+ initialStreamReceiveWindowOffset:
259
+ this.initialStreamFlowControlWindow,
260
+ streamShouldAutoTuneReceiveWindow:
261
+ this.streamShouldAutoTuneReceiveWindow,
262
+ streamReceiveWindowSizeLimit:
263
+ this.streamFlowControlWindowSizeLimit
264
+ }))
265
+ }
266
+ },
267
+ sendWindowOffset: this.sessionFlowControlWindowSizeLimit,
268
+ receiveWindowOffset: this.sessionFlowControlWindowSizeLimit,
269
+ shouldAutoTuneReceiveWindow:
270
+ this.sessionShouldAutoTuneReceiveWindow,
271
+ receiveWindowSizeLimit: this.sessionFlowControlWindowSizeLimit
272
+ }),
273
+ path,
274
+ header,
275
+ reliable: true,
276
+ object: this // My server
277
+ }
278
+ const resp = {
279
+ ':status': '200'
280
+ }
281
+ // @ts-ignore
282
+ if (websocketProt) resp['Sec-WebSocket-Protocol'] = websocketProt
283
+ stream.respond(resp)
284
+ this.jsobj.onHttpWTSessionVisitor(retObj)
285
+ } else if (this.hasrequesthandler) {
286
+ const retObj = {
287
+ header,
288
+ session: stream,
289
+ protocol: websocketProt ? 'websocket' : 'capsule'
290
+ }
291
+ const resp = {
292
+ ':status': '200'
293
+ }
294
+ // @ts-ignore
295
+ if (websocketProt) resp['Sec-WebSocket-Protocol'] = websocketProt
296
+ stream.respond(resp)
297
+ this.jsobj.onSessionRequest(retObj)
298
+ } else {
299
+ stream.respond({
300
+ ':status': '404'
301
+ })
302
+ stream.end()
303
+ stream.close()
304
+ // eslint-disable-next-line no-useless-return
305
+ return
306
+ }
307
+ })
308
+ }
309
+
310
+ /**
311
+ * @param {import("http2").IncomingHttpHeaders} header
312
+ */
313
+ checkProtocolHeader(header) {
314
+ const sechead = header['sec-websocket-protocol']
315
+ let prots
316
+ if (!Array.isArray(sechead)) {
317
+ prots = [sechead]
318
+ } else {
319
+ prots = sechead
320
+ }
321
+ prots = prots
322
+ .map((el) => (el ? el.split('_') : [undefined, undefined]))
323
+ .filter((el) => el[0] === 'webtransport')
324
+ .filter((el) => (el[1] ? supportedVersions.includes(el[1]) : false))
325
+ if (prots.length > 0) return prots[0].join('_')
326
+ else return undefined
327
+ }
328
+
329
+ startServer() {
330
+ this.serverInt.listen(this.port, this.host)
331
+ }
332
+
333
+ stopServer() {
334
+ this.serverInt.close()
335
+ // TODO call close on all sessions
336
+ }
337
+
338
+ /**
339
+ * @param {string} cert
340
+ * @param {string} privKey
341
+ * @param {boolean} http2only
342
+ * */
343
+ updateCert(cert, privKey, http2only) {
344
+ this.serverInt.setSecureContext({ key: privKey, cert })
345
+ }
346
+
347
+ /**
348
+ * @param {boolean} isset
349
+ */
350
+ setJSRequestHandler(isset) {
351
+ this.hasrequesthandler = isset
352
+ }
353
+
354
+ /**
355
+ * @param {string} path
356
+ */
357
+ addPath(path) {
358
+ this.paths[path] = true
359
+ }
360
+
361
+ /**
362
+ * @param {{stream: import('net').Socket, header: any, protocol: string}} args
363
+ */
364
+ async sendHttp1Headers({ stream, header, protocol }) {
365
+ try {
366
+ const digi = await crypto.subtle.digest(
367
+ 'SHA-1',
368
+ new TextEncoder().encode(
369
+ header['sec-websocket-key'] + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
370
+ )
371
+ )
372
+ const wstoken = Buffer.from(digi).toString('base64')
373
+ stream.write(
374
+ 'HTTP/1.1 101 Switching Protocols\r\n' +
375
+ 'Upgrade: websocket\r\n' +
376
+ 'Connection: Upgrade\r\n' +
377
+ 'Sec-WebSocket-Protocol: ' +
378
+ protocol +
379
+ '\r\n' +
380
+ 'Sec-WebSocket-Accept: ' +
381
+ wstoken +
382
+ '\r\n' +
383
+ '\r\n'
384
+ )
385
+ // @ts-ignore
386
+ } catch (error) {
387
+ log('Problem decoding websocket token:', error)
388
+ stream.destroy()
389
+ }
390
+ }
391
+
392
+ /**
393
+ * @param {import('../../types.js').NativeFinishSessionRequest} args
394
+ */
395
+ finishSessionRequest({ header, session: stream, status, protocol, head }) {
396
+ if (status !== 200) {
397
+ if (protocol === 'websocketoverhttp1') {
398
+ stream.destroy()
399
+ } else {
400
+ stream.close(constants.HTTP_STATUS_NOT_FOUND)
401
+ }
402
+ } else {
403
+ if (protocol === 'websocketoverhttp1') {
404
+ // @ts-ignore
405
+ this.sendHttp1Headers({ stream, header })
406
+ .then(() => {
407
+ const retObj = {
408
+ session: new Http2WebTransportSession({
409
+ stream,
410
+ isclient: false,
411
+ createParser: (
412
+ /** @type {Http2WebTransportSession} */ nativesession
413
+ ) => {
414
+ const parse = (this.capsParser = new WebSocketParser({
415
+ stream,
416
+ nativesession,
417
+ isclient: false,
418
+ initialStreamSendWindowOffset:
419
+ this.initialStreamFlowControlWindow,
420
+ initialStreamReceiveWindowOffset:
421
+ this.initialStreamFlowControlWindow,
422
+ streamShouldAutoTuneReceiveWindow:
423
+ this.streamShouldAutoTuneReceiveWindow,
424
+ streamReceiveWindowSizeLimit:
425
+ this.streamFlowControlWindowSizeLimit
426
+ }))
427
+ if (head && head.byteLength > 0) parse.parseData(head)
428
+ return parse
429
+ },
430
+ sendWindowOffset: this.sessionFlowControlWindowSizeLimit,
431
+ receiveWindowOffset: this.sessionFlowControlWindowSizeLimit,
432
+ shouldAutoTuneReceiveWindow:
433
+ this.sessionShouldAutoTuneReceiveWindow,
434
+ receiveWindowSizeLimit: this.sessionFlowControlWindowSizeLimit
435
+ }),
436
+ path: header[':path'],
437
+ header
438
+ }
439
+ // @ts-ignore
440
+ this.jsobj.onHttpWTSessionVisitor(retObj)
441
+ })
442
+ .catch((error) => {
443
+ log('sendHttp1Headers error', error)
444
+ })
445
+ } else {
446
+ const retObj = {
447
+ session: new Http2WebTransportSession({
448
+ stream,
449
+ isclient: false,
450
+ createParser: (
451
+ /** @type {Http2WebTransportSession} */ nativesession
452
+ ) => {
453
+ if (protocol !== 'websocket') {
454
+ return new Http2CapsuleParser({
455
+ stream,
456
+ nativesession,
457
+ isclient: false,
458
+ initialStreamSendWindowOffset:
459
+ this.initialStreamFlowControlWindow,
460
+ initialStreamReceiveWindowOffset:
461
+ this.initialStreamFlowControlWindow,
462
+ streamShouldAutoTuneReceiveWindow:
463
+ this.streamShouldAutoTuneReceiveWindow,
464
+ streamReceiveWindowSizeLimit:
465
+ this.streamFlowControlWindowSizeLimit
466
+ })
467
+ } else {
468
+ return (this.capsParser = new WebSocketParser({
469
+ stream,
470
+ nativesession,
471
+ isclient: false,
472
+ initialStreamSendWindowOffset:
473
+ this.initialStreamFlowControlWindow,
474
+ initialStreamReceiveWindowOffset:
475
+ this.initialStreamFlowControlWindow,
476
+ streamShouldAutoTuneReceiveWindow:
477
+ this.streamShouldAutoTuneReceiveWindow,
478
+ streamReceiveWindowSizeLimit:
479
+ this.streamFlowControlWindowSizeLimit
480
+ }))
481
+ }
482
+ },
483
+ sendWindowOffset: this.sessionFlowControlWindowSizeLimit,
484
+ receiveWindowOffset: this.sessionFlowControlWindowSizeLimit,
485
+ shouldAutoTuneReceiveWindow:
486
+ this.sessionShouldAutoTuneReceiveWindow,
487
+ receiveWindowSizeLimit: this.sessionFlowControlWindowSizeLimit
488
+ }),
489
+ path: header[':path'],
490
+ header
491
+ }
492
+ // @ts-ignore
493
+ this.jsobj.onHttpWTSessionVisitor(retObj)
494
+ }
495
+
496
+ // @ts-ignore
497
+ }
498
+ }
499
+ }