@fails-components/webtransport 1.6.8 → 1.6.9
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/http2/browser/browserparser.d.ts +12 -15
- package/dist/lib/http2/browser/browserparser.d.ts.map +1 -1
- package/dist/lib/http2/bufferHelper.d.ts +178 -0
- package/dist/lib/http2/bufferHelper.d.ts.map +1 -0
- package/dist/lib/http2/node/capsuleparser.d.ts +12 -6
- package/dist/lib/http2/node/capsuleparser.d.ts.map +1 -1
- package/dist/lib/http2/node/websocketparser.d.ts +21 -11
- package/dist/lib/http2/node/websocketparser.d.ts.map +1 -1
- package/dist/lib/http2/parserbase.d.ts +2 -7
- package/dist/lib/http2/parserbase.d.ts.map +1 -1
- package/dist/lib/http2/parserbasehttp2.d.ts +0 -25
- package/dist/lib/http2/parserbasehttp2.d.ts.map +1 -1
- package/dist/lib/http2/stream.d.ts +2 -2
- package/dist/lib/http2/stream.d.ts.map +1 -1
- package/eslint.config.js +1 -1
- package/lib/http2/browser/browserparser.js +53 -89
- package/lib/http2/bufferHelper.js +269 -0
- package/lib/http2/node/capsuleparser.js +68 -60
- package/lib/http2/node/server.js +1 -1
- package/lib/http2/node/websocketparser.js +256 -247
- package/lib/http2/parserbase.js +12 -17
- package/lib/http2/parserbasehttp2.js +12 -67
- package/lib/http2/stream.js +16 -7
- package/package.json +1 -1
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto'
|
|
2
|
-
import { ParserBase
|
|
2
|
+
import { ParserBase } from '../parserbase.js'
|
|
3
3
|
import {
|
|
4
|
-
|
|
4
|
+
advanceBufferToOffset,
|
|
5
|
+
lengthVarInt,
|
|
5
6
|
readVarInt,
|
|
6
7
|
writeVarInt,
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
writeUInt8,
|
|
9
|
+
writeUint16BE,
|
|
10
|
+
writeUint32BE,
|
|
11
|
+
writeBigInt64BE,
|
|
12
|
+
readUInt8,
|
|
13
|
+
readUint32,
|
|
14
|
+
advanceBuffer,
|
|
15
|
+
getUint8ArrayfromBuffer,
|
|
16
|
+
getUint8ArraysfromBuffer,
|
|
17
|
+
advanceBufferBy,
|
|
18
|
+
readUInt16BE,
|
|
19
|
+
readString,
|
|
20
|
+
detachReadBuffers
|
|
21
|
+
} from '../bufferHelper.js'
|
|
22
|
+
import { ParserBaseHttp2 } from '../parserbasehttp2.js'
|
|
9
23
|
import { logger } from '../../utils.js'
|
|
10
24
|
|
|
11
25
|
const log = logger(`webtransport:http2:node:websocketparser(${process?.pid})`)
|
|
@@ -14,32 +28,32 @@ const log = logger(`webtransport:http2:node:websocketparser(${process?.pid})`)
|
|
|
14
28
|
*/
|
|
15
29
|
|
|
16
30
|
/**
|
|
17
|
-
* @param{{offset: Number, buffer:
|
|
31
|
+
* @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
|
|
18
32
|
*/
|
|
19
33
|
function readByte(bs) {
|
|
20
|
-
const val =
|
|
21
|
-
bs
|
|
34
|
+
const val = readUInt8(bs)
|
|
35
|
+
advanceBuffer(bs)
|
|
22
36
|
return val
|
|
23
37
|
}
|
|
24
38
|
|
|
25
39
|
/**
|
|
26
|
-
* @param{{offset: Number, buffer:
|
|
40
|
+
* @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
|
|
27
41
|
*/
|
|
28
42
|
function readWord(bs) {
|
|
29
|
-
let val =
|
|
30
|
-
bs
|
|
31
|
-
val = (val << 8) |
|
|
32
|
-
bs
|
|
43
|
+
let val = readUInt8(bs)
|
|
44
|
+
advanceBuffer(bs)
|
|
45
|
+
val = (val << 8) | readUInt8(bs)
|
|
46
|
+
advanceBuffer(bs)
|
|
33
47
|
return val
|
|
34
48
|
}
|
|
35
49
|
|
|
36
50
|
/**
|
|
37
|
-
* @param{{offset: Number, buffer:
|
|
51
|
+
* @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
|
|
38
52
|
* @param{{offset: Number, mask: Uint8Array}} ms
|
|
39
53
|
*/
|
|
40
54
|
export function readVarIntMasked(bs, ms) {
|
|
41
|
-
let val =
|
|
42
|
-
bs
|
|
55
|
+
let val = readUInt8(bs) ^ ms.mask[ms.offset % 4]
|
|
56
|
+
advanceBuffer(bs)
|
|
43
57
|
ms.offset++
|
|
44
58
|
const prefix = val >>> 6
|
|
45
59
|
const intlength = 1 << prefix
|
|
@@ -49,49 +63,48 @@ export function readVarIntMasked(bs, ms) {
|
|
|
49
63
|
}
|
|
50
64
|
val = val & 0x3f
|
|
51
65
|
for (let i = 0; i < intlength - 1; i++) {
|
|
52
|
-
val = (val << 8) | (
|
|
53
|
-
bs
|
|
66
|
+
val = (val << 8) | (readUInt8(bs) ^ ms.mask[ms.offset % 4])
|
|
67
|
+
advanceBuffer(bs)
|
|
54
68
|
ms.offset++
|
|
55
69
|
}
|
|
56
70
|
return val
|
|
57
71
|
}
|
|
58
72
|
|
|
59
73
|
/**
|
|
60
|
-
* @param{{offset: Number, buffer:
|
|
74
|
+
* @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
|
|
61
75
|
*/
|
|
62
76
|
function readQWord(bs) {
|
|
63
|
-
let val =
|
|
64
|
-
bs
|
|
65
|
-
val = (val <<
|
|
66
|
-
bs
|
|
67
|
-
val = (val <<
|
|
68
|
-
bs
|
|
69
|
-
val = (val <<
|
|
70
|
-
bs
|
|
71
|
-
val = (val <<
|
|
72
|
-
bs
|
|
73
|
-
val = (val <<
|
|
74
|
-
bs
|
|
75
|
-
val = (val <<
|
|
76
|
-
bs
|
|
77
|
-
val = (val <<
|
|
78
|
-
bs
|
|
77
|
+
let val = BigInt(readUInt8(bs))
|
|
78
|
+
advanceBuffer(bs)
|
|
79
|
+
val = (val << 8n) | BigInt(readUInt8(bs))
|
|
80
|
+
advanceBuffer(bs)
|
|
81
|
+
val = (val << 8n) | BigInt(readUInt8(bs))
|
|
82
|
+
advanceBuffer(bs)
|
|
83
|
+
val = (val << 8n) | BigInt(readUInt8(bs))
|
|
84
|
+
advanceBuffer(bs)
|
|
85
|
+
val = (val << 8n) | BigInt(readUInt8(bs))
|
|
86
|
+
advanceBuffer(bs)
|
|
87
|
+
val = (val << 8n) | BigInt(readUInt8(bs))
|
|
88
|
+
advanceBuffer(bs)
|
|
89
|
+
val = (val << 8n) | BigInt(readUInt8(bs))
|
|
90
|
+
advanceBuffer(bs)
|
|
91
|
+
val = (val << 8n) | BigInt(readUInt8(bs))
|
|
92
|
+
advanceBuffer(bs)
|
|
79
93
|
return val
|
|
80
94
|
}
|
|
81
95
|
|
|
82
96
|
/**
|
|
83
97
|
* @param{{offset: Number, mask: Uint8Array}} ms
|
|
84
|
-
* @param{
|
|
98
|
+
* @param{Uint8Array} data
|
|
85
99
|
* @param{number} offset
|
|
86
100
|
* @param{number} length
|
|
87
101
|
*/
|
|
88
|
-
function applyMask(ms,
|
|
102
|
+
function applyMask(ms, data, offset, length) {
|
|
89
103
|
// Note offset: includes the byteOffset into the buffer
|
|
90
104
|
if (length > 24) {
|
|
91
105
|
let run = 0
|
|
92
106
|
// alignment preamble, inspired from ws bufferutil
|
|
93
|
-
|
|
94
|
-
while (run < length && (offset + run) % 8) {
|
|
107
|
+
while (run < length && (offset + run + data.byteOffset) % 8) {
|
|
95
108
|
data[run + offset] ^= ms.mask[(run + ms.offset) % 4]
|
|
96
109
|
run++
|
|
97
110
|
}
|
|
@@ -106,8 +119,8 @@ function applyMask(ms, buffer, offset, length) {
|
|
|
106
119
|
workmask[6] = ms.mask[(6 + run + ms.offset) % 4]
|
|
107
120
|
workmask[7] = ms.mask[(7 + run + ms.offset) % 4]
|
|
108
121
|
const data64 = new BigUint64Array(
|
|
109
|
-
|
|
110
|
-
run + offset,
|
|
122
|
+
data.buffer,
|
|
123
|
+
run + offset + data.byteOffset,
|
|
111
124
|
Math.floor((length - run) / 8)
|
|
112
125
|
)
|
|
113
126
|
const workmask64 = new BigUint64Array(workmask.buffer)
|
|
@@ -128,40 +141,45 @@ function applyMask(ms, buffer, offset, length) {
|
|
|
128
141
|
workmask[1] = ms.mask[(1 + ms.offset) % 4]
|
|
129
142
|
workmask[2] = ms.mask[(2 + ms.offset) % 4]
|
|
130
143
|
workmask[3] = ms.mask[(3 + ms.offset) % 4]
|
|
131
|
-
const data = new Uint8Array(buffer.buffer, offset, length)
|
|
132
144
|
for (let run = 0 /* Math.round(length / 4) * 4 */; run < length; run++) {
|
|
133
|
-
data[run] ^= workmask[run % 4]
|
|
145
|
+
data[run + offset] ^= workmask[run % 4]
|
|
134
146
|
}
|
|
135
147
|
}
|
|
136
148
|
ms.offset += length
|
|
137
149
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
bs.
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
150
|
+
/**
|
|
151
|
+
* @param{{offset: Number, mask: Uint8Array}} ms
|
|
152
|
+
* @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
|
|
153
|
+
* @param{number} length
|
|
154
|
+
*/
|
|
155
|
+
function applyMaskBuffer(ms, bs, length) {
|
|
156
|
+
let curBufOffset = bs.curBufOffset
|
|
157
|
+
let curBuf = bs.curBuf
|
|
158
|
+
let remainLen = length
|
|
159
|
+
|
|
160
|
+
while (remainLen > 0) {
|
|
161
|
+
let buf = bs.buffer[curBuf]
|
|
162
|
+
let curbufsize = Math.min(buf.byteLength - curBufOffset, remainLen)
|
|
163
|
+
applyMask(ms, buf, curBufOffset, curbufsize)
|
|
164
|
+
curBufOffset = 0
|
|
165
|
+
curBuf++
|
|
166
|
+
remainLen -= curbufsize
|
|
167
|
+
}
|
|
149
168
|
}
|
|
150
|
-
*/
|
|
151
169
|
|
|
152
170
|
/**
|
|
153
|
-
* @param{{offset: Number, buffer:
|
|
171
|
+
* @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
|
|
154
172
|
*/
|
|
155
173
|
function readMask(bs) {
|
|
156
174
|
const val = new Uint8Array(4)
|
|
157
|
-
val[0] =
|
|
158
|
-
bs
|
|
159
|
-
val[1] =
|
|
160
|
-
bs
|
|
161
|
-
val[2] =
|
|
162
|
-
bs
|
|
163
|
-
val[3] =
|
|
164
|
-
bs
|
|
175
|
+
val[0] = readUInt8(bs)
|
|
176
|
+
advanceBuffer(bs)
|
|
177
|
+
val[1] = readUInt8(bs)
|
|
178
|
+
advanceBuffer(bs)
|
|
179
|
+
val[2] = readUInt8(bs)
|
|
180
|
+
advanceBuffer(bs)
|
|
181
|
+
val[3] = readUInt8(bs)
|
|
182
|
+
advanceBuffer(bs)
|
|
165
183
|
return val
|
|
166
184
|
}
|
|
167
185
|
|
|
@@ -196,8 +214,18 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
196
214
|
streamReceiveWindowSizeLimit
|
|
197
215
|
})
|
|
198
216
|
this.mode = 's' // frame start
|
|
199
|
-
|
|
200
|
-
|
|
217
|
+
this.bufferstate = {
|
|
218
|
+
/** @type {number} */
|
|
219
|
+
offset: 0,
|
|
220
|
+
/** @type {number} */
|
|
221
|
+
size: 0,
|
|
222
|
+
/** @type {Uint8Array[]} */
|
|
223
|
+
buffer: [],
|
|
224
|
+
/** @type {number} */
|
|
225
|
+
curBuf: 0,
|
|
226
|
+
/** @type {number} */
|
|
227
|
+
curBufOffset: 0
|
|
228
|
+
}
|
|
201
229
|
/** @type {Number|undefined} */
|
|
202
230
|
this.rtype = undefined
|
|
203
231
|
|
|
@@ -206,30 +234,25 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
206
234
|
}
|
|
207
235
|
|
|
208
236
|
/**
|
|
209
|
-
* @param {
|
|
237
|
+
* @param {Uint8Array[]} data
|
|
210
238
|
*/
|
|
211
239
|
parseData(data) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
delete this.saveddata
|
|
216
|
-
}
|
|
217
|
-
const bufferstate = { offset: 0, size: cdata.length, buffer: cdata }
|
|
240
|
+
const bufferstate = this.bufferstate
|
|
241
|
+
bufferstate.buffer.push(...data)
|
|
242
|
+
bufferstate.size += data.reduce((sum, chunk) => sum + chunk.byteLength, 0)
|
|
218
243
|
while (bufferstate.size - bufferstate.offset > 0) {
|
|
219
244
|
switch (this.mode) {
|
|
220
245
|
case 's':
|
|
221
246
|
{
|
|
222
|
-
const framestart =
|
|
223
|
-
|
|
224
|
-
const
|
|
225
|
-
bufferstate.buffer.byteLength - bufferstate.offset
|
|
247
|
+
const framestart = bufferstate.offset
|
|
248
|
+
const frameCurBuf = bufferstate.curBuf
|
|
249
|
+
const frameCurBufOffset = bufferstate.curBufOffset
|
|
226
250
|
// we are at frame start
|
|
227
251
|
if (bufferstate.size < 2 + bufferstate.offset) {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
)
|
|
252
|
+
bufferstate.offset = framestart
|
|
253
|
+
bufferstate.curBuf = frameCurBuf
|
|
254
|
+
bufferstate.curBufOffset = frameCurBufOffset
|
|
255
|
+
detachReadBuffers(bufferstate)
|
|
233
256
|
return
|
|
234
257
|
}
|
|
235
258
|
let curbyte = readByte(bufferstate)
|
|
@@ -242,34 +265,58 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
242
265
|
curbyte = readByte(bufferstate)
|
|
243
266
|
const mask = (curbyte & 0x80) >>> 7
|
|
244
267
|
const mlength = mask ? 4 : 0
|
|
268
|
+
/** @type {Number|undefined} */
|
|
245
269
|
let plength = curbyte & 0x7f
|
|
246
270
|
if (plength === 126) {
|
|
247
271
|
if (bufferstate.size < 2 + bufferstate.offset) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
)
|
|
272
|
+
bufferstate.offset = framestart
|
|
273
|
+
bufferstate.curBuf = frameCurBuf
|
|
274
|
+
bufferstate.curBufOffset = frameCurBufOffset
|
|
275
|
+
detachReadBuffers(bufferstate)
|
|
253
276
|
return
|
|
254
277
|
}
|
|
255
278
|
plength = readWord(bufferstate)
|
|
256
279
|
} else if (plength === 127) {
|
|
257
280
|
if (bufferstate.size < 8 + bufferstate.offset) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
)
|
|
281
|
+
bufferstate.offset = framestart
|
|
282
|
+
bufferstate.curBuf = frameCurBuf
|
|
283
|
+
bufferstate.curBufOffset = frameCurBufOffset
|
|
284
|
+
detachReadBuffers(bufferstate)
|
|
263
285
|
return
|
|
264
286
|
}
|
|
265
|
-
|
|
287
|
+
let longlength = readQWord(bufferstate)
|
|
288
|
+
|
|
289
|
+
if (
|
|
290
|
+
typeof longlength !== 'undefined' &&
|
|
291
|
+
longlength <= BigInt(Number.MAX_SAFE_INTEGER)
|
|
292
|
+
) {
|
|
293
|
+
plength = Number(longlength)
|
|
294
|
+
} else {
|
|
295
|
+
plength = undefined
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (
|
|
299
|
+
typeof plength === 'undefined' ||
|
|
300
|
+
plength >
|
|
301
|
+
Math.max(
|
|
302
|
+
16 * Number(this.session.flowController.receiveWindowSize),
|
|
303
|
+
1000000
|
|
304
|
+
)
|
|
305
|
+
) {
|
|
306
|
+
// too long abort, could be an attack vector
|
|
307
|
+
this.session.closeConnection({
|
|
308
|
+
code: 63, // QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA, // probably the right one...
|
|
309
|
+
reason: plength
|
|
310
|
+
? 'Frame length too big :' + plength
|
|
311
|
+
: 'Frame length overflow'
|
|
312
|
+
})
|
|
313
|
+
return
|
|
266
314
|
}
|
|
267
315
|
if (bufferstate.size < mlength + bufferstate.offset) {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
)
|
|
316
|
+
bufferstate.offset = framestart
|
|
317
|
+
bufferstate.curBuf = frameCurBuf
|
|
318
|
+
bufferstate.curBufOffset = frameCurBufOffset
|
|
319
|
+
detachReadBuffers(bufferstate)
|
|
273
320
|
return
|
|
274
321
|
}
|
|
275
322
|
if (mask) {
|
|
@@ -292,22 +339,24 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
292
339
|
const length = plength
|
|
293
340
|
|
|
294
341
|
if (
|
|
342
|
+
typeof length === 'undefined' ||
|
|
295
343
|
length >
|
|
296
|
-
|
|
344
|
+
4 * Number(this.session.flowController.receiveWindowSize)
|
|
297
345
|
) {
|
|
298
346
|
// too long abort, could be an attack vector
|
|
299
347
|
this.session.closeConnection({
|
|
300
348
|
code: 63, // QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA, // probably the right one...
|
|
301
|
-
reason:
|
|
349
|
+
reason: length
|
|
350
|
+
? 'Frame length too big :' + length
|
|
351
|
+
: 'Frame length overflow'
|
|
302
352
|
})
|
|
303
353
|
return
|
|
304
354
|
} else {
|
|
305
355
|
if (bufferstate.size < length + bufferstate.offset) {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
)
|
|
356
|
+
bufferstate.offset = framestart
|
|
357
|
+
bufferstate.curBuf = frameCurBuf
|
|
358
|
+
bufferstate.curBufOffset = frameCurBufOffset
|
|
359
|
+
detachReadBuffers(bufferstate)
|
|
311
360
|
return
|
|
312
361
|
}
|
|
313
362
|
}
|
|
@@ -315,29 +364,16 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
315
364
|
case WebSocketParser.WS_CLOSE:
|
|
316
365
|
if (!this.closesend) {
|
|
317
366
|
if (this.maskcontext)
|
|
318
|
-
|
|
319
|
-
this.maskcontext,
|
|
320
|
-
bufferstate.buffer,
|
|
321
|
-
bufferstate.buffer.byteOffset + bufferstate.offset,
|
|
322
|
-
length
|
|
323
|
-
)
|
|
367
|
+
applyMaskBuffer(this.maskcontext, bufferstate, length)
|
|
324
368
|
this.sendCloseInt(
|
|
325
|
-
|
|
326
|
-
bufferstate.buffer.buffer,
|
|
327
|
-
bufferstate.buffer.byteOffset + bufferstate.offset,
|
|
328
|
-
length
|
|
329
|
-
)
|
|
369
|
+
getUint8ArrayfromBuffer(bufferstate, length)
|
|
330
370
|
)
|
|
331
371
|
let code = 0
|
|
332
372
|
let error = 'Session websocket closed'
|
|
333
373
|
if (length > 2) {
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
length
|
|
338
|
-
)
|
|
339
|
-
code = bufhelp.readUint16BE(0)
|
|
340
|
-
const terror = bufhelp.toString('utf8', 2)
|
|
374
|
+
const wbufferstate = { ...bufferstate } // working copy
|
|
375
|
+
code = readUInt16BE(wbufferstate)
|
|
376
|
+
const terror = readString(wbufferstate, length - 2)
|
|
341
377
|
let tokens = terror.split(':')
|
|
342
378
|
if (tokens.length > 1) {
|
|
343
379
|
code = parseInt(tokens[0])
|
|
@@ -345,33 +381,32 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
345
381
|
}
|
|
346
382
|
error = tokens.join(':')
|
|
347
383
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
384
|
+
if (
|
|
385
|
+
!(
|
|
386
|
+
this.session.jsobj.state === 'failed' ||
|
|
387
|
+
this.session.jsobj.state === 'closed'
|
|
388
|
+
)
|
|
389
|
+
) {
|
|
390
|
+
this.session.jsobj.onClose({
|
|
391
|
+
errorcode: code,
|
|
392
|
+
error
|
|
393
|
+
})
|
|
394
|
+
}
|
|
352
395
|
} else {
|
|
353
396
|
// just the answer
|
|
354
397
|
}
|
|
355
398
|
break
|
|
356
399
|
case WebSocketParser.WS_PING:
|
|
357
400
|
if (this.maskcontext)
|
|
358
|
-
|
|
359
|
-
this.maskcontext,
|
|
360
|
-
bufferstate.buffer,
|
|
361
|
-
bufferstate.buffer.byteOffset + bufferstate.offset,
|
|
362
|
-
length
|
|
363
|
-
)
|
|
401
|
+
applyMaskBuffer(this.maskcontext, bufferstate, length)
|
|
364
402
|
this.sendPong(
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
bufferstate.buffer.byteOffset + bufferstate.offset,
|
|
368
|
-
length
|
|
369
|
-
)
|
|
403
|
+
getUint8ArrayfromBuffer(bufferstate, length) ||
|
|
404
|
+
new Uint8Array()
|
|
370
405
|
)
|
|
371
406
|
break
|
|
372
407
|
default: // aka pong
|
|
373
408
|
}
|
|
374
|
-
bufferstate
|
|
409
|
+
advanceBufferBy(bufferstate, length)
|
|
375
410
|
} else if (
|
|
376
411
|
opcode === WebSocketParser.WS_BINARY ||
|
|
377
412
|
(opcode === WebSocketParser.WS_CONTINUE &&
|
|
@@ -384,17 +419,16 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
384
419
|
if (plength === 0) {
|
|
385
420
|
log('warning empty data frame')
|
|
386
421
|
// empty frame ?
|
|
387
|
-
bufferstate
|
|
422
|
+
advanceBufferBy(bufferstate, plength)
|
|
388
423
|
continue
|
|
389
424
|
}
|
|
390
425
|
|
|
391
426
|
if (opcode === WebSocketParser.WS_BINARY) {
|
|
392
427
|
if (bufferstate.size < 2 + bufferstate.offset) {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
)
|
|
428
|
+
bufferstate.offset = framestart
|
|
429
|
+
bufferstate.curBuf = frameCurBuf
|
|
430
|
+
bufferstate.curBufOffset = frameCurBufOffset
|
|
431
|
+
detachReadBuffers(bufferstate)
|
|
398
432
|
return
|
|
399
433
|
}
|
|
400
434
|
continuep = false
|
|
@@ -408,11 +442,10 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
408
442
|
typeof type === 'undefined' ||
|
|
409
443
|
bufferstate.size < 1 + bufferstate.offset
|
|
410
444
|
) {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
)
|
|
445
|
+
bufferstate.offset = framestart
|
|
446
|
+
bufferstate.curBuf = frameCurBuf
|
|
447
|
+
bufferstate.curBufOffset = frameCurBufOffset
|
|
448
|
+
detachReadBuffers(bufferstate)
|
|
416
449
|
return
|
|
417
450
|
}
|
|
418
451
|
this.curtype = type
|
|
@@ -439,19 +472,17 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
439
472
|
checklength = Math.min(length, 64) // stream id + some Data
|
|
440
473
|
}
|
|
441
474
|
if (bufferstate.size < checklength + bufferstate.offset) {
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
)
|
|
475
|
+
bufferstate.offset = framestart
|
|
476
|
+
bufferstate.curBuf = frameCurBuf
|
|
477
|
+
bufferstate.curBufOffset = frameCurBufOffset
|
|
478
|
+
detachReadBuffers(bufferstate)
|
|
447
479
|
return
|
|
448
480
|
}
|
|
449
481
|
// all safeguards passed now apply the mask
|
|
450
482
|
if (this.maskcontext)
|
|
451
|
-
|
|
483
|
+
applyMaskBuffer(
|
|
452
484
|
this.maskcontext,
|
|
453
|
-
bufferstate
|
|
454
|
-
bufferstate.buffer.byteOffset + bufferstate.offset,
|
|
485
|
+
bufferstate,
|
|
455
486
|
offsetend - bufferstate.offset
|
|
456
487
|
)
|
|
457
488
|
let streamid
|
|
@@ -461,30 +492,25 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
461
492
|
type !== ParserBase.WT_STREAM_WFIN
|
|
462
493
|
) {
|
|
463
494
|
if (fin) {
|
|
464
|
-
wbufferstate = bufferstate
|
|
495
|
+
wbufferstate = { ...bufferstate }
|
|
465
496
|
if (this.contframes) {
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
bufferstate.buffer.byteOffset + bufferstate.offset,
|
|
470
|
-
offsetend - bufferstate.offset
|
|
471
|
-
)
|
|
497
|
+
const newframes = getUint8ArraysfromBuffer(
|
|
498
|
+
bufferstate,
|
|
499
|
+
offsetend - bufferstate.offset
|
|
472
500
|
)
|
|
501
|
+
if (newframes) this.contframes.push(...newframes)
|
|
473
502
|
// we need to concat all buffers super
|
|
474
503
|
const nsize = this.contframes.reduce(
|
|
475
504
|
(length, val) => length + val.byteLength,
|
|
476
505
|
0
|
|
477
506
|
)
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
return offset + val.byteLength
|
|
486
|
-
}, 0)
|
|
487
|
-
wbufferstate = { offset: 0, size: nsize, buffer: jbuffer }
|
|
507
|
+
wbufferstate = {
|
|
508
|
+
offset: 0,
|
|
509
|
+
size: nsize,
|
|
510
|
+
buffer: this.contframes, // Fix me
|
|
511
|
+
curBuf: 0,
|
|
512
|
+
curBufOffset: 0
|
|
513
|
+
}
|
|
488
514
|
}
|
|
489
515
|
} else {
|
|
490
516
|
if (!this.contframes)
|
|
@@ -492,13 +518,11 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
492
518
|
* @type {Uint8Array[]}
|
|
493
519
|
*/
|
|
494
520
|
this.contframes = []
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
bufferstate.buffer.byteOffset + bufferstate.offset,
|
|
499
|
-
offsetend - bufferstate.offset
|
|
500
|
-
)
|
|
521
|
+
const newframes = getUint8ArraysfromBuffer(
|
|
522
|
+
bufferstate,
|
|
523
|
+
offsetend - bufferstate.offset
|
|
501
524
|
)
|
|
525
|
+
if (newframes) this.contframes.push(...newframes)
|
|
502
526
|
}
|
|
503
527
|
}
|
|
504
528
|
|
|
@@ -556,10 +580,8 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
556
580
|
object.recvData({
|
|
557
581
|
data:
|
|
558
582
|
offsetend - bufferstate.offset > 0
|
|
559
|
-
?
|
|
560
|
-
bufferstate
|
|
561
|
-
bufferstate.buffer.byteOffset +
|
|
562
|
-
bufferstate.offset,
|
|
583
|
+
? getUint8ArraysfromBuffer(
|
|
584
|
+
bufferstate,
|
|
563
585
|
offsetend - bufferstate.offset
|
|
564
586
|
)
|
|
565
587
|
: undefined,
|
|
@@ -612,13 +634,15 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
612
634
|
{
|
|
613
635
|
const code = readUint32(bufferstate) || 0
|
|
614
636
|
const decoder = new TextDecoder()
|
|
615
|
-
const reason =
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
637
|
+
const reason =
|
|
638
|
+
offsetend - bufferstate.offset > 0
|
|
639
|
+
? decoder.decode(
|
|
640
|
+
getUint8ArrayfromBuffer(
|
|
641
|
+
bufferstate,
|
|
642
|
+
offsetend - bufferstate.offset
|
|
643
|
+
)
|
|
644
|
+
)
|
|
645
|
+
: ''
|
|
622
646
|
this.onCloseWebTransportSession({ code, reason })
|
|
623
647
|
}
|
|
624
648
|
break
|
|
@@ -628,11 +652,11 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
628
652
|
case ParserBase.DATAGRAM:
|
|
629
653
|
if (wbufferstate) {
|
|
630
654
|
this.session.jsobj.onDatagramReceived({
|
|
631
|
-
datagram:
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
655
|
+
datagram:
|
|
656
|
+
getUint8ArrayfromBuffer(
|
|
657
|
+
wbufferstate,
|
|
658
|
+
offsetend - wbufferstate.offset
|
|
659
|
+
) || new Uint8Array(0)
|
|
636
660
|
})
|
|
637
661
|
}
|
|
638
662
|
break
|
|
@@ -643,12 +667,12 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
643
667
|
if (bufferstate.size < length + offsetbegin) {
|
|
644
668
|
this.remainlength = length + offsetbegin - bufferstate.size
|
|
645
669
|
this.mode = 'c'
|
|
646
|
-
if (streamid) {
|
|
670
|
+
if (typeof streamid !== 'undefined') {
|
|
647
671
|
this.rstreamid = streamid
|
|
648
672
|
this.rfin = type === ParserBase.WT_STREAM_WFIN
|
|
649
673
|
}
|
|
650
674
|
}
|
|
651
|
-
bufferstate
|
|
675
|
+
advanceBufferToOffset(bufferstate, offsetend)
|
|
652
676
|
} else {
|
|
653
677
|
const length = plength
|
|
654
678
|
if (bufferstate.offset + length > bufferstate.size) {
|
|
@@ -656,9 +680,9 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
656
680
|
this.rstreamid = undefined
|
|
657
681
|
this.remainlength =
|
|
658
682
|
bufferstate.offset + length - bufferstate.size
|
|
659
|
-
bufferstate
|
|
683
|
+
advanceBufferToOffset(bufferstate, bufferstate.size)
|
|
660
684
|
} else {
|
|
661
|
-
bufferstate
|
|
685
|
+
advanceBufferBy(bufferstate, length)
|
|
662
686
|
}
|
|
663
687
|
}
|
|
664
688
|
}
|
|
@@ -669,7 +693,7 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
669
693
|
bufferstate.size - bufferstate.offset,
|
|
670
694
|
this.remainlength
|
|
671
695
|
)
|
|
672
|
-
if (this.rstreamid) {
|
|
696
|
+
if (typeof this.rstreamid !== 'undefined') {
|
|
673
697
|
// not in j mode
|
|
674
698
|
// TODO submitData
|
|
675
699
|
const object = this.wtstreams.get(this.rstreamid)
|
|
@@ -679,26 +703,17 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
679
703
|
if (object) {
|
|
680
704
|
if (fin) object.onFin()
|
|
681
705
|
if (this.maskcontext)
|
|
682
|
-
|
|
683
|
-
this.maskcontext,
|
|
684
|
-
bufferstate.buffer,
|
|
685
|
-
bufferstate.buffer.byteOffset + bufferstate.offset,
|
|
686
|
-
clength
|
|
687
|
-
)
|
|
706
|
+
applyMaskBuffer(this.maskcontext, bufferstate, clength)
|
|
688
707
|
// TODO submit data
|
|
689
708
|
object.recvData({
|
|
690
|
-
data:
|
|
691
|
-
bufferstate.buffer.buffer,
|
|
692
|
-
bufferstate.buffer.byteOffset + bufferstate.offset,
|
|
693
|
-
clength
|
|
694
|
-
),
|
|
709
|
+
data: getUint8ArraysfromBuffer(bufferstate, clength),
|
|
695
710
|
fin
|
|
696
711
|
})
|
|
697
712
|
}
|
|
698
713
|
}
|
|
699
714
|
|
|
700
715
|
this.remainlength = this.remainlength - clength
|
|
701
|
-
bufferstate
|
|
716
|
+
advanceBufferBy(bufferstate, clength)
|
|
702
717
|
if (this.remainlength === 0) {
|
|
703
718
|
this.maskcontext = undefined
|
|
704
719
|
this.mode = 's'
|
|
@@ -709,6 +724,7 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
709
724
|
break
|
|
710
725
|
}
|
|
711
726
|
}
|
|
727
|
+
detachReadBuffers(bufferstate)
|
|
712
728
|
}
|
|
713
729
|
|
|
714
730
|
/**
|
|
@@ -754,8 +770,14 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
754
770
|
headlength += 2
|
|
755
771
|
}
|
|
756
772
|
|
|
757
|
-
const cdata =
|
|
758
|
-
const bufferstate = {
|
|
773
|
+
const cdata = new Uint8Array(headlength)
|
|
774
|
+
const bufferstate = {
|
|
775
|
+
offset: 0,
|
|
776
|
+
size: cdata.length,
|
|
777
|
+
buffer: [cdata],
|
|
778
|
+
curBuf: 0,
|
|
779
|
+
curBufOffset: 0
|
|
780
|
+
}
|
|
759
781
|
const maskstate = this.writeHeader(bufferstate, {
|
|
760
782
|
opcode: WebSocketParser.WS_BINARY,
|
|
761
783
|
plength,
|
|
@@ -768,19 +790,8 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
768
790
|
for (const ind in headerVints) writeVarInt(bufferstate, headerVints[ind])
|
|
769
791
|
const endmask = bufferstate.offset
|
|
770
792
|
if (maskstate) {
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
bufferstate.buffer,
|
|
774
|
-
bufferstate.offset + bufferstate.buffer.byteOffset,
|
|
775
|
-
endmask - beginmask
|
|
776
|
-
)
|
|
777
|
-
if (payload)
|
|
778
|
-
applyMask(
|
|
779
|
-
maskstate,
|
|
780
|
-
Buffer.from(payload.buffer, payload.byteOffset, payload.byteLength),
|
|
781
|
-
payload.byteOffset,
|
|
782
|
-
payload.byteLength
|
|
783
|
-
)
|
|
793
|
+
applyMaskBuffer(maskstate, bufferstate, endmask - beginmask)
|
|
794
|
+
if (payload) applyMask(maskstate, payload, 0, payload.byteLength)
|
|
784
795
|
}
|
|
785
796
|
let blocked = false
|
|
786
797
|
if (payload) {
|
|
@@ -795,12 +806,12 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
795
806
|
}
|
|
796
807
|
|
|
797
808
|
/**
|
|
798
|
-
* @param
|
|
809
|
+
* @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
|
|
799
810
|
* @param {{ opcode: number; plength: number; mask: number; }} args
|
|
800
811
|
*/
|
|
801
812
|
writeHeader(bs, { opcode, plength, mask }) {
|
|
802
|
-
bs
|
|
803
|
-
bs
|
|
813
|
+
writeUInt8(bs, 0x80 | (opcode & 0x0f))
|
|
814
|
+
advanceBuffer(bs)
|
|
804
815
|
let splength = plength
|
|
805
816
|
if (plength > 0xffff) {
|
|
806
817
|
splength = 127
|
|
@@ -808,20 +819,17 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
808
819
|
splength = 126
|
|
809
820
|
}
|
|
810
821
|
|
|
811
|
-
bs
|
|
812
|
-
bs
|
|
822
|
+
writeUInt8(bs, (mask && 0x80) | (splength & 0x7f))
|
|
823
|
+
advanceBuffer(bs)
|
|
813
824
|
if (plength > 0xffff) {
|
|
814
|
-
|
|
815
|
-
bs.offset += 8
|
|
825
|
+
writeBigInt64BE(bs, BigInt(plength))
|
|
816
826
|
} else if (plength > 125) {
|
|
817
|
-
|
|
818
|
-
bs.offset += 2
|
|
827
|
+
writeUint16BE(bs, plength)
|
|
819
828
|
}
|
|
820
829
|
let maskstate
|
|
821
830
|
if (mask) {
|
|
822
831
|
maskstate = { offset: 0, mask: randomBytes(4) }
|
|
823
|
-
|
|
824
|
-
bs.offset += 4
|
|
832
|
+
writeUint32BE(bs, maskstate.mask.readUInt32BE(0))
|
|
825
833
|
}
|
|
826
834
|
return maskstate
|
|
827
835
|
}
|
|
@@ -842,8 +850,14 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
842
850
|
} else if (plength > 125) {
|
|
843
851
|
headlength += 2
|
|
844
852
|
}
|
|
845
|
-
const cdata =
|
|
846
|
-
const bufferstate = {
|
|
853
|
+
const cdata = new Uint8Array(headlength)
|
|
854
|
+
const bufferstate = {
|
|
855
|
+
offset: 0,
|
|
856
|
+
size: cdata.length,
|
|
857
|
+
buffer: [cdata],
|
|
858
|
+
curBuf: 0,
|
|
859
|
+
curBufOffset: 0
|
|
860
|
+
}
|
|
847
861
|
const maskstate = this.writeHeader(bufferstate, { opcode, plength, mask })
|
|
848
862
|
|
|
849
863
|
if (bufferstate.offset !== headlength)
|
|
@@ -851,12 +865,7 @@ export class WebSocketParser extends ParserBaseHttp2 {
|
|
|
851
865
|
|
|
852
866
|
let blocked = !this.stream.write(cdata)
|
|
853
867
|
if (maskstate && payload)
|
|
854
|
-
applyMask(
|
|
855
|
-
maskstate,
|
|
856
|
-
Buffer.from(payload.buffer, payload.byteOffset, payload.byteLength),
|
|
857
|
-
0,
|
|
858
|
-
payload.byteLength
|
|
859
|
-
)
|
|
868
|
+
applyMask(maskstate, payload, 0, payload.byteLength)
|
|
860
869
|
if (payload) blocked = !this.stream.write(payload) || blocked
|
|
861
870
|
// do something if blocked
|
|
862
871
|
if (blocked) this.blocked = true
|