quico 0.1.3 → 0.3.0

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/libs/h3.js DELETED
@@ -1,1461 +0,0 @@
1
- /*
2
- * quico: HTTP/3 and QUIC implementation for Node.js
3
- * Copyright 2025 colocohen
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at:
8
- *
9
- * https://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * This file is part of the open-source project hosted at:
12
- * https://github.com/colocohen/quico
13
- *
14
- * Unless required by applicable law or agreed to in writing, software
15
- * distributed under the License is distributed on an "AS IS" BASIS,
16
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
- */
18
-
19
- import {
20
- concatUint8Arrays,
21
- writeVarInt,
22
- readVarInt
23
- } from './utils.js';
24
-
25
-
26
- var huffman_codes = new Uint32Array([
27
- 0x1ff8,//(0)
28
- 0x7fffd8,//(1)
29
- 0xfffffe2,//(2)
30
- 0xfffffe3,//(3)
31
- 0xfffffe4,//(4)
32
- 0xfffffe5,//(5)
33
- 0xfffffe6,//(6)
34
- 0xfffffe7,//(7)
35
- 0xfffffe8,//(8)
36
- 0xffffea,//(9)
37
- 0x3ffffffc,//(10)
38
- 0xfffffe9,//(11)
39
- 0xfffffea,//(12)
40
- 0x3ffffffd,//(13)
41
- 0xfffffeb,//(14)
42
- 0xfffffec,//(15)
43
- 0xfffffed,//(16)
44
- 0xfffffee,//(17)
45
- 0xfffffef,//(18)
46
- 0xffffff0,//(19)
47
- 0xffffff1,//(20)
48
- 0xffffff2,//(21)
49
- 0x3ffffffe,//(22)
50
- 0xffffff3,//(23)
51
- 0xffffff4,//(24)
52
- 0xffffff5,//(25)
53
- 0xffffff6,//(26)
54
- 0xffffff7,//(27)
55
- 0xffffff8,//(28)
56
- 0xffffff9,//(29)
57
- 0xffffffa,//(30)
58
- 0xffffffb,//(31)
59
- 0x14,//' ' (32)
60
- 0x3f8,//'!' (33)
61
- 0x3f9,//'"' (34)
62
- 0xffa,//'#' (35)
63
- 0x1ff9,//'$' (36)
64
- 0x15,//'%' (37)
65
- 0xf8,//'&' (38)
66
- 0x7fa,//''' (39)
67
- 0x3fa,//'(' (40)
68
- 0x3fb,//')' (41)
69
- 0xf9,//'*' (42)
70
- 0x7fb,//'+' (43)
71
- 0xfa,//',' (44)
72
- 0x16,//'-' (45)
73
- 0x17,//'.' (46)
74
- 0x18,//'/' (47)
75
- 0x0,//'0' (48)
76
- 0x1,//'1' (49)
77
- 0x2,//'2' (50)
78
- 0x19,//'3' (51)
79
- 0x1a,//'4' (52)
80
- 0x1b,//'5' (53)
81
- 0x1c,//'6' (54)
82
- 0x1d,//'7' (55)
83
- 0x1e,//'8' (56)
84
- 0x1f,//'9' (57)
85
- 0x5c,//':' (58)
86
- 0xfb,//';' (59)
87
- 0x7ffc,//'<' (60)
88
- 0x20,//'=' (61)
89
- 0xffb,//'>' (62)
90
- 0x3fc,//'?' (63)
91
- 0x1ffa,//'@' (64)
92
- 0x21,//'A' (65)
93
- 0x5d,//'B' (66)
94
- 0x5e,//'C' (67)
95
- 0x5f,//'D' (68)
96
- 0x60,//'E' (69)
97
- 0x61,//'F' (70)
98
- 0x62,//'G' (71)
99
- 0x63,//'H' (72)
100
- 0x64,//'I' (73)
101
- 0x65,//'J' (74)
102
- 0x66,//'K' (75)
103
- 0x67,//'L' (76)
104
- 0x68,//'M' (77)
105
- 0x69,//'N' (78)
106
- 0x6a,//'O' (79)
107
- 0x6b,//'P' (80)
108
- 0x6c,//'Q' (81)
109
- 0x6d,//'R' (82)
110
- 0x6e,//'S' (83)
111
- 0x6f,//'T' (84)
112
- 0x70,//'U' (85)
113
- 0x71,//'V' (86)
114
- 0x72,//'W' (87)
115
- 0xfc,//'X' (88)
116
- 0x73,//'Y' (89)
117
- 0xfd,//'Z' (90)
118
- 0x1ffb,//'[' (91)
119
- 0x7fff0,//'\' (92)
120
- 0x1ffc,//']' (93)
121
- 0x3ffc,//'^' (94)
122
- 0x22,//'_' (95)
123
- 0x7ffd,//'`' (96)
124
- 0x3,//'a' (97)
125
- 0x23,//'b' (98)
126
- 0x4,//'c' (99)
127
- 0x24,//'d' (100)
128
- 0x5,//'e' (101)
129
- 0x25,//'f' (102)
130
- 0x26,//'g' (103)
131
- 0x27,//'h' (104)
132
- 0x6,//'i' (105)
133
- 0x74,//'j' (106)
134
- 0x75,//'k' (107)
135
- 0x28,//'l' (108)
136
- 0x29,//'m' (109)
137
- 0x2a,//'n' (110)
138
- 0x7,//'o' (111)
139
- 0x2b,//'p' (112)
140
- 0x76,//'q' (113)
141
- 0x2c,//'r' (114)
142
- 0x8,//'s' (115)
143
- 0x9,//'t' (116)
144
- 0x2d,//'u' (117)
145
- 0x77,//'v' (118)
146
- 0x78,//'w' (119)
147
- 0x79,//'x' (120)
148
- 0x7a,//'y' (121)
149
- 0x7b,//'z' (122)
150
- 0x7ffe,//'{' (123)
151
- 0x7fc,//'|' (124)
152
- 0x3ffd,//'}' (125)
153
- 0x1ffd,//'~' (126)
154
- 0xffffffc,//(127)
155
- 0xfffe6,//(128)
156
- 0x3fffd2,//(129)
157
- 0xfffe7,//(130)
158
- 0xfffe8,//(131)
159
- 0x3fffd3,//(132)
160
- 0x3fffd4,//(133)
161
- 0x3fffd5,//(134)
162
- 0x7fffd9,//(135)
163
- 0x3fffd6,//(136)
164
- 0x7fffda,//(137)
165
- 0x7fffdb,//(138)
166
- 0x7fffdc,//(139)
167
- 0x7fffdd,//(140)
168
- 0x7fffde,//(141)
169
- 0xffffeb,//(142)
170
- 0x7fffdf,//(143)
171
- 0xffffec,//(144)
172
- 0xffffed,//(145)
173
- 0x3fffd7,//(146)
174
- 0x7fffe0,//(147)
175
- 0xffffee,//(148)
176
- 0x7fffe1,//(149)
177
- 0x7fffe2,//(150)
178
- 0x7fffe3,//(151)
179
- 0x7fffe4,//(152)
180
- 0x1fffdc,//(153)
181
- 0x3fffd8,//(154)
182
- 0x7fffe5,//(155)
183
- 0x3fffd9,//(156)
184
- 0x7fffe6,//(157)
185
- 0x7fffe7,//(158)
186
- 0xffffef,//(159)
187
- 0x3fffda,//(160)
188
- 0x1fffdd,//(161)
189
- 0xfffe9,//(162)
190
- 0x3fffdb,//(163)
191
- 0x3fffdc,//(164)
192
- 0x7fffe8,//(165)
193
- 0x7fffe9,//(166)
194
- 0x1fffde,//(167)
195
- 0x7fffea,//(168)
196
- 0x3fffdd,//(169)
197
- 0x3fffde,//(170)
198
- 0xfffff0,//(171)
199
- 0x1fffdf,//(172)
200
- 0x3fffdf,//(173)
201
- 0x7fffeb,//(174)
202
- 0x7fffec,//(175)
203
- 0x1fffe0,//(176)
204
- 0x1fffe1,//(177)
205
- 0x3fffe0,//(178)
206
- 0x1fffe2,//(179)
207
- 0x7fffed,//(180)
208
- 0x3fffe1,//(181)
209
- 0x7fffee,//(182)
210
- 0x7fffef,//(183)
211
- 0xfffea,//(184)
212
- 0x3fffe2,//(185)
213
- 0x3fffe3,//(186)
214
- 0x3fffe4,//(187)
215
- 0x7ffff0,//(188)
216
- 0x3fffe5,//(189)
217
- 0x3fffe6,//(190)
218
- 0x7ffff1,//(191)
219
- 0x3ffffe0,//(192)
220
- 0x3ffffe1,//(193)
221
- 0xfffeb,//(194)
222
- 0x7fff1,//(195)
223
- 0x3fffe7,//(196)
224
- 0x7ffff2,//(197)
225
- 0x3fffe8,//(198)
226
- 0x1ffffec,//(199)
227
- 0x3ffffe2,//(200)
228
- 0x3ffffe3,//(201)
229
- 0x3ffffe4,//(202)
230
- 0x7ffffde,//(203)
231
- 0x7ffffdf,//(204)
232
- 0x3ffffe5,//(205)
233
- 0xfffff1,//(206)
234
- 0x1ffffed,//(207)
235
- 0x7fff2,//(208)
236
- 0x1fffe3,//(209)
237
- 0x3ffffe6,//(210)
238
- 0x7ffffe0,//(211)
239
- 0x7ffffe1,//(212)
240
- 0x3ffffe7,//(213)
241
- 0x7ffffe2,//(214)
242
- 0xfffff2,//(215)
243
- 0x1fffe4,//(216)
244
- 0x1fffe5,//(217)
245
- 0x3ffffe8,//(218)
246
- 0x3ffffe9,//(219)
247
- 0xffffffd,//(220)
248
- 0x7ffffe3,//(221)
249
- 0x7ffffe4,//(222)
250
- 0x7ffffe5,//(223)
251
- 0xfffec,//(224)
252
- 0xfffff3,//(225)
253
- 0xfffed,//(226)
254
- 0x1fffe6,//(227)
255
- 0x3fffe9,//(228)
256
- 0x1fffe7,//(229)
257
- 0x1fffe8,//(230)
258
- 0x7ffff3,//(231)
259
- 0x3fffea,//(232)
260
- 0x3fffeb,//(233)
261
- 0x1ffffee,//(234)
262
- 0x1ffffef,//(235)
263
- 0xfffff4,//(236)
264
- 0xfffff5,//(237)
265
- 0x3ffffea,//(238)
266
- 0x7ffff4,//(239)
267
- 0x3ffffeb,//(240)
268
- 0x7ffffe6,//(241)
269
- 0x3ffffec,//(242)
270
- 0x3ffffed,//(243)
271
- 0x7ffffe7,//(244)
272
- 0x7ffffe8,//(245)
273
- 0x7ffffe9,//(246)
274
- 0x7ffffea,//(247)
275
- 0x7ffffeb,//(248)
276
- 0xffffffe,//(249)
277
- 0x7ffffec,//(250)
278
- 0x7ffffed,//(251)
279
- 0x7ffffee,//(252)
280
- 0x7ffffef,//(253)
281
- 0x7fffff0,//(254)
282
- 0x3ffffee,//(255)
283
- 0x3fffffff,//EOS (256)
284
- ]);
285
-
286
-
287
- var huffman_bits = new Uint8Array([13,23,28,28,28,28,28,28,28,24,30,28,28,30,28,28,28,28,28,28,28,28,30,28,28,28,28,28,28,28,28,28,6,10,10,12,13,6,8,11,10,10,8,11,8,6,6,6,5,5,5,6,6,6,6,6,6,6,7,8,15,6,12,10,13,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,7,8,13,19,13,14,6,15,5,6,5,6,5,6,6,6,5,7,7,6,6,6,5,6,7,6,5,5,6,7,7,7,7,7,15,11,14,13,28,20,22,20,20,22,22,22,23,22,23,23,23,23,23,24,23,24,24,22,23,24,23,23,23,23,21,22,23,22,23,23,24,22,21,20,22,22,23,23,21,23,22,22,24,21,22,23,23,21,21,22,21,23,22,23,23,20,22,22,22,23,22,22,23,26,26,20,19,22,23,22,25,26,26,26,27,27,26,24,25,19,21,26,27,27,26,27,24,21,21,26,26,28,27,27,27,20,24,20,21,22,21,21,23,22,22,25,25,24,24,26,23,26,27,26,26,27,27,27,27,27,28,27,27,27,27,27,26,30]);
288
-
289
-
290
-
291
-
292
- function buildHuffmanDecodeTrie() {
293
- var root = {};
294
- for (var i = 0; i < huffman_codes.length; i++) {
295
- var code = huffman_codes[i];
296
- var length = huffman_bits[i];
297
- var node = root;
298
- for (var j = length - 1; j >= 0; j--) {
299
- var bit = (code >> j) & 1;
300
- if (!node[bit]) node[bit] = {};
301
- node = node[bit];
302
- }
303
- node.symbol = i;
304
- }
305
- return root;
306
- }
307
-
308
- var huffman_flat_decode_tables = buildHuffmanDecodeTrie();
309
-
310
-
311
-
312
- var qpack_static_table_entries = [
313
- [":authority", ""],
314
- [":path", "/"],
315
- ["age", "0"],
316
- ["content-disposition", ""],
317
- ["content-length", "0"],
318
- ["cookie", ""],
319
- ["date", ""],
320
- ["etag", ""],
321
- ["if-modified-since", ""],
322
- ["if-none-match", ""],
323
- ["last-modified", ""],
324
- ["link", ""],
325
- ["location", ""],
326
- ["referer", ""],
327
- ["set-cookie", ""],
328
- [":method", "CONNECT"],
329
- [":method", "DELETE"],
330
- [":method", "GET"],
331
- [":method", "HEAD"],
332
- [":method", "OPTIONS"],
333
- [":method", "POST"],
334
- [":method", "PUT"],
335
- [":scheme", "http"],
336
- [":scheme", "https"],
337
- [":status", "103"],
338
- [":status", "200"],
339
- [":status", "304"],
340
- [":status", "404"],
341
- [":status", "503"],
342
- ["accept", "*/*"],
343
- ["accept", "application/dns-message"],
344
- ["accept-encoding", "gzip, deflate, br"],
345
- ["accept-ranges", "bytes"],
346
- ["access-control-allow-headers", "cache-control"],
347
- ["access-control-allow-headers", "content-type"],
348
- ["access-control-allow-origin", "*"],
349
- ["cache-control", "max-age=0"],
350
- ["cache-control", "max-age=2592000"],
351
- ["cache-control", "max-age=604800"],
352
- ["cache-control", "no-cache"],
353
- ["cache-control", "no-store"],
354
- ["cache-control", "public, max-age=31536000"],
355
- ["content-encoding", "br"],
356
- ["content-encoding", "gzip"],
357
- ["content-type", "application/dns-message"],
358
- ["content-type", "application/javascript"],
359
- ["content-type", "application/json"],
360
- ["content-type", "application/x-www-form-urlencoded"],
361
- ["content-type", "image/gif"],
362
- ["content-type", "image/jpeg"],
363
- ["content-type", "image/png"],
364
- ["content-type", "text/css"],
365
- ["content-type", "text/html; charset=utf-8"],
366
- ["content-type", "text/plain"],
367
- ["content-type", "text/plain;charset=utf-8"],
368
- ["range", "bytes=0-"],
369
- ["strict-transport-security", "max-age=31536000"],
370
- ["strict-transport-security", "max-age=31536000; includesubdomains"],
371
- ["strict-transport-security", "max-age=31536000; includesubdomains; preload"],
372
- ["vary", "accept-encoding"],
373
- ["vary", "origin"],
374
- ["x-content-type-options", "nosniff"],
375
- ["x-xss-protection", "1; mode=block"],
376
- [":status", "100"],
377
- [":status", "204"],
378
- [":status", "206"],
379
- [":status", "302"],
380
- [":status", "400"],
381
- [":status", "403"],
382
- [":status", "421"],
383
- [":status", "425"],
384
- [":status", "500"],
385
- ["accept-language", ""],
386
- ["access-control-allow-credentials", "FALSE"],
387
- ["access-control-allow-credentials", "TRUE"],
388
- ["access-control-allow-headers", "*"],
389
- ["access-control-allow-methods", "get"],
390
- ["access-control-allow-methods", "get, post, options"],
391
- ["access-control-allow-methods", "options"],
392
- ["access-control-expose-headers", "content-length"],
393
- ["access-control-request-headers", "content-type"],
394
- ["access-control-request-method", "get"],
395
- ["access-control-request-method", "post"],
396
- ["alt-svc", "clear"],
397
- ["authorization", ""],
398
- ["content-security-policy", "script-src 'none'; object-src 'none'; base-uri 'none'"],
399
- ["early-data", "1"],
400
- ["expect-ct", ""],
401
- ["forwarded", ""],
402
- ["if-range", ""],
403
- ["origin", ""],
404
- ["purpose", "prefetch"],
405
- ["server", ""],
406
- ["timing-allow-origin", "*"],
407
- ["upgrade-insecure-requests", "1"],
408
- ["user-agent", ""],
409
- ["x-forwarded-for", ""],
410
- ["x-frame-options", "deny"],
411
- ["x-frame-options", "sameorigin"]
412
- ];
413
-
414
-
415
-
416
-
417
- function decodeVarInt(buf, prefixBits, pos) {
418
- var maxPrefix = (1 << prefixBits) - 1;
419
- var byte = buf[pos];
420
- var value = byte & maxPrefix;
421
- pos++;
422
-
423
- if (value < maxPrefix) // נגמר במרווח-הבייט הראשון
424
- return { value, next: pos };
425
-
426
- var m = 0;
427
- while (true) {
428
- byte = buf[pos++];
429
- value += (byte & 0x7f) << m;
430
- if ((byte & 0x80) === 0) break;
431
- m += 7;
432
- }
433
- return { value, next: pos };
434
- }
435
-
436
-
437
- function huffmanEncode(text) {
438
- var input = new TextEncoder().encode(text); // UTF-8 -> bytes
439
- var bitBuffer = 0;
440
- var bitLen = 0;
441
- var output = [];
442
-
443
- for (var i = 0; i < input.length; i++) {
444
- var sym = input[i];
445
- var code = huffman_codes[sym];
446
- var nbits = huffman_bits[sym];
447
-
448
- bitBuffer = (bitBuffer << nbits) | code;
449
- bitLen += nbits;
450
-
451
- while (bitLen >= 8) {
452
- bitLen -= 8;
453
- output.push((bitBuffer >> bitLen) & 0xff);
454
- }
455
- }
456
-
457
- // Padding: לפי התקן, ממלאים 1-ים עד סוף בייט
458
- if (bitLen > 0) {
459
- bitBuffer = (bitBuffer << (8 - bitLen)) | ((1 << (8 - bitLen)) - 1);
460
- output.push(bitBuffer & 0xff);
461
- }
462
-
463
- return new Uint8Array(output);
464
- }
465
-
466
-
467
-
468
- // פונקציית פיענוח לפי עץ
469
- function decodeHuffman(buf) {
470
- var output = [];
471
- var node = huffman_flat_decode_tables;
472
- var current = 0;
473
- var nbits = 0;
474
-
475
- for (var i = 0; i < buf.length; i++) {
476
- current = (current << 8) | buf[i];
477
- nbits += 8;
478
-
479
- while (nbits > 0) {
480
- var bit = (current >> (nbits - 1)) & 1;
481
- node = node[bit];
482
- if (!node) throw new Error("Invalid Huffman encoding");
483
- nbits--;
484
-
485
- if (node.symbol !== undefined) {
486
- output.push(node.symbol);
487
- node = huffman_flat_decode_tables;
488
- }
489
- }
490
- }
491
-
492
- // בדיקה לסיומת padding חוקית (לפי התקן — רק 1s מותר בסוף)
493
- var padding = (1 << nbits) - 1;
494
- if ((current & padding) !== padding) {
495
- throw new Error("Invalid Huffman padding");
496
- }
497
-
498
- return new TextDecoder().decode(Uint8Array.from(output));
499
- }
500
-
501
-
502
-
503
- function parse_qpack_header_block(buf) {
504
- var pos = 0;
505
- var headers = [];
506
-
507
- // Required Insert Count (prefix-8)
508
- var ric = decodeVarInt(buf, 8, pos);
509
- pos = ric.next;
510
-
511
- // Delta Base (prefix-7 + S-bit)
512
- var firstDbByte = buf[pos];
513
- var postBase = (firstDbByte & 0x80) !== 0; // S-bit
514
- var db = decodeVarInt(buf, 7, pos);
515
- pos = db.next;
516
-
517
- // Base Index = RIC ± DB לפי S-bit
518
- var baseIndex = postBase
519
- ? ric.value + db.value
520
- : ric.value - db.value;
521
-
522
- // Header Field Lines
523
- while (pos < buf.length) {
524
- var byte = buf[pos];
525
-
526
- // A. Indexed Field Line – 1xxxxxxx
527
- if ((byte & 0x80) === 0x80) {
528
- var fromStatic = (byte & 0x40) !== 0; // T-bit
529
- var idx = decodeVarInt(buf, 6, pos); // prefix-6
530
- pos = idx.next;
531
- headers.push({
532
- type: "indexed",
533
- from_static_table: fromStatic,
534
- index: idx.value
535
- });
536
- continue;
537
- }
538
-
539
- // B. Literal With Name Reference – 01xxxxxx
540
- if ((byte & 0xC0) === 0x40) {
541
- var neverIndexed = (byte & 0x20) !== 0; // N-bit
542
- var fromStatic = (byte & 0x10) !== 0; // T-bit
543
- var nameIdx = decodeVarInt(buf, 4, pos); // prefix-4
544
- pos = nameIdx.next;
545
-
546
- var valH = (buf[pos] & 0x80) !== 0;
547
- var valLen = decodeVarInt(buf, 7, pos); // prefix-7
548
- pos = valLen.next;
549
-
550
- var valBytes = buf.slice(pos, pos + valLen.value);
551
- pos += valLen.value;
552
- var value = valH ? decodeHuffman(valBytes)
553
- : new TextDecoder().decode(valBytes);
554
-
555
- headers.push({
556
- type: "literal_with_name_ref",
557
- never_indexed: neverIndexed,
558
- from_static_table: fromStatic,
559
- name_index: nameIdx.value,
560
- value
561
- });
562
-
563
- continue;
564
- }
565
-
566
- // C. Literal With Literal Name – 001xxxxx
567
- if ((byte & 0xE0) === 0x20) {
568
- var neverIndexed = (byte & 0x10) !== 0; // N-bit
569
- var nameH = (byte & 0x08) !== 0; // H-bit
570
- var nameLen = decodeVarInt(buf, 3, pos); // prefix-3
571
- pos = nameLen.next;
572
-
573
- var nameBytes = buf.slice(pos, pos + nameLen.value);
574
- pos += nameLen.value;
575
- var name = nameH ? decodeHuffman(nameBytes)
576
- : new TextDecoder().decode(nameBytes);
577
-
578
- var valH = (buf[pos] & 0x80) !== 0; // H-bit
579
- var valLen = decodeVarInt(buf, 7, pos); // prefix-7
580
- pos = valLen.next;
581
-
582
- var valBytes = buf.slice(pos, pos + valLen.value);
583
- pos += valLen.value;
584
- var value = valH ? decodeHuffman(valBytes)
585
- : new TextDecoder().decode(valBytes);
586
-
587
- headers.push({
588
- type: "literal_with_literal_name",
589
- never_indexed: neverIndexed,
590
- name,
591
- value
592
- });
593
- continue;
594
- }
595
-
596
- // לא אמור להגיע לכאן – תקלה לפי התקן
597
- throw new Error(
598
- `Unknown header-block instruction at byte ${pos} (0x${byte.toString(16)})`
599
- );
600
- }
601
-
602
- return {
603
- insert_count: ric.value,
604
- delta_base: db.value,
605
- post_base: postBase,
606
- base_index: baseIndex,
607
- headers
608
- };
609
- }
610
-
611
-
612
- function parse_qpack_header_block_old(buf) {
613
- var pos = 0;
614
- var headers = [];
615
-
616
- /* 1) Field-section prefix */
617
- var ric = decodeVarInt(buf, 8, pos); // Required Insert Count (prefix-8)
618
- pos = ric.next;
619
-
620
- var db = decodeVarInt(buf, 7, pos); // Delta Base (prefix-7)
621
- pos = db.next;
622
-
623
- /* 2) Field-line representations */
624
- while (pos < buf.length) {
625
- var byte = buf[pos];
626
-
627
- /* A. Indexed Field Line – 1xxxxxxx */
628
- if ((byte & 0x80) === 0x80) {
629
- var fromStatic = (byte & 0x40) !== 0; // T-bit
630
- var idx = decodeVarInt(buf, 6, pos); // prefix-6
631
- pos = idx.next;
632
- headers.push({
633
- type: "indexed",
634
- from_static_table: fromStatic,
635
- index: idx.value
636
- });
637
- continue;
638
- }
639
-
640
- /* B. Literal Field Line + Name Reference – 01xxxxxx */
641
- if ((byte & 0xC0) === 0x40) {
642
- var neverIndexed = (byte & 0x20) !== 0; // N-bit
643
- var fromStatic = (byte & 0x10) !== 0; // T-bit
644
- var nameIdx = decodeVarInt(buf, 4, pos); // prefix-4
645
- pos = nameIdx.next;
646
-
647
- var valH = (buf[pos] & 0x80) !== 0;
648
- var valLen = decodeVarInt(buf, 7, pos); // prefix-7
649
- pos = valLen.next;
650
-
651
- var valBytes = buf.slice(pos, pos + valLen.value);
652
- pos += valLen.value;
653
- var value = valH ? decodeHuffman(valBytes)
654
- : new TextDecoder().decode(valBytes);
655
-
656
- headers.push({
657
- type: "literal_with_name_ref",
658
- never_indexed: neverIndexed,
659
- from_static_table: fromStatic,
660
- name_index: nameIdx.value,
661
- value
662
- });
663
-
664
- continue;
665
- }
666
-
667
- /* C. Literal Field Line + Literal Name – 001xxxxx */
668
- if ((byte & 0xE0) === 0x20) {
669
- var neverIndexed = (byte & 0x10) !== 0; // N-bit
670
- var nameH = (byte & 0x08) !== 0; // H-bit (שם) :contentReference[oaicite:0]{index=0}
671
- var nameLen = decodeVarInt(buf, 3, pos); // prefix-3
672
- pos = nameLen.next;
673
-
674
- var nameBytes = buf.slice(pos, pos + nameLen.value);
675
- pos += nameLen.value;
676
- var name = nameH ? decodeHuffman(nameBytes)
677
- : new TextDecoder().decode(nameBytes);
678
-
679
- var valH = (buf[pos] & 0x80) !== 0; // H-bit (ערך)
680
- var valLen = decodeVarInt(buf, 7, pos); // prefix-7
681
- pos = valLen.next;
682
-
683
- var valBytes = buf.slice(pos, pos + valLen.value);
684
- pos += valLen.value;
685
- var value = valH ? decodeHuffman(valBytes)
686
- : new TextDecoder().decode(valBytes);
687
-
688
- headers.push({
689
- type: "literal_with_literal_name",
690
- never_indexed: neverIndexed,
691
- name,
692
- value
693
- });
694
- continue;
695
- }
696
-
697
- /* לא אמור להגיע לכאן – פסילה לפי התקן */
698
- throw new Error(
699
- `Unknown header-block instruction at byte ${pos} (0x${byte.toString(16)})`
700
- );
701
- }
702
-
703
- return {
704
- insert_count: ric.value,
705
- delta_base: db.value,
706
- headers: headers
707
- };
708
- }
709
-
710
-
711
-
712
-
713
-
714
- // הנחות:
715
- // - chunks: Array<Uint8Array>, לפי הסדר (head → tail)
716
- // - from_offset: offset לוגי (למי שצריך; נעדכן אותו בסוף)
717
- // - readVarInt(u8, off) => { value, byteLength }
718
- // - concatUint8Arrays(arr) קיים אצלך
719
-
720
- function extract_h3_frames_from_chunks(chunks, from_offset) {
721
- // אם אין צ'אנקים – אין מה לפרסר
722
- if (!chunks || chunks.length === 0) {
723
- return { frames: [], new_from_offset: from_offset };
724
- }
725
-
726
- // בונים buffers החל מהמיקום הלוגי from_offset בלי לשנות את chunks
727
- var buffers = [];
728
- var acc = 0;
729
- for (var i = 0; i < chunks.length; i++) {
730
- var c = chunks[i];
731
- var nextAcc = acc + c.length;
732
- if (from_offset < nextAcc) {
733
- // from_offset נופל לתוך הצ'אנק הזה
734
- var start = from_offset - acc;
735
- buffers.push(c.slice(start));
736
- // כל שאר הצ'אנקים כמות שהם
737
- for (var j = i + 1; j < chunks.length; j++) {
738
- buffers.push(chunks[j]);
739
- }
740
- break;
741
- }
742
- acc = nextAcc;
743
- }
744
-
745
- if (buffers.length === 0) {
746
- // from_offset מעבר לסוף הנתונים שיש כרגע
747
- return { frames: [], new_from_offset: from_offset };
748
- }
749
-
750
- var combined = concatUint8Arrays(buffers);
751
- var offset = 0;
752
- var frames = [];
753
-
754
- // קריאת VarInt בטוחה מתוך 'combined' עם קידום offset מקומי
755
- function safeReadVarInt() {
756
- if (offset >= combined.length) return null;
757
- var firstByte = combined[offset];
758
- var lengthBits = firstByte >> 6; // 0..3 → 1,2,4,8 bytes
759
- var neededLength = 1 << lengthBits;
760
- if (offset + neededLength > combined.length) return null;
761
- var res = readVarInt(combined, offset);
762
- if (!res || typeof res.byteLength !== 'number') return null;
763
- offset += res.byteLength;
764
- return res;
765
- }
766
-
767
- while (offset < combined.length) {
768
- var startOffset = offset;
769
-
770
- var frameType = safeReadVarInt();
771
- if (!frameType) break;
772
-
773
- var lengthInfo = safeReadVarInt();
774
- if (!lengthInfo) {
775
- // לא הצלחנו אפילו לקרוא את האורך – נחזור לנק' ההתחלה ונחכה לנתונים נוספים
776
- offset = startOffset;
777
- break;
778
- }
779
-
780
- var payloadLength = lengthInfo.value >>> 0; // מניחים אורך עד 2^32-1
781
- if (offset + payloadLength > combined.length) {
782
- // פריים חלקי – rollback מלא
783
- offset = startOffset;
784
- break;
785
- }
786
-
787
- var payload = combined.slice(offset, offset + payloadLength);
788
- frames.push({ frame_type: frameType.value, payload: payload });
789
- offset += payloadLength;
790
- }
791
-
792
- // לא משנים את chunks; רק מקדמים את from_offset לפי כמה באמת נקרא
793
- return { frames: frames, new_from_offset: from_offset + offset };
794
- }
795
-
796
-
797
- function extract_h3_frames_from_chunks2(chunks, from_offset) {
798
- var offsets = Object.keys(chunks).map(Number).sort((a, b) => a - b);
799
- var buffers = [];
800
- var totalLength = 0;
801
-
802
- // מחברים את כל הצ’אנקים החל מ־from_offset
803
- for (var i = 0; i < offsets.length; i++) {
804
- var base = offsets[i];
805
- var chunk = chunks[base];
806
- if (from_offset >= base && from_offset < base + chunk.length) {
807
- var start = from_offset - base;
808
- var sliced = chunk.slice(start);
809
- buffers.push(sliced);
810
- totalLength += sliced.length;
811
-
812
- for (var j = i + 1; j < offsets.length; j++) {
813
- buffers.push(chunks[offsets[j]]);
814
- totalLength += chunks[offsets[j]].length;
815
- }
816
-
817
- break;
818
- }
819
- }
820
-
821
- if (buffers.length === 0) return { frames: [], new_from_offset: from_offset };
822
-
823
- var combined = concatUint8Arrays(buffers);
824
- var offset = 0;
825
- var frames = [];
826
-
827
- // פונקציית עזר בטוחה לקריאת VarInt
828
- function safeReadVarInt() {
829
- if (offset >= combined.length) return null;
830
- var firstByte = combined[offset];
831
- var lengthBits = firstByte >> 6;
832
- var neededLength = 1 << lengthBits;
833
- if (offset + neededLength > combined.length) return null;
834
- var res = readVarInt(combined, offset);
835
- if (!res || typeof res.byteLength !== 'number') return null;
836
- offset += res.byteLength;
837
- return res;
838
- }
839
-
840
- while (offset < combined.length) {
841
- var startOffset = offset;
842
-
843
- var frameType = safeReadVarInt();
844
- if (!frameType) break;
845
-
846
- var lengthInfo = safeReadVarInt();
847
- if (!lengthInfo) {
848
- offset = startOffset; // rollback – אי אפשר אפילו לקרוא אורך
849
- break;
850
- }
851
-
852
- var payloadLength = lengthInfo.value;
853
- if (offset + payloadLength > combined.length) {
854
- offset = startOffset; // rollback
855
- break;
856
- }
857
-
858
- var payload = combined.slice(offset, offset + payloadLength);
859
- frames.push({ frame_type: frameType.value, payload });
860
- offset += payloadLength;
861
- }
862
-
863
- // עדכון chunks כדי להסיר את מה שקראנו
864
- if (offset > 0) {
865
- var bytesToRemove = offset;
866
- var newChunks = {};
867
- var processed = 0;
868
- var currentOffset = from_offset;
869
-
870
- for (var k = 0; k < offsets.length; k++) {
871
- var base = offsets[k];
872
- var chunk = chunks[base];
873
-
874
- if (currentOffset >= base + chunk.length) continue;
875
-
876
- var relStart = Math.max(currentOffset - base, 0);
877
- var relEnd = Math.min(chunk.length, currentOffset + bytesToRemove - base);
878
- if (relEnd < chunk.length) {
879
- var leftover = chunk.slice(relEnd);
880
- var newBase = base + relEnd;
881
- newChunks[newBase] = leftover;
882
- }
883
-
884
- bytesToRemove -= (relEnd - relStart);
885
- if (bytesToRemove <= 0) break;
886
- }
887
-
888
- for (var key in chunks) delete chunks[key];
889
- for (var key in newChunks) chunks[key] = newChunks[key];
890
- from_offset += offset;
891
- }
892
-
893
- return { frames, new_from_offset: from_offset };
894
- }
895
-
896
-
897
-
898
-
899
- function build_h3_frames(frames) {
900
- var parts = [];
901
-
902
- for (var i = 0; i < frames.length; i++) {
903
- var frame = frames[i];
904
-
905
- // כל חלק מהפריים כ־Uint8Array
906
- var typeBytes = writeVarInt(frame.frame_type);
907
- var lenBytes = writeVarInt(frame.payload.length);
908
- var payload = frame.payload;
909
-
910
- parts.push(typeBytes, lenBytes, payload);
911
- }
912
-
913
- return concatUint8Arrays(parts);
914
-
915
- }
916
-
917
-
918
-
919
- /* חישוב אורך varint לפי HPACK/QPACK (prefix-N) */
920
- function computeVarIntLen(buf, pos, prefixBits) {
921
- if (pos >= buf.length) return null;
922
- var first = buf[pos];
923
- var prefixMask = (1 << prefixBits) - 1;
924
- var prefixVal = first & prefixMask;
925
-
926
- // אם הערך קטן מהמקסימום – varint של בייט אחד
927
- if (prefixVal < prefixMask) return 1;
928
-
929
- // אחרת ממשיכים ב-Base128 עד שבייט בלי MSB=1
930
- var len = 1;
931
- var idx = pos + 1;
932
- while (idx < buf.length) {
933
- len++;
934
- if ((buf[idx] & 0x80) === 0) return len; // הסתיים
935
- idx++;
936
- }
937
- return null; // חסר נתונים
938
- }
939
-
940
- /* קריאה בטוחה של varint */
941
- function safeDecodeVarInt(buf, posRef, prefixBits) {
942
- var len = computeVarIntLen(buf, posRef.pos, prefixBits);
943
- if (len === null) return null; // לא שלם
944
-
945
- var res = decodeVarInt(buf, prefixBits, posRef.pos); // הפונקציה שלך
946
- posRef.pos = res.next;
947
- return res.value;
948
- }
949
-
950
- /* ---------- פונקציית החילוץ העיקרית ---------- */
951
-
952
- // הנחות:
953
- // - chunks: Array<Uint8Array>, לפי הסדר (head → tail)
954
- // - from_offset: מספר מצטבר (רק להחזרה/מתן עקיבה)
955
- // - concatUint8Arrays(arr) קיים אצלך
956
- // - safeDecodeVarInt(buf, posRef, prefixBits) -> number|null (posRef.pos מתקדם בפנים)
957
- // - decodeHuffman(u8) קיים אם אתה תומך בהאףמן; אחרת אפשר להחזיר שגיאה/לקרוא כ-raw
958
-
959
- function extract_qpack_encoder_instructions_from_chunks(chunks, from_offset) {
960
- // אם אין צ'אנקים – אין מה לפרסר
961
- if (!chunks || chunks.length === 0) {
962
- return { instructions: [], new_from_offset: from_offset };
963
- }
964
-
965
- // מחברים ל-buffer יחיד החל מ-from_offset, בלי לשנות את chunks
966
- var buffers = [];
967
- var acc = 0;
968
- for (var i = 0; i < chunks.length; i++) {
969
- var c = chunks[i];
970
- var nextAcc = acc + c.length;
971
- if (from_offset < nextAcc) {
972
- // from_offset בתוך הצ'אנק הזה
973
- var start = from_offset - acc;
974
- buffers.push(c.slice(start));
975
- // כל שאר הצ'אנקים כפי שהם
976
- for (var j = i + 1; j < chunks.length; j++) {
977
- buffers.push(chunks[j]);
978
- }
979
- break;
980
- }
981
- acc = nextAcc;
982
- }
983
-
984
- if (buffers.length === 0) {
985
- // from_offset מעבר לנתונים שיש כרגע
986
- return { instructions: [], new_from_offset: from_offset };
987
- }
988
-
989
- var combined = concatUint8Arrays(buffers);
990
- var posRef = { pos: 0 };
991
- var instructions = [];
992
-
993
- // 2) לולאת פירוש הוראות QPACK-Encoder
994
- while (posRef.pos < combined.length) {
995
- var startPos = posRef.pos;
996
- if (posRef.pos >= combined.length) break;
997
- var byte = combined[posRef.pos];
998
-
999
- // --- A. Insert With Name Reference (1xxxxxxx) ---
1000
- if ((byte & 0x80) === 0x80) {
1001
- var fromStatic = (byte & 0x40) !== 0;
1002
- var nameIdx = safeDecodeVarInt(combined, posRef, 6);
1003
- if (nameIdx === null) break; // חסר נתונים
1004
-
1005
- // value length (Huffman flag בביט העליון של בייט האורך)
1006
- if (posRef.pos >= combined.length) { posRef.pos = startPos; break; }
1007
- var valHuffman = (combined[posRef.pos] & 0x80) !== 0;
1008
- var valLen = safeDecodeVarInt(combined, posRef, 7);
1009
- if (valLen === null || posRef.pos + valLen > combined.length) {
1010
- posRef.pos = startPos; break;
1011
- }
1012
-
1013
- var valBytes = combined.slice(posRef.pos, posRef.pos + valLen);
1014
- posRef.pos += valLen;
1015
-
1016
- var value = valHuffman ? decodeHuffman(valBytes)
1017
- : new TextDecoder().decode(valBytes);
1018
-
1019
- instructions.push({
1020
- type: 'insert_with_name_ref',
1021
- from_static_table: fromStatic,
1022
- name_index: nameIdx,
1023
- value: value
1024
- });
1025
- continue;
1026
- }
1027
-
1028
- // --- B. Insert Without Name Reference (01xxxxxx) ---
1029
- if ((byte & 0xC0) === 0x40) {
1030
- // שים לב: בדפוס הזה ה־N-flag (שם בהאףמן) נמצא בביט 0x20 של הבייט הראשון
1031
- var nameH = (byte & 0x20) !== 0;
1032
- var nameLen = safeDecodeVarInt(combined, posRef, 5);
1033
- if (nameLen === null || posRef.pos + nameLen > combined.length) {
1034
- posRef.pos = startPos; break;
1035
- }
1036
- var nameBytes = combined.slice(posRef.pos, posRef.pos + nameLen);
1037
- posRef.pos += nameLen;
1038
-
1039
- // value length (Huffman flag בביט העליון של בייט האורך)
1040
- if (posRef.pos >= combined.length) { posRef.pos = startPos; break; }
1041
- var valH = (combined[posRef.pos] & 0x80) !== 0;
1042
- var valLen2 = safeDecodeVarInt(combined, posRef, 7);
1043
- if (valLen2 === null || posRef.pos + valLen2 > combined.length) {
1044
- posRef.pos = startPos; break;
1045
- }
1046
- var valBytes2 = combined.slice(posRef.pos, posRef.pos + valLen2);
1047
- posRef.pos += valLen2;
1048
-
1049
- var nameStr = nameH ? decodeHuffman(nameBytes)
1050
- : new TextDecoder().decode(nameBytes);
1051
- var valueStr = valH ? decodeHuffman(valBytes2)
1052
- : new TextDecoder().decode(valBytes2);
1053
-
1054
- instructions.push({
1055
- type: 'insert_without_name_ref',
1056
- name: nameStr,
1057
- value: valueStr
1058
- });
1059
- continue;
1060
- }
1061
-
1062
- // --- C. Set Dynamic Table Capacity (001xxxxx) ---
1063
- if ((byte & 0xE0) === 0x20) {
1064
- var capacity = safeDecodeVarInt(combined, posRef, 5);
1065
- if (capacity === null) { posRef.pos = startPos; break; }
1066
-
1067
- instructions.push({
1068
- type: 'set_dynamic_table_capacity',
1069
- capacity: capacity
1070
- });
1071
- continue;
1072
- }
1073
-
1074
- // --- D. Duplicate (0000xxxx) ---
1075
- if ((byte & 0xF0) === 0x00) {
1076
- var dupIndex = safeDecodeVarInt(combined, posRef, 4);
1077
- if (dupIndex === null) { posRef.pos = startPos; break; }
1078
-
1079
- instructions.push({
1080
- type: 'duplicate',
1081
- index: dupIndex
1082
- });
1083
- continue;
1084
- }
1085
-
1086
- // אופקוד לא מוכר או לא נתמך – נעצור עד שיגיע עוד מידע / נטפל חיצונית
1087
- break;
1088
- }
1089
-
1090
- // כמה בייטים פרשנו מתוך ה־view המאוחד
1091
- var consumed = posRef.pos | 0;
1092
-
1093
- // לא משנים את chunks; רק מקדמים offset לוגי
1094
- return { instructions: instructions, new_from_offset: from_offset + consumed };
1095
- }
1096
-
1097
-
1098
- function extract_qpack_encoder_instructions_from_chunks2(chunks, from_offset) {
1099
- /* 1) חיבור הצ’אנקים החל מ-from_offset */
1100
- var offsets = Object.keys(chunks).map(Number).sort(function (a, b) { return a - b; });
1101
- var buffers = [];
1102
- var totalLen = 0;
1103
-
1104
- for (var i = 0; i < offsets.length; i++) {
1105
- var base = offsets[i];
1106
- var chunk = chunks[base];
1107
- if (from_offset >= base && from_offset < base + chunk.length) {
1108
- var start = from_offset - base;
1109
- var sliced = chunk.slice(start);
1110
- buffers.push(sliced);
1111
- totalLen += sliced.length;
1112
-
1113
- for (var j = i + 1; j < offsets.length; j++) {
1114
- buffers.push(chunks[offsets[j]]);
1115
- totalLen += chunks[offsets[j]].length;
1116
- }
1117
- break;
1118
- }
1119
- }
1120
-
1121
- if (buffers.length === 0) {
1122
- return { instructions: [], new_from_offset: from_offset };
1123
- }
1124
-
1125
- var combined = concatUint8Arrays(buffers);
1126
- var posRef = { pos: 0 };
1127
- var instructions = [];
1128
-
1129
- /* 2) לולאת פיענוח ההוראות */
1130
- while (posRef.pos < combined.length) {
1131
- var startPos = posRef.pos;
1132
- var byte = combined[posRef.pos];
1133
-
1134
- /* --- A. Insert With Name Reference (1xxxxxxx) --- */
1135
- if ((byte & 0x80) === 0x80) {
1136
- var fromStatic = (byte & 0x40) !== 0;
1137
- var nameIdx = safeDecodeVarInt(combined, posRef, 6);
1138
- if (nameIdx === null) break; // לא שלם
1139
-
1140
- // value length
1141
- var valHuffman = (combined[posRef.pos] & 0x80) !== 0;
1142
- var valLen = safeDecodeVarInt(combined, posRef, 7);
1143
- if (valLen === null || posRef.pos + valLen > combined.length) {
1144
- posRef.pos = startPos; break;
1145
- }
1146
-
1147
- var valBytes = combined.slice(posRef.pos, posRef.pos + valLen);
1148
- posRef.pos += valLen;
1149
-
1150
- var value = valHuffman ? decodeHuffman(valBytes)
1151
- : new TextDecoder().decode(valBytes);
1152
-
1153
- instructions.push({
1154
- type: 'insert_with_name_ref',
1155
- from_static_table: fromStatic,
1156
- name_index: nameIdx,
1157
- value: value
1158
- });
1159
- continue;
1160
- }
1161
-
1162
- /* --- B. Insert Without Name Reference (01xxxxxx) --- */
1163
- if ((byte & 0xC0) === 0x40) {
1164
- var nameH = (byte & 0x20) !== 0;
1165
- var nameLen = safeDecodeVarInt(combined, posRef, 5);
1166
- if (nameLen === null || posRef.pos + nameLen > combined.length) {
1167
- posRef.pos = startPos; break;
1168
- }
1169
- var nameBytes = combined.slice(posRef.pos, posRef.pos + nameLen);
1170
- posRef.pos += nameLen;
1171
-
1172
- var valH = (combined[posRef.pos] & 0x80) !== 0;
1173
- var valLen2 = safeDecodeVarInt(combined, posRef, 7);
1174
- if (valLen2 === null || posRef.pos + valLen2 > combined.length) {
1175
- posRef.pos = startPos; break;
1176
- }
1177
- var valBytes2 = combined.slice(posRef.pos, posRef.pos + valLen2);
1178
- posRef.pos += valLen2;
1179
-
1180
- var nameStr = nameH ? decodeHuffman(nameBytes)
1181
- : new TextDecoder().decode(nameBytes);
1182
- var valueStr = valH ? decodeHuffman(valBytes2)
1183
- : new TextDecoder().decode(valBytes2);
1184
-
1185
- instructions.push({
1186
- type: 'insert_without_name_ref',
1187
- name: nameStr,
1188
- value: valueStr
1189
- });
1190
- continue;
1191
- }
1192
-
1193
- /* --- C. Set Dynamic Table Capacity (001xxxxx) --- */
1194
- if ((byte & 0xE0) === 0x20) {
1195
- var capacity = safeDecodeVarInt(combined, posRef, 5);
1196
- if (capacity === null) { posRef.pos = startPos; break; }
1197
-
1198
- instructions.push({
1199
- type: 'set_dynamic_table_capacity',
1200
- capacity: capacity
1201
- });
1202
- continue;
1203
- }
1204
-
1205
- /* --- D. Duplicate (0000xxxx) --- */
1206
- if ((byte & 0xF0) === 0x00) {
1207
- var dupIndex = safeDecodeVarInt(combined, posRef, 4);
1208
- if (dupIndex === null) { posRef.pos = startPos; break; }
1209
-
1210
- instructions.push({
1211
- type: 'duplicate',
1212
- index: dupIndex
1213
- });
1214
- continue;
1215
- }
1216
-
1217
- /* לא מוכר - נעצור */
1218
- break;
1219
- }
1220
-
1221
- var consumed = posRef.pos; // כמה בייטים הצלחנו לפרש
1222
-
1223
- /* 3) ניקוי הצ’אנקים והתקדמות from_offset */
1224
- if (consumed > 0) {
1225
- var bytesLeft = consumed;
1226
- var newChunks = {};
1227
- var currOff = from_offset;
1228
-
1229
- for (var k = 0; k < offsets.length; k++) {
1230
- var base = offsets[k];
1231
- var chunk = chunks[base];
1232
-
1233
- if (currOff >= base + chunk.length) continue;
1234
-
1235
- var relStart = Math.max(currOff - base, 0);
1236
- var relEnd = Math.min(chunk.length, currOff + bytesLeft - base);
1237
-
1238
- if (relEnd < chunk.length) {
1239
- var leftover = chunk.slice(relEnd);
1240
- newChunks[base + relEnd] = leftover;
1241
- }
1242
-
1243
- bytesLeft -= (relEnd - relStart);
1244
- if (bytesLeft <= 0) break;
1245
- }
1246
-
1247
- for (var key in chunks) delete chunks[key];
1248
- for (var nk in newChunks) chunks[nk] = newChunks[nk];
1249
-
1250
- from_offset += consumed;
1251
- }
1252
-
1253
- return { instructions: instructions, new_from_offset: from_offset };
1254
- }
1255
-
1256
-
1257
-
1258
- var h3_settings_frame_params = [
1259
- [0x01, "SETTINGS_QPACK_MAX_TABLE_CAPACITY"],
1260
- [0x06, "SETTINGS_MAX_FIELD_SECTION_SIZE"],
1261
- [0x07, "SETTINGS_QPACK_BLOCKED_STREAMS"],
1262
- [0x08, "SETTINGS_ENABLE_CONNECT_PROTOCOL"],
1263
- [0x33, "SETTINGS_H3_DATAGRAM"],
1264
- [0x2b603742, "SETTINGS_ENABLE_WEBTRANSPORT"], // תקני לפי draft
1265
- [0x0d, "SETTINGS_NO_RFC9114_LEGACY_CODEPOINT"],
1266
- [0x14E9CD29, "SETTINGS_WT_MAX_SESSIONS"],
1267
- [0x4d44, "SETTINGS_ENABLE_METADATA"] // provisional
1268
- ];
1269
-
1270
- var h3_name_to_id = {};
1271
- var h3_id_to_name = {};
1272
-
1273
- for (var i = 0; i < h3_settings_frame_params.length; i++) {
1274
- var [id, name] = h3_settings_frame_params[i];
1275
- h3_name_to_id[name] = id;
1276
- h3_id_to_name[id] = name;
1277
- }
1278
-
1279
-
1280
-
1281
- function parse_h3_settings_frame(buf) {
1282
- var settings = {};
1283
- var offset = 0;
1284
-
1285
- while (offset < buf.length) {
1286
- var idRes = readVarInt(buf, offset);
1287
- if (!idRes) break;
1288
- offset += idRes.byteLength;
1289
-
1290
- var valRes = readVarInt(buf, offset);
1291
- if (!valRes) break;
1292
- offset += valRes.byteLength;
1293
-
1294
- var id = idRes.value;
1295
- var value = valRes.value;
1296
-
1297
- var name = h3_id_to_name[id] || `UNKNOWN_0x${id.toString(16)}`;
1298
- settings[name] = value;
1299
- }
1300
-
1301
- return settings;
1302
- }
1303
-
1304
-
1305
- function build_settings_frame(settings_named) {
1306
- var frame_payload = [];
1307
-
1308
- for (var name in settings_named) {
1309
- var id = h3_name_to_id[name];
1310
- if (id === undefined) {
1311
- throw new Error("Unknown setting name: " + name);
1312
- }
1313
- var value = settings_named[name];
1314
-
1315
- frame_payload.push(...writeVarInt(id));
1316
- frame_payload.push(...writeVarInt(value));
1317
- }
1318
-
1319
- return new Uint8Array(frame_payload);
1320
- }
1321
-
1322
-
1323
-
1324
- function build_control_stream_old(settings_named) {
1325
- var setting_ids = {
1326
- SETTINGS_QPACK_MAX_TABLE_CAPACITY: 0x01,
1327
- SETTINGS_MAX_FIELD_SECTION_SIZE: 0x06,
1328
- SETTINGS_ENABLE_WEBTRANSPORT: 0x2b603742, // תקני לפי draft
1329
- SETTINGS_H3_DATAGRAM: 0x33, // תקני לפי RFC 9297
1330
- SETTINGS_NO_RFC9114_LEGACY_CODEPOINT: 0x0d,
1331
- SETTINGS_ENABLE_CONNECT_PROTOCOL: 0x08, // תקני לפי RFC 9220
1332
- SETTINGS_WT_MAX_SESSIONS: 0x14E9CD29
1333
- };
1334
-
1335
- var frame_payload = [];
1336
-
1337
- for (var name in settings_named) {
1338
- var id = setting_ids[name];
1339
- if (id === undefined) {
1340
- throw new Error("Unknown setting name: " + name);
1341
- }
1342
-
1343
- var value = settings_named[name];
1344
- frame_payload.push(...writeVarInt(id));
1345
- frame_payload.push(...writeVarInt(value));
1346
- }
1347
-
1348
- var frame_header = [
1349
- ...writeVarInt(0x04), // SETTINGS frame type
1350
- ...writeVarInt(frame_payload.length)
1351
- ];
1352
-
1353
- return new Uint8Array([
1354
- 0x00, // Stream Type: Control Stream
1355
- ...frame_header,
1356
- ...frame_payload
1357
- ]);
1358
- }
1359
-
1360
-
1361
- function encodeInt(value, prefixBits) {
1362
- var max = (1 << prefixBits) - 1;
1363
- if (value < max) return [value]; // נכנס כולו בפריפיקס
1364
- var bytes = [max];
1365
- value -= max;
1366
- while (value >= 128) { // המשך varint (7-bit groups)
1367
- bytes.push((value & 0x7F) | 0x80);
1368
- value >>= 7;
1369
- }
1370
- bytes.push(value);
1371
- return bytes;
1372
- }
1373
-
1374
- function encodeStringLiteral(bytes, hFlag /* 0/1 */) {
1375
- var lenBytes = encodeInt(bytes.length, 7); // prefix-7
1376
- lenBytes[0] |= (hFlag << 7); // מוסיפים H
1377
- return lenBytes.concat(Array.from(bytes));
1378
- }
1379
-
1380
- /* ---------- בניית HEADERS (Literal) ---------- */
1381
- function build_http3_literal_headers_frame(headers) {
1382
- var out = [];
1383
- out.push(0x00, 0x00); // QPACK prefix
1384
-
1385
- for (var header_name in headers) {
1386
- var nameBytes = new TextEncoder().encode(header_name.toLowerCase());
1387
- var valueBytes = new TextEncoder().encode(String(headers[header_name]));
1388
-
1389
- /* בייט ראשון: 001 | N=0 | H=0 | NameLen(3+) */
1390
- var nameLenEnc = encodeInt(nameBytes.length, 3); // prefix-3
1391
- var firstByte = 0x20 | nameLenEnc[0]; // 0b0010_0000
1392
- out.push(firstByte, ...nameLenEnc.slice(1), ...nameBytes);
1393
-
1394
- /* value: H=0 + prefix-7 */
1395
- out.push(...encodeStringLiteral(valueBytes, 0));
1396
- }
1397
- return new Uint8Array(out);
1398
- }
1399
-
1400
-
1401
- function build_qpack_block_header_ack(stream_id) {
1402
- return concatUint8Arrays([
1403
- Uint8Array.from([0x81]), // instruction type
1404
- writeVarInt(stream_id) // full VarInt
1405
- ]);
1406
- }
1407
- function build_qpack_known_received_count(count) {
1408
- if (count <= 0) return null; // אין מה לשלוח
1409
- var buf = writeVarInt(count); // VarInt עם prefix-6
1410
- buf[0] &= 0x3F; // מוודא ששני הביטים העליונים 00
1411
- return buf;
1412
- }
1413
-
1414
-
1415
- function parse_webtransport_datagram(payload) {
1416
- var result = readVarInt(payload, 0);
1417
- if (!result) {
1418
- throw new Error("Invalid VarInt at beginning of payload");
1419
- }
1420
-
1421
- var stream_id = result.value;
1422
- var data = payload.slice(result.byteLength); // שאר ה־payload זה הנתונים
1423
-
1424
- return {
1425
- stream_id: stream_id,
1426
- data: data
1427
- };
1428
- }
1429
-
1430
-
1431
- function build_close_webtransport(errorCode, reason) {
1432
- var reasonBytes = reason ? new TextEncoder().encode(reason) : new Uint8Array();
1433
- var payload = [
1434
- ...writeVarInt(errorCode),
1435
- ...writeVarInt(reasonBytes.length),
1436
- ...reasonBytes
1437
- ];
1438
-
1439
- var frame = [
1440
- ...writeVarInt(0x2843), // type
1441
- ...writeVarInt(payload.length), // length
1442
- ...payload
1443
- ];
1444
-
1445
- return new Uint8Array(frame);
1446
- }
1447
-
1448
- export {
1449
- build_h3_frames,
1450
- build_settings_frame,
1451
- parse_h3_settings_frame,
1452
- extract_qpack_encoder_instructions_from_chunks,
1453
- extract_h3_frames_from_chunks,
1454
- parse_qpack_header_block,
1455
- build_http3_literal_headers_frame,
1456
- parse_webtransport_datagram,
1457
- build_close_webtransport,
1458
- build_qpack_block_header_ack,
1459
- build_qpack_known_received_count,
1460
- qpack_static_table_entries
1461
- };