@fails-components/webtransport 1.6.7 → 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.
@@ -1,72 +1,17 @@
1
- import { ParserBase, lengthVarInt } from '../parserbase.js'
1
+ import { ParserBase } from '../parserbase.js'
2
+ import {
3
+ lengthVarInt,
4
+ readUint32,
5
+ readVarInt,
6
+ writeVarInt,
7
+ getUint8ArrayfromBuffer,
8
+ getUint8ArraysfromBuffer,
9
+ advanceBufferToOffset,
10
+ detachReadBuffers
11
+ } from '../bufferHelper.js'
2
12
  import { logger } from '../../utils.js'
3
13
 
4
14
  const log = logger(`webtransport:http2:browserparser`)
5
- /**
6
- * @param{{offset: Number, buffer: Uint8Array, size: Number}} bs
7
- */
8
- function readVarInt(bs) {
9
- if (bs.offset + 1 > bs.size) return undefined
10
- let val = BigInt(bs.buffer[bs.offset])
11
- bs.offset++
12
- const prefix = Number(val) >>> 6
13
- const intlength = 1 << prefix
14
-
15
- if (bs.offset + intlength - 1 > bs.size) {
16
- return undefined
17
- }
18
- val = val & 0x3fn
19
- for (let i = 0; i < intlength - 1; i++) {
20
- val = (val << 8n) | BigInt(bs.buffer[bs.offset])
21
- bs.offset++
22
- }
23
- return val
24
- }
25
-
26
- /**
27
- * @param{{offset: Number, buffer: Uint8Array, size: Number}} bs
28
- */
29
- function readUint32(bs) {
30
- if (bs.offset + 4 > bs.size) return undefined
31
- let val = bs.buffer[bs.offset]
32
- bs.offset++
33
- val = (val << 8) | bs.buffer[bs.offset]
34
- bs.offset++
35
- val = (val << 8) | bs.buffer[bs.offset]
36
- bs.offset++
37
- val = (val << 8) | bs.buffer[bs.offset]
38
- bs.offset++
39
- return val
40
- }
41
-
42
- /**
43
- * @param{{offset: Number, buffer: Uint8Array, size: Number}} bs
44
- * @param{Number|bigint} int
45
- */
46
- export function writeVarInt(bs, int) {
47
- let numbytes = 8n
48
- let msb = 0xc0n
49
- const bint = BigInt(int)
50
- if (bint < 64n) {
51
- numbytes = 1n
52
- msb = 0x0n
53
- } else if (bint < 16384n) {
54
- numbytes = 2n
55
- msb = 0x40n
56
- } else if (bint < 1073741824n) {
57
- numbytes = 4n
58
- msb = 0x80n
59
- }
60
- bs.buffer[bs.offset] = Number(
61
- msb | ((bint >> ((numbytes - 1n) * 8n)) & 0xffn)
62
- )
63
- bs.offset++
64
-
65
- for (let i = numbytes - 2n; i >= 0n; i--) {
66
- bs.buffer[bs.offset] = Number((bint >> (i * 8n)) & 0xffn)
67
- bs.offset++
68
- }
69
- }
70
15
 
71
16
  export class BrowserParser extends ParserBase {
72
17
  static WS_CONTINUE = 0x0
@@ -98,8 +43,18 @@ export class BrowserParser extends ParserBase {
98
43
  streamReceiveWindowSizeLimit
99
44
  })
100
45
  this.ws = ws
101
- /** @type {Buffer|undefined} */
102
- this.saveddata = undefined
46
+ this.bufferstate = {
47
+ /** @type {number} */
48
+ offset: 0,
49
+ /** @type {number} */
50
+ size: 0,
51
+ /** @type {Uint8Array[]} */
52
+ buffer: [],
53
+ /** @type {number} */
54
+ curBuf: 0,
55
+ /** @type {number} */
56
+ curBufOffset: 0
57
+ }
103
58
  /** @type {Number|undefined} */
104
59
  this.rtype = undefined
105
60
 
@@ -108,7 +63,7 @@ export class BrowserParser extends ParserBase {
108
63
  this.ws.addEventListener('message', (event) => {
109
64
  if (event.data instanceof ArrayBuffer) {
110
65
  // binary frame
111
- this.parseData(new Uint8Array(event.data, 0, event.data.byteLength))
66
+ this.parseData([new Uint8Array(event.data, 0, event.data.byteLength)])
112
67
  } else {
113
68
  // text frame
114
69
  log('Illegal text frame', event.data)
@@ -117,10 +72,12 @@ export class BrowserParser extends ParserBase {
117
72
  }
118
73
 
119
74
  /**
120
- * @param {Uint8Array} data
75
+ * @param {Uint8Array[]} data
121
76
  */
122
77
  parseData(data) {
123
- const bufferstate = { offset: 0, size: data.byteLength, buffer: data }
78
+ const bufferstate = this.bufferstate
79
+ bufferstate.buffer.push(...data)
80
+ bufferstate.size += data.reduce((sum, chunk) => sum + chunk.byteLength, 0)
124
81
 
125
82
  const offsetend = bufferstate.size
126
83
 
@@ -175,9 +132,8 @@ export class BrowserParser extends ParserBase {
175
132
  const fin = type === ParserBase.WT_STREAM_WFIN
176
133
  if (fin) object.onFin()
177
134
  object.recvData({
178
- data: new Uint8Array(
179
- bufferstate.buffer.buffer,
180
- bufferstate.buffer.byteOffset + bufferstate.offset,
135
+ data: getUint8ArraysfromBuffer(
136
+ bufferstate,
181
137
  offsetend - bufferstate.offset
182
138
  ),
183
139
  fin
@@ -224,13 +180,15 @@ export class BrowserParser extends ParserBase {
224
180
  {
225
181
  const code = readUint32(bufferstate) || 0
226
182
  const decoder = new TextDecoder()
227
- const reason = decoder.decode(
228
- new Uint8Array(
229
- bufferstate.buffer.buffer,
230
- bufferstate.buffer.byteOffset + bufferstate.offset,
231
- offsetend - bufferstate.offset
232
- )
233
- )
183
+ const reason =
184
+ offsetend - bufferstate.offset > 0
185
+ ? decoder.decode(
186
+ getUint8ArrayfromBuffer(
187
+ bufferstate,
188
+ offsetend - bufferstate.offset
189
+ )
190
+ )
191
+ : ''
234
192
  this.onCloseWebTransportSession({ code, reason })
235
193
  }
236
194
  break
@@ -239,19 +197,19 @@ export class BrowserParser extends ParserBase {
239
197
  break
240
198
  case ParserBase.DATAGRAM:
241
199
  this.session.jsobj.onDatagramReceived({
242
- datagram: new Uint8Array(
243
- bufferstate.buffer.buffer,
244
- bufferstate.buffer.byteOffset + bufferstate.offset,
245
- offsetend - bufferstate.offset
246
- )
200
+ datagram:
201
+ getUint8ArrayfromBuffer(
202
+ bufferstate,
203
+ offsetend - bufferstate.offset
204
+ ) || new Uint8Array(0)
247
205
  })
248
206
 
249
207
  break
250
208
  default:
251
209
  // do nothing
252
210
  }
253
-
254
- bufferstate.offset = offsetend
211
+ advanceBufferToOffset(bufferstate, offsetend)
212
+ detachReadBuffers(bufferstate)
255
213
  }
256
214
 
257
215
  /**
@@ -265,7 +223,13 @@ export class BrowserParser extends ParserBase {
265
223
  if (payload) plength += payload.byteLength
266
224
 
267
225
  const cdata = new Uint8Array(plength)
268
- const bufferstate = { offset: 0, size: cdata.length, buffer: cdata }
226
+ const bufferstate = {
227
+ offset: 0,
228
+ size: cdata.length,
229
+ buffer: [cdata],
230
+ curBuf: 0,
231
+ curBufOffset: 0
232
+ }
269
233
  writeVarInt(bufferstate, type)
270
234
  for (const ind in headerVints) writeVarInt(bufferstate, headerVints[ind])
271
235
  const dest = new Uint8Array(cdata.buffer, cdata.byteOffset + hlength)
@@ -0,0 +1,269 @@
1
+ /**
2
+ * @param{Number|bigint} int
3
+ * @returns {Number}
4
+ */
5
+
6
+ export function lengthVarInt(int) {
7
+ if (BigInt(int) < 64n) return 1
8
+ if (BigInt(int) < 16384n) return 2
9
+ if (BigInt(int) < 1073741824n) return 4
10
+ /* if (BigInt(int) < 4611686018427387904 ) */
11
+ return 8
12
+ }
13
+
14
+ /**
15
+ * @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
16
+ */
17
+ export function advanceBuffer(bs) {
18
+ bs.curBufOffset++
19
+ if (bs.curBufOffset === bs.buffer[bs.curBuf].byteLength) {
20
+ bs.curBufOffset = 0
21
+ bs.curBuf++
22
+ }
23
+ bs.offset++
24
+ }
25
+
26
+ /**
27
+ * @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
28
+ * @param{number} offset
29
+ */
30
+ export function advanceBufferToOffset(bs, offset) {
31
+ if (bs.offset >= offset) return
32
+ let remainConsume = offset - bs.offset
33
+ while (remainConsume > 0) {
34
+ const curBufferSpace = bs.buffer[bs.curBuf].byteLength - bs.curBufOffset
35
+ if (curBufferSpace > remainConsume) {
36
+ bs.curBufOffset += remainConsume
37
+ bs.offset += remainConsume
38
+ return // done last buffer to touch
39
+ }
40
+ remainConsume -= curBufferSpace
41
+ bs.offset += curBufferSpace
42
+ bs.curBufOffset = 0
43
+ bs.curBuf++
44
+ }
45
+ }
46
+
47
+ /**
48
+ * @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
49
+ * @param{number} length
50
+ */
51
+ export function advanceBufferBy(bs, length) {
52
+ return advanceBufferToOffset(bs, bs.offset + length)
53
+ }
54
+
55
+ /**
56
+ * @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
57
+ */
58
+ export function detachReadBuffers(bs) {
59
+ while (bs.buffer.length > 1 && bs.buffer[0].byteLength < bs.offset) {
60
+ const curBuf = bs.buffer.shift()
61
+ // @ts-ignore
62
+ const curBufSize = curBuf.byteLength
63
+ bs.size -= curBufSize
64
+ bs.offset -= curBufSize
65
+ bs.curBuf--
66
+ }
67
+ }
68
+
69
+ /**
70
+ * @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
71
+ * @param {number} length
72
+ */
73
+ export function getUint8ArraysfromBuffer(bs, length) {
74
+ /** @type {Uint8Array[]} */
75
+ const retArr = new Array()
76
+ let remainLen = length
77
+ let curBufOffset = bs.curBufOffset // note this does not advance the buffer
78
+ let curBuf = bs.curBuf
79
+ while (remainLen > 0) {
80
+ const curbuf = bs.buffer[curBuf]
81
+ const avail = Math.min(curbuf.byteLength - curBufOffset, remainLen)
82
+ if (avail !== 0) {
83
+ retArr.push(
84
+ new Uint8Array(curbuf.buffer, curbuf.byteOffset + curBufOffset, avail)
85
+ )
86
+ }
87
+ curBufOffset = 0
88
+ curBuf++
89
+ remainLen -= avail
90
+ }
91
+ if (retArr.length === 0) return undefined
92
+ return retArr
93
+ }
94
+ /**
95
+ * @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
96
+ * @param {number} length
97
+ */
98
+ export function getUint8ArrayfromBuffer(bs, length) {
99
+ const chunks = getUint8ArraysfromBuffer(bs, length)
100
+
101
+ if (typeof chunks === 'undefined') return undefined
102
+
103
+ const totalLength = chunks.reduce((acc, c) => acc + c.length, 0)
104
+ const result = new Uint8Array(totalLength)
105
+
106
+ let offset = 0
107
+ for (let i = 0; i < chunks.length; i++) {
108
+ result.set(chunks[i], offset)
109
+ offset += chunks[i].length
110
+ }
111
+ return result
112
+ }
113
+
114
+ /**
115
+ * @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
116
+ */
117
+
118
+ export function readUInt8(bs) {
119
+ return bs.buffer[bs.curBuf][bs.curBufOffset]
120
+ }
121
+
122
+ /**
123
+ * @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
124
+ * @returns {number}
125
+ */
126
+ export function readUInt16BE(bs) {
127
+ const highByte = readUInt8(bs)
128
+ advanceBuffer(bs)
129
+ const lowByte = readUInt8(bs)
130
+ advanceBuffer(bs)
131
+
132
+ return (highByte << 8) | lowByte
133
+ }
134
+
135
+ /**
136
+ * @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
137
+ * @param {number} length
138
+ * @returns {string}
139
+ */
140
+ export function readString(bs, length) {
141
+ const data = getUint8ArrayfromBuffer(bs, length)
142
+ advanceBufferBy(bs, length)
143
+ const utf8decoder = new TextDecoder('utf-8')
144
+ return utf8decoder.decode(data)
145
+ }
146
+
147
+ /**
148
+ * @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
149
+ * @param{Number} value
150
+ */
151
+ export function writeUInt8(bs, value) {
152
+ bs.buffer[bs.curBuf][bs.curBufOffset] = value
153
+ }
154
+
155
+ /**
156
+ * @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
157
+ */
158
+ export function readVarInt(bs) {
159
+ if (bs.offset + 1 > bs.size) return undefined
160
+
161
+ let val = BigInt(readUInt8(bs))
162
+ advanceBuffer(bs)
163
+ const prefix = Number(val) >>> 6
164
+ const intlength = 1 << prefix
165
+
166
+ if (bs.offset + intlength - 1 > bs.size) {
167
+ return undefined
168
+ }
169
+ val = val & 0x3fn
170
+ for (let i = 0; i < intlength - 1; i++) {
171
+ val = (val << 8n) | BigInt(readUInt8(bs))
172
+ advanceBuffer(bs)
173
+ }
174
+ return val
175
+ }
176
+ /**
177
+ * @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
178
+ */
179
+ export function readUint32(bs) {
180
+ if (bs.offset + 4 > bs.size) return undefined
181
+ let val = readUInt8(bs)
182
+ advanceBuffer(bs)
183
+ val = (val << 8) | readUInt8(bs)
184
+ advanceBuffer(bs)
185
+ val = (val << 8) | readUInt8(bs)
186
+ advanceBuffer(bs)
187
+ val = (val << 8) | readUInt8(bs)
188
+ advanceBuffer(bs)
189
+ return val
190
+ }
191
+
192
+ /**
193
+ * @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
194
+ * @param{number} value
195
+ */
196
+ export function writeUint16BE(bs, value) {
197
+ writeUInt8(bs, (value >> 8) & 0xff)
198
+ advanceBuffer(bs)
199
+ writeUInt8(bs, value & 0xff)
200
+ advanceBuffer(bs)
201
+ }
202
+
203
+ /**
204
+ * @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
205
+ * @param{number} value
206
+ */
207
+ export function writeUint32BE(bs, value) {
208
+ writeUInt8(bs, (value >>> 24) & 0xff)
209
+ advanceBuffer(bs)
210
+ writeUInt8(bs, (value >>> 16) & 0xff)
211
+ advanceBuffer(bs)
212
+ writeUInt8(bs, (value >>> 8) & 0xff)
213
+ advanceBuffer(bs)
214
+ writeUInt8(bs, value & 0xff)
215
+ advanceBuffer(bs)
216
+ }
217
+
218
+ /**
219
+ * @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
220
+ * @param{bigint} value
221
+ */
222
+ export function writeBigInt64BE(bs, value) {
223
+ const val = BigInt(value)
224
+
225
+ writeUInt8(bs, Number((val >> 56n) & 0xffn))
226
+ advanceBuffer(bs)
227
+ writeUInt8(bs, Number((val >> 48n) & 0xffn))
228
+ advanceBuffer(bs)
229
+ writeUInt8(bs, Number((val >> 40n) & 0xffn))
230
+ advanceBuffer(bs)
231
+ writeUInt8(bs, Number((val >> 32n) & 0xffn))
232
+ advanceBuffer(bs)
233
+ writeUInt8(bs, Number((val >> 24n) & 0xffn))
234
+ advanceBuffer(bs)
235
+ writeUInt8(bs, Number((val >> 16n) & 0xffn))
236
+ advanceBuffer(bs)
237
+ writeUInt8(bs, Number((val >> 8n) & 0xffn))
238
+ advanceBuffer(bs)
239
+ writeUInt8(bs, Number(val & 0xffn))
240
+ advanceBuffer(bs)
241
+ }
242
+
243
+ /**
244
+ * @param{{offset: Number, buffer: Uint8Array[], size: Number, curBuf: Number, curBufOffset: Number}} bs
245
+ * @param{Number|bigint} int
246
+ */
247
+
248
+ export function writeVarInt(bs, int) {
249
+ let numbytes = 8n
250
+ let msb = 0xc0n
251
+ const bint = BigInt(int)
252
+ if (bint < 64) {
253
+ numbytes = 1n
254
+ msb = 0x0n
255
+ } else if (bint < 16384) {
256
+ numbytes = 2n
257
+ msb = 0x40n
258
+ } else if (bint < 1073741824) {
259
+ numbytes = 4n
260
+ msb = 0x80n
261
+ }
262
+ writeUInt8(bs, Number(msb | ((bint >> ((numbytes - 1n) * 8n)) & 0xffn)))
263
+ advanceBuffer(bs)
264
+
265
+ for (let i = numbytes - 2n; i >= 0; i--) {
266
+ writeUInt8(bs, Number((bint >> (i * 8n)) & 0xffn))
267
+ advanceBuffer(bs)
268
+ }
269
+ }