@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.
@@ -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
+ }
@@ -1,10 +1,15 @@
1
+ import { ParserBaseHttp2 } from '../parserbasehttp2.js'
1
2
  import {
2
- ParserBaseHttp2,
3
+ lengthVarInt,
3
4
  readVarInt,
4
5
  readUint32,
5
- writeVarInt
6
- } from '../parserbasehttp2.js'
7
- import { lengthVarInt } from '../parserbase.js'
6
+ writeVarInt,
7
+ advanceBufferToOffset,
8
+ getUint8ArrayfromBuffer,
9
+ getUint8ArraysfromBuffer,
10
+ advanceBufferBy,
11
+ detachReadBuffers
12
+ } from '../bufferHelper.js'
8
13
 
9
14
  export class Http2CapsuleParser extends ParserBaseHttp2 {
10
15
  /**
@@ -31,37 +36,43 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
31
36
  streamReceiveWindowSizeLimit
32
37
  })
33
38
  this.mode = 's' // capsule start
34
- /** @type {Buffer|undefined} */
35
- this.saveddata = undefined
39
+ this.bufferstate = {
40
+ /** @type {number} */
41
+ offset: 0,
42
+ /** @type {number} */
43
+ size: 0,
44
+ /** @type {Uint8Array[]} */
45
+ buffer: [],
46
+ /** @type {number} */
47
+ curBuf: 0,
48
+ /** @type {number} */
49
+ curBufOffset: 0
50
+ }
36
51
  /** @type {Number|undefined} */
37
52
  this.rtype = undefined
38
53
  }
39
54
 
40
55
  /**
41
- * @param {Buffer} data
56
+ * @param {Uint8Array[]} data
42
57
  */
43
58
  parseData(data) {
44
- let cdata = data
45
- if (this.saveddata) {
46
- cdata = Buffer.concat([this.saveddata, cdata])
47
- delete this.saveddata
48
- }
49
- const bufferstate = { offset: 0, size: cdata.length, buffer: cdata }
59
+ const bufferstate = this.bufferstate
60
+ bufferstate.buffer.push(...data)
61
+ bufferstate.size += data.reduce((sum, chunk) => sum + chunk.byteLength, 0)
62
+
50
63
  while (bufferstate.size - bufferstate.offset > 0) {
51
64
  switch (this.mode) {
52
65
  case 's':
53
66
  {
54
- const capsulestart =
55
- bufferstate.offset + bufferstate.buffer.byteOffset
56
- const capsulemaxlength =
57
- bufferstate.buffer.byteLength - bufferstate.offset
67
+ const capsulestart = bufferstate.offset
68
+ const capsuleCurBuf = bufferstate.curBuf
69
+ const capsuleCurBufOffset = bufferstate.curBufOffset
58
70
  // we are at capsule start
59
71
  if (bufferstate.size < 2 + bufferstate.offset) {
60
- this.saveddata = Buffer.from(
61
- bufferstate.buffer.buffer,
62
- capsulestart,
63
- capsulemaxlength
64
- )
72
+ bufferstate.offset = capsulestart
73
+ bufferstate.curBuf = capsuleCurBuf
74
+ bufferstate.curBufOffset = capsuleCurBufOffset
75
+ detachReadBuffers(bufferstate)
65
76
  return
66
77
  }
67
78
  const rtype = readVarInt(bufferstate)
@@ -69,21 +80,19 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
69
80
  typeof rtype === 'undefined' ||
70
81
  bufferstate.size < 1 + bufferstate.offset
71
82
  ) {
72
- this.saveddata = Buffer.from(
73
- bufferstate.buffer.buffer,
74
- capsulestart,
75
- capsulemaxlength
76
- )
83
+ bufferstate.offset = capsulestart
84
+ bufferstate.curBuf = capsuleCurBuf
85
+ bufferstate.curBufOffset = capsuleCurBufOffset
86
+ detachReadBuffers(bufferstate)
77
87
  return
78
88
  }
79
89
  const type = Number(rtype)
80
90
  const rlength = readVarInt(bufferstate)
81
91
  if (typeof rlength === 'undefined') {
82
- this.saveddata = Buffer.from(
83
- bufferstate.buffer.buffer,
84
- capsulestart,
85
- capsulemaxlength
86
- )
92
+ bufferstate.offset = capsulestart
93
+ bufferstate.curBuf = capsuleCurBuf
94
+ bufferstate.curBufOffset = capsuleCurBufOffset
95
+ detachReadBuffers(bufferstate)
87
96
  return
88
97
  }
89
98
  const length = Number(rlength)
@@ -114,11 +123,10 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
114
123
  return
115
124
  }
116
125
  if (bufferstate.size < checklength + bufferstate.offset) {
117
- this.saveddata = Buffer.from(
118
- bufferstate.buffer.buffer,
119
- capsulestart,
120
- capsulemaxlength
121
- )
126
+ bufferstate.offset = capsulestart
127
+ bufferstate.curBuf = capsuleCurBuf
128
+ bufferstate.curBufOffset = capsuleCurBufOffset
129
+ detachReadBuffers(bufferstate)
122
130
  return
123
131
  }
124
132
  let streamid
@@ -171,10 +179,8 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
171
179
  object.recvData({
172
180
  data:
173
181
  offsetend - bufferstate.offset > 0
174
- ? new Uint8Array(
175
- bufferstate.buffer.buffer,
176
- bufferstate.buffer.byteOffset +
177
- bufferstate.offset,
182
+ ? getUint8ArraysfromBuffer(
183
+ bufferstate,
178
184
  offsetend - bufferstate.offset
179
185
  )
180
186
  : undefined,
@@ -228,9 +234,8 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
228
234
  const code = readUint32(bufferstate) || 0
229
235
  const decoder = new TextDecoder()
230
236
  const reason = decoder.decode(
231
- new Uint8Array(
232
- bufferstate.buffer.buffer,
233
- bufferstate.buffer.byteOffset + bufferstate.offset,
237
+ getUint8ArrayfromBuffer(
238
+ bufferstate,
234
239
  offsetend - bufferstate.offset
235
240
  )
236
241
  )
@@ -242,11 +247,11 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
242
247
  break
243
248
  case Http2CapsuleParser.DATAGRAM:
244
249
  this.session.jsobj.onDatagramReceived({
245
- datagram: new Uint8Array(
246
- bufferstate.buffer.buffer,
247
- bufferstate.buffer.byteOffset + bufferstate.offset,
248
- offsetend - bufferstate.offset
249
- )
250
+ datagram:
251
+ getUint8ArrayfromBuffer(
252
+ bufferstate,
253
+ offsetend - bufferstate.offset
254
+ ) || new Uint8Array(0)
250
255
  })
251
256
  break
252
257
  default:
@@ -256,12 +261,12 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
256
261
  if (bufferstate.size < length + offsetbegin) {
257
262
  this.remainlength = length + offsetbegin - bufferstate.size
258
263
  this.mode = 'c'
259
- if (streamid) {
264
+ if (typeof streamid !== 'undefined') {
260
265
  this.rstreamid = streamid
261
266
  this.rfin = type === Http2CapsuleParser.WT_STREAM_WFIN
262
267
  }
263
268
  }
264
- bufferstate.offset = offsetend
269
+ advanceBufferToOffset(bufferstate, offsetend)
265
270
  }
266
271
  break
267
272
  case 'c':
@@ -270,7 +275,7 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
270
275
  bufferstate.size - bufferstate.offset,
271
276
  this.remainlength
272
277
  )
273
- if (this.rstreamid) {
278
+ if (typeof this.rstreamid !== 'undefined') {
274
279
  // TODO submitData
275
280
  const object = this.wtstreams.get(this.rstreamid)
276
281
  const fin =
@@ -280,18 +285,14 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
280
285
  if (object) {
281
286
  if (fin) object.onFin()
282
287
  object.recvData({
283
- data: new Uint8Array(
284
- bufferstate.buffer.buffer,
285
- bufferstate.buffer.byteOffset + bufferstate.offset,
286
- clength
287
- ),
288
+ data: getUint8ArraysfromBuffer(bufferstate, clength),
288
289
  fin
289
290
  })
290
291
  }
291
292
  }
292
293
 
293
294
  this.remainlength = this.remainlength - clength
294
- bufferstate.offset += clength
295
+ advanceBufferBy(bufferstate, clength)
295
296
  if (this.remainlength === 0) {
296
297
  this.mode = 's'
297
298
  delete this.rfin
@@ -301,6 +302,7 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
301
302
  break
302
303
  }
303
304
  }
305
+ detachReadBuffers(bufferstate)
304
306
  }
305
307
 
306
308
  /**
@@ -312,8 +314,14 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
312
314
  let headlength = length
313
315
  if (payload) length += payload.byteLength
314
316
  headlength += lengthVarInt(length) + lengthVarInt(type)
315
- const cdata = Buffer.alloc(headlength)
316
- const bufferstate = { offset: 0, size: cdata.length, buffer: cdata }
317
+ const cdata = new Uint8Array(headlength)
318
+ const bufferstate = {
319
+ offset: 0,
320
+ size: cdata.length,
321
+ buffer: [cdata],
322
+ curBuf: 0,
323
+ curBufOffset: 0
324
+ }
317
325
  writeVarInt(bufferstate, type)
318
326
  writeVarInt(bufferstate, length)
319
327
  for (const ind in headerVints) writeVarInt(bufferstate, headerVints[ind])
@@ -558,7 +558,7 @@ export class Http2WebTransportServer {
558
558
  streamReceiveWindowSizeLimit:
559
559
  this.streamFlowControlWindowSizeLimit
560
560
  }))
561
- if (head && head.byteLength > 0) parse.parseData(head)
561
+ if (head && head.byteLength > 0) parse.parseData([head])
562
562
  return parse
563
563
  },
564
564
  initialBidirectionalSendStreams: 0,