@fails-components/webtransport 0.3.0 → 1.0.0-rc.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 (163) 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 -6
  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/testinone.js +2854 -0
  44. package/test/unidirectional-streams.spec.js +20 -4
  45. package/CMakeLists.txt +0 -991
  46. package/LICENSE.chromium +0 -27
  47. package/LICENSE.envoy +0 -207
  48. package/build.js +0 -313
  49. package/dist/lib/client.d.ts +0 -78
  50. package/dist/lib/client.d.ts.map +0 -1
  51. package/dist/lib/dom.d.ts +0 -87
  52. package/dist/lib/dom.d.ts.map +0 -1
  53. package/dist/lib/error.d.ts +0 -8
  54. package/dist/lib/error.d.ts.map +0 -1
  55. package/dist/lib/event-loop.d.ts +0 -33
  56. package/dist/lib/event-loop.d.ts.map +0 -1
  57. package/dist/lib/index.d.ts +0 -79
  58. package/dist/lib/index.d.ts.map +0 -1
  59. package/dist/lib/native.d.ts +0 -2
  60. package/dist/lib/native.d.ts.map +0 -1
  61. package/dist/lib/server.d.ts +0 -92
  62. package/dist/lib/server.d.ts.map +0 -1
  63. package/dist/lib/session.d.ts +0 -298
  64. package/dist/lib/session.d.ts.map +0 -1
  65. package/dist/lib/stream.d.ts +0 -135
  66. package/dist/lib/stream.d.ts.map +0 -1
  67. package/dist/lib/transport.d.ts +0 -34
  68. package/dist/lib/transport.d.ts.map +0 -1
  69. package/dist/lib/types.d.ts +0 -212
  70. package/dist/lib/types.d.ts.map +0 -1
  71. package/dist/lib/utils.d.ts +0 -11
  72. package/dist/lib/utils.d.ts.map +0 -1
  73. package/dist/lib/webtransport.d.ts +0 -47
  74. package/dist/lib/webtransport.d.ts.map +0 -1
  75. package/dist/test/bidirectional-streams.spec.d.ts +0 -5
  76. package/dist/test/bidirectional-streams.spec.d.ts.map +0 -1
  77. package/dist/test/datagrams.spec.d.ts +0 -5
  78. package/dist/test/datagrams.spec.d.ts.map +0 -1
  79. package/dist/test/event-loop.node.d.ts +0 -2
  80. package/dist/test/event-loop.node.d.ts.map +0 -1
  81. package/dist/test/fixtures/certificate.d.ts +0 -21
  82. package/dist/test/fixtures/certificate.d.ts.map +0 -1
  83. package/dist/test/fixtures/chai.d.ts +0 -2
  84. package/dist/test/fixtures/chai.d.ts.map +0 -1
  85. package/dist/test/fixtures/known-bytes.d.ts +0 -6
  86. package/dist/test/fixtures/known-bytes.d.ts.map +0 -1
  87. package/dist/test/fixtures/p-timeout.d.ts +0 -8
  88. package/dist/test/fixtures/p-timeout.d.ts.map +0 -1
  89. package/dist/test/fixtures/read-cert-hash.d.ts +0 -6
  90. package/dist/test/fixtures/read-cert-hash.d.ts.map +0 -1
  91. package/dist/test/fixtures/read-stream.d.ts +0 -19
  92. package/dist/test/fixtures/read-stream.d.ts.map +0 -1
  93. package/dist/test/fixtures/reader-value.d.ts +0 -22
  94. package/dist/test/fixtures/reader-value.d.ts.map +0 -1
  95. package/dist/test/fixtures/server.d.ts +0 -5
  96. package/dist/test/fixtures/server.d.ts.map +0 -1
  97. package/dist/test/fixtures/webtransport.browser.d.ts +0 -3
  98. package/dist/test/fixtures/webtransport.browser.d.ts.map +0 -1
  99. package/dist/test/fixtures/webtransport.d.ts +0 -3
  100. package/dist/test/fixtures/webtransport.d.ts.map +0 -1
  101. package/dist/test/fixtures/write-stream.d.ts +0 -10
  102. package/dist/test/fixtures/write-stream.d.ts.map +0 -1
  103. package/dist/test/index.d.ts +0 -2
  104. package/dist/test/index.d.ts.map +0 -1
  105. package/dist/test/session.spec.d.ts +0 -5
  106. package/dist/test/session.spec.d.ts.map +0 -1
  107. package/dist/test/unidirectional-streams.spec.d.ts +0 -2
  108. package/dist/test/unidirectional-streams.spec.d.ts.map +0 -1
  109. package/failslogolicensereadme.txt +0 -4
  110. package/lib/event-loop.js +0 -88
  111. package/lib/native.js +0 -28
  112. package/lib/transport.js +0 -82
  113. package/platform/icufix/fakedata.cpp +0 -8
  114. package/platform/quiche/quic/core/io/socket_win.inc +0 -3
  115. package/platform/quiche_platform_impl/quiche_bug_tracker_impl.h +0 -7
  116. package/platform/quiche_platform_impl/quiche_client_stats_impl.h +0 -7
  117. package/platform/quiche_platform_impl/quiche_command_line_flags_impl.h +0 -7
  118. package/platform/quiche_platform_impl/quiche_containers_impl.h +0 -7
  119. package/platform/quiche_platform_impl/quiche_event_loop_impl.h +0 -7
  120. package/platform/quiche_platform_impl/quiche_export_impl.h +0 -6
  121. package/platform/quiche_platform_impl/quiche_flag_utils_impl.h +0 -11
  122. package/platform/quiche_platform_impl/quiche_flags_impl.h +0 -8
  123. package/platform/quiche_platform_impl/quiche_iovec_impl.h +0 -10
  124. package/platform/quiche_platform_impl/quiche_logging_impl.h +0 -21
  125. package/platform/quiche_platform_impl/quiche_mem_slice_impl.h +0 -2
  126. package/platform/quiche_platform_impl/quiche_mutex_impl.h +0 -8
  127. package/platform/quiche_platform_impl/quiche_prefetch_impl.h +0 -11
  128. package/platform/quiche_platform_impl/quiche_reference_counted_impl.h +0 -16
  129. package/platform/quiche_platform_impl/quiche_server_stats_impl.h +0 -7
  130. package/platform/quiche_platform_impl/quiche_stack_trace_impl.h +0 -12
  131. package/platform/quiche_platform_impl/quiche_stream_buffer_allocator_impl.h +0 -8
  132. package/platform/quiche_platform_impl/quiche_testvalue_impl.h +0 -1
  133. package/platform/quiche_platform_impl/quiche_thread_local_impl.h +0 -6
  134. package/platform/quiche_platform_impl/quiche_time_utils_impl.h +0 -13
  135. package/platform/quiche_platform_impl/quiche_udp_socket_platform_impl.h +0 -39
  136. package/src/http3backendresponse.cc +0 -36
  137. package/src/http3backendresponse.h +0 -109
  138. package/src/http3client.cc +0 -1529
  139. package/src/http3client.h +0 -557
  140. package/src/http3clientsession.cc +0 -65
  141. package/src/http3clientsession.h +0 -60
  142. package/src/http3clientstream.cc +0 -52
  143. package/src/http3clientstream.h +0 -42
  144. package/src/http3dispatcher.cc +0 -62
  145. package/src/http3dispatcher.h +0 -57
  146. package/src/http3eventloop.cc +0 -1107
  147. package/src/http3eventloop.h +0 -316
  148. package/src/http3server.cc +0 -514
  149. package/src/http3server.h +0 -151
  150. package/src/http3serverbackend.cc +0 -105
  151. package/src/http3serverbackend.h +0 -98
  152. package/src/http3serversession.cc +0 -123
  153. package/src/http3serversession.h +0 -95
  154. package/src/http3serverstream.cc +0 -463
  155. package/src/http3serverstream.h +0 -114
  156. package/src/http3sessioncache.cc +0 -85
  157. package/src/http3sessioncache.h +0 -59
  158. package/src/http3wtsessionvisitor.cc +0 -46
  159. package/src/http3wtsessionvisitor.h +0 -397
  160. package/src/http3wtstreamvisitor.cc +0 -155
  161. package/src/http3wtstreamvisitor.h +0 -404
  162. package/test/event-loop.node.js +0 -24
  163. 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
+ }