quico 0.1.1 → 0.2.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,1214 +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
- var {
20
- concatUint8Arrays,
21
- writeVarInt,
22
- readVarInt
23
- } = require('./utils');
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
- const maxPrefix = (1 << prefixBits) - 1;
419
- let byte = buf[pos];
420
- let value = byte & maxPrefix;
421
- pos++;
422
-
423
- if (value < maxPrefix) // נגמר במרווח-הבייט הראשון
424
- return { value, next: pos };
425
-
426
- let 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
- let pos = 0;
505
- const headers = [];
506
-
507
- // Required Insert Count (prefix-8)
508
- const ric = decodeVarInt(buf, 8, pos);
509
- pos = ric.next;
510
-
511
- // Delta Base (prefix-7 + S-bit)
512
- const firstDbByte = buf[pos];
513
- const postBase = (firstDbByte & 0x80) !== 0; // S-bit
514
- const db = decodeVarInt(buf, 7, pos);
515
- pos = db.next;
516
-
517
- // Base Index = RIC ± DB לפי S-bit
518
- const baseIndex = postBase
519
- ? ric.value + db.value
520
- : ric.value - db.value;
521
-
522
- // Header Field Lines
523
- while (pos < buf.length) {
524
- const byte = buf[pos];
525
-
526
- // A. Indexed Field Line – 1xxxxxxx
527
- if ((byte & 0x80) === 0x80) {
528
- const fromStatic = (byte & 0x40) !== 0; // T-bit
529
- const 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
- const neverIndexed = (byte & 0x20) !== 0; // N-bit
542
- const fromStatic = (byte & 0x10) !== 0; // T-bit
543
- const nameIdx = decodeVarInt(buf, 4, pos); // prefix-4
544
- pos = nameIdx.next;
545
-
546
- const valH = (buf[pos] & 0x80) !== 0;
547
- const valLen = decodeVarInt(buf, 7, pos); // prefix-7
548
- pos = valLen.next;
549
-
550
- const valBytes = buf.slice(pos, pos + valLen.value);
551
- pos += valLen.value;
552
- const 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
- const neverIndexed = (byte & 0x10) !== 0; // N-bit
569
- const nameH = (byte & 0x08) !== 0; // H-bit
570
- const nameLen = decodeVarInt(buf, 3, pos); // prefix-3
571
- pos = nameLen.next;
572
-
573
- const nameBytes = buf.slice(pos, pos + nameLen.value);
574
- pos += nameLen.value;
575
- const name = nameH ? decodeHuffman(nameBytes)
576
- : new TextDecoder().decode(nameBytes);
577
-
578
- const valH = (buf[pos] & 0x80) !== 0; // H-bit
579
- const valLen = decodeVarInt(buf, 7, pos); // prefix-7
580
- pos = valLen.next;
581
-
582
- const valBytes = buf.slice(pos, pos + valLen.value);
583
- pos += valLen.value;
584
- const 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
- let pos = 0;
614
- const headers = [];
615
-
616
- /* 1) Field-section prefix */
617
- const ric = decodeVarInt(buf, 8, pos); // Required Insert Count (prefix-8)
618
- pos = ric.next;
619
-
620
- const 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
- const byte = buf[pos];
626
-
627
- /* A. Indexed Field Line – 1xxxxxxx */
628
- if ((byte & 0x80) === 0x80) {
629
- const fromStatic = (byte & 0x40) !== 0; // T-bit
630
- const 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
- const neverIndexed = (byte & 0x20) !== 0; // N-bit
643
- const fromStatic = (byte & 0x10) !== 0; // T-bit
644
- const nameIdx = decodeVarInt(buf, 4, pos); // prefix-4
645
- pos = nameIdx.next;
646
-
647
- const valH = (buf[pos] & 0x80) !== 0;
648
- const valLen = decodeVarInt(buf, 7, pos); // prefix-7
649
- pos = valLen.next;
650
-
651
- const valBytes = buf.slice(pos, pos + valLen.value);
652
- pos += valLen.value;
653
- const 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
- const neverIndexed = (byte & 0x10) !== 0; // N-bit
670
- const nameH = (byte & 0x08) !== 0; // H-bit (שם) :contentReference[oaicite:0]{index=0}
671
- const nameLen = decodeVarInt(buf, 3, pos); // prefix-3
672
- pos = nameLen.next;
673
-
674
- const nameBytes = buf.slice(pos, pos + nameLen.value);
675
- pos += nameLen.value;
676
- const name = nameH ? decodeHuffman(nameBytes)
677
- : new TextDecoder().decode(nameBytes);
678
-
679
- const valH = (buf[pos] & 0x80) !== 0; // H-bit (ערך)
680
- const valLen = decodeVarInt(buf, 7, pos); // prefix-7
681
- pos = valLen.next;
682
-
683
- const valBytes = buf.slice(pos, pos + valLen.value);
684
- pos += valLen.value;
685
- const 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
- function extract_h3_frames_from_chunks(chunks, from_offset) {
716
- var offsets = Object.keys(chunks).map(Number).sort((a, b) => a - b);
717
- var buffers = [];
718
- var totalLength = 0;
719
-
720
- // מחברים את כל הצ’אנקים החל מ־from_offset
721
- for (var i = 0; i < offsets.length; i++) {
722
- var base = offsets[i];
723
- var chunk = chunks[base];
724
- if (from_offset >= base && from_offset < base + chunk.length) {
725
- var start = from_offset - base;
726
- var sliced = chunk.slice(start);
727
- buffers.push(sliced);
728
- totalLength += sliced.length;
729
-
730
- for (var j = i + 1; j < offsets.length; j++) {
731
- buffers.push(chunks[offsets[j]]);
732
- totalLength += chunks[offsets[j]].length;
733
- }
734
-
735
- break;
736
- }
737
- }
738
-
739
- if (buffers.length === 0) return { frames: [], new_from_offset: from_offset };
740
-
741
- var combined = concatUint8Arrays(buffers);
742
- var offset = 0;
743
- var frames = [];
744
-
745
- // פונקציית עזר בטוחה לקריאת VarInt
746
- function safeReadVarInt() {
747
- if (offset >= combined.length) return null;
748
- var firstByte = combined[offset];
749
- var lengthBits = firstByte >> 6;
750
- var neededLength = 1 << lengthBits;
751
- if (offset + neededLength > combined.length) return null;
752
- var res = readVarInt(combined, offset);
753
- if (!res || typeof res.byteLength !== 'number') return null;
754
- offset += res.byteLength;
755
- return res;
756
- }
757
-
758
- while (offset < combined.length) {
759
- var startOffset = offset;
760
-
761
- var frameType = safeReadVarInt();
762
- if (!frameType) break;
763
-
764
- var lengthInfo = safeReadVarInt();
765
- if (!lengthInfo) {
766
- offset = startOffset; // rollback – אי אפשר אפילו לקרוא אורך
767
- break;
768
- }
769
-
770
- var payloadLength = lengthInfo.value;
771
- if (offset + payloadLength > combined.length) {
772
- offset = startOffset; // rollback
773
- break;
774
- }
775
-
776
- var payload = combined.slice(offset, offset + payloadLength);
777
- frames.push({ frame_type: frameType.value, payload });
778
- offset += payloadLength;
779
- }
780
-
781
- // עדכון chunks כדי להסיר את מה שקראנו
782
- if (offset > 0) {
783
- var bytesToRemove = offset;
784
- var newChunks = {};
785
- var processed = 0;
786
- var currentOffset = from_offset;
787
-
788
- for (var k = 0; k < offsets.length; k++) {
789
- var base = offsets[k];
790
- var chunk = chunks[base];
791
-
792
- if (currentOffset >= base + chunk.length) continue;
793
-
794
- var relStart = Math.max(currentOffset - base, 0);
795
- var relEnd = Math.min(chunk.length, currentOffset + bytesToRemove - base);
796
- if (relEnd < chunk.length) {
797
- var leftover = chunk.slice(relEnd);
798
- var newBase = base + relEnd;
799
- newChunks[newBase] = leftover;
800
- }
801
-
802
- bytesToRemove -= (relEnd - relStart);
803
- if (bytesToRemove <= 0) break;
804
- }
805
-
806
- for (var key in chunks) delete chunks[key];
807
- for (var key in newChunks) chunks[key] = newChunks[key];
808
- from_offset += offset;
809
- }
810
-
811
- return { frames, new_from_offset: from_offset };
812
- }
813
-
814
-
815
-
816
-
817
- function build_h3_frames(frames) {
818
- var parts = [];
819
-
820
- for (var i = 0; i < frames.length; i++) {
821
- var frame = frames[i];
822
-
823
- // כל חלק מהפריים כ־Uint8Array
824
- var typeBytes = writeVarInt(frame.frame_type);
825
- var lenBytes = writeVarInt(frame.payload.length);
826
- var payload = frame.payload;
827
-
828
- parts.push(typeBytes, lenBytes, payload);
829
- }
830
-
831
- return concatUint8Arrays(parts);
832
-
833
- }
834
-
835
-
836
-
837
- /* חישוב אורך varint לפי HPACK/QPACK (prefix-N) */
838
- function computeVarIntLen(buf, pos, prefixBits) {
839
- if (pos >= buf.length) return null;
840
- var first = buf[pos];
841
- var prefixMask = (1 << prefixBits) - 1;
842
- var prefixVal = first & prefixMask;
843
-
844
- // אם הערך קטן מהמקסימום – varint של בייט אחד
845
- if (prefixVal < prefixMask) return 1;
846
-
847
- // אחרת ממשיכים ב-Base128 עד שבייט בלי MSB=1
848
- var len = 1;
849
- var idx = pos + 1;
850
- while (idx < buf.length) {
851
- len++;
852
- if ((buf[idx] & 0x80) === 0) return len; // הסתיים
853
- idx++;
854
- }
855
- return null; // חסר נתונים
856
- }
857
-
858
- /* קריאה בטוחה של varint */
859
- function safeDecodeVarInt(buf, posRef, prefixBits) {
860
- var len = computeVarIntLen(buf, posRef.pos, prefixBits);
861
- if (len === null) return null; // לא שלם
862
-
863
- var res = decodeVarInt(buf, prefixBits, posRef.pos); // הפונקציה שלך
864
- posRef.pos = res.next;
865
- return res.value;
866
- }
867
-
868
- /* ---------- פונקציית החילוץ העיקרית ---------- */
869
-
870
- function extract_qpack_encoder_instructions_from_chunks(chunks, from_offset) {
871
- /* 1) חיבור הצ’אנקים החל מ-from_offset */
872
- var offsets = Object.keys(chunks).map(Number).sort(function (a, b) { return a - b; });
873
- var buffers = [];
874
- var totalLen = 0;
875
-
876
- for (var i = 0; i < offsets.length; i++) {
877
- var base = offsets[i];
878
- var chunk = chunks[base];
879
- if (from_offset >= base && from_offset < base + chunk.length) {
880
- var start = from_offset - base;
881
- var sliced = chunk.slice(start);
882
- buffers.push(sliced);
883
- totalLen += sliced.length;
884
-
885
- for (var j = i + 1; j < offsets.length; j++) {
886
- buffers.push(chunks[offsets[j]]);
887
- totalLen += chunks[offsets[j]].length;
888
- }
889
- break;
890
- }
891
- }
892
-
893
- if (buffers.length === 0) {
894
- return { instructions: [], new_from_offset: from_offset };
895
- }
896
-
897
- var combined = concatUint8Arrays(buffers);
898
- var posRef = { pos: 0 };
899
- var instructions = [];
900
-
901
- /* 2) לולאת פיענוח ההוראות */
902
- while (posRef.pos < combined.length) {
903
- var startPos = posRef.pos;
904
- var byte = combined[posRef.pos];
905
-
906
- /* --- A. Insert With Name Reference (1xxxxxxx) --- */
907
- if ((byte & 0x80) === 0x80) {
908
- var fromStatic = (byte & 0x40) !== 0;
909
- var nameIdx = safeDecodeVarInt(combined, posRef, 6);
910
- if (nameIdx === null) break; // לא שלם
911
-
912
- // value length
913
- var valHuffman = (combined[posRef.pos] & 0x80) !== 0;
914
- var valLen = safeDecodeVarInt(combined, posRef, 7);
915
- if (valLen === null || posRef.pos + valLen > combined.length) {
916
- posRef.pos = startPos; break;
917
- }
918
-
919
- var valBytes = combined.slice(posRef.pos, posRef.pos + valLen);
920
- posRef.pos += valLen;
921
-
922
- var value = valHuffman ? decodeHuffman(valBytes)
923
- : new TextDecoder().decode(valBytes);
924
-
925
- instructions.push({
926
- type: 'insert_with_name_ref',
927
- from_static_table: fromStatic,
928
- name_index: nameIdx,
929
- value: value
930
- });
931
- continue;
932
- }
933
-
934
- /* --- B. Insert Without Name Reference (01xxxxxx) --- */
935
- if ((byte & 0xC0) === 0x40) {
936
- var nameH = (byte & 0x20) !== 0;
937
- var nameLen = safeDecodeVarInt(combined, posRef, 5);
938
- if (nameLen === null || posRef.pos + nameLen > combined.length) {
939
- posRef.pos = startPos; break;
940
- }
941
- var nameBytes = combined.slice(posRef.pos, posRef.pos + nameLen);
942
- posRef.pos += nameLen;
943
-
944
- var valH = (combined[posRef.pos] & 0x80) !== 0;
945
- var valLen2 = safeDecodeVarInt(combined, posRef, 7);
946
- if (valLen2 === null || posRef.pos + valLen2 > combined.length) {
947
- posRef.pos = startPos; break;
948
- }
949
- var valBytes2 = combined.slice(posRef.pos, posRef.pos + valLen2);
950
- posRef.pos += valLen2;
951
-
952
- var nameStr = nameH ? decodeHuffman(nameBytes)
953
- : new TextDecoder().decode(nameBytes);
954
- var valueStr = valH ? decodeHuffman(valBytes2)
955
- : new TextDecoder().decode(valBytes2);
956
-
957
- instructions.push({
958
- type: 'insert_without_name_ref',
959
- name: nameStr,
960
- value: valueStr
961
- });
962
- continue;
963
- }
964
-
965
- /* --- C. Set Dynamic Table Capacity (001xxxxx) --- */
966
- if ((byte & 0xE0) === 0x20) {
967
- var capacity = safeDecodeVarInt(combined, posRef, 5);
968
- if (capacity === null) { posRef.pos = startPos; break; }
969
-
970
- instructions.push({
971
- type: 'set_dynamic_table_capacity',
972
- capacity: capacity
973
- });
974
- continue;
975
- }
976
-
977
- /* --- D. Duplicate (0000xxxx) --- */
978
- if ((byte & 0xF0) === 0x00) {
979
- var dupIndex = safeDecodeVarInt(combined, posRef, 4);
980
- if (dupIndex === null) { posRef.pos = startPos; break; }
981
-
982
- instructions.push({
983
- type: 'duplicate',
984
- index: dupIndex
985
- });
986
- continue;
987
- }
988
-
989
- /* לא מוכר - נעצור */
990
- break;
991
- }
992
-
993
- var consumed = posRef.pos; // כמה בייטים הצלחנו לפרש
994
-
995
- /* 3) ניקוי הצ’אנקים והתקדמות from_offset */
996
- if (consumed > 0) {
997
- var bytesLeft = consumed;
998
- var newChunks = {};
999
- var currOff = from_offset;
1000
-
1001
- for (var k = 0; k < offsets.length; k++) {
1002
- var base = offsets[k];
1003
- var chunk = chunks[base];
1004
-
1005
- if (currOff >= base + chunk.length) continue;
1006
-
1007
- var relStart = Math.max(currOff - base, 0);
1008
- var relEnd = Math.min(chunk.length, currOff + bytesLeft - base);
1009
-
1010
- if (relEnd < chunk.length) {
1011
- var leftover = chunk.slice(relEnd);
1012
- newChunks[base + relEnd] = leftover;
1013
- }
1014
-
1015
- bytesLeft -= (relEnd - relStart);
1016
- if (bytesLeft <= 0) break;
1017
- }
1018
-
1019
- for (var key in chunks) delete chunks[key];
1020
- for (var nk in newChunks) chunks[nk] = newChunks[nk];
1021
-
1022
- from_offset += consumed;
1023
- }
1024
-
1025
- return { instructions: instructions, new_from_offset: from_offset };
1026
- }
1027
-
1028
-
1029
-
1030
- var h3_settings_frame_params = [
1031
- [0x01, "SETTINGS_QPACK_MAX_TABLE_CAPACITY"],
1032
- [0x06, "SETTINGS_MAX_FIELD_SECTION_SIZE"],
1033
- [0x07, "SETTINGS_QPACK_BLOCKED_STREAMS"],
1034
- [0x08, "SETTINGS_ENABLE_CONNECT_PROTOCOL"],
1035
- [0x33, "SETTINGS_H3_DATAGRAM"],
1036
- [0x2b603742, "SETTINGS_ENABLE_WEBTRANSPORT"], // תקני לפי draft
1037
- [0x0d, "SETTINGS_NO_RFC9114_LEGACY_CODEPOINT"],
1038
- [0x14E9CD29, "SETTINGS_WT_MAX_SESSIONS"],
1039
- [0x4d44, "SETTINGS_ENABLE_METADATA"] // provisional
1040
- ];
1041
-
1042
- var h3_name_to_id = {};
1043
- var h3_id_to_name = {};
1044
-
1045
- for (var i = 0; i < h3_settings_frame_params.length; i++) {
1046
- var [id, name] = h3_settings_frame_params[i];
1047
- h3_name_to_id[name] = id;
1048
- h3_id_to_name[id] = name;
1049
- }
1050
-
1051
-
1052
-
1053
- function parse_h3_settings_frame(buf) {
1054
- var settings = {};
1055
- var offset = 0;
1056
-
1057
- while (offset < buf.length) {
1058
- var idRes = readVarInt(buf, offset);
1059
- if (!idRes) break;
1060
- offset += idRes.byteLength;
1061
-
1062
- var valRes = readVarInt(buf, offset);
1063
- if (!valRes) break;
1064
- offset += valRes.byteLength;
1065
-
1066
- var id = idRes.value;
1067
- var value = valRes.value;
1068
-
1069
- var name = h3_id_to_name[id] || `UNKNOWN_0x${id.toString(16)}`;
1070
- settings[name] = value;
1071
- }
1072
-
1073
- return settings;
1074
- }
1075
-
1076
-
1077
- function build_settings_frame(settings_named) {
1078
- var frame_payload = [];
1079
-
1080
- for (var name in settings_named) {
1081
- var id = h3_name_to_id[name];
1082
- if (id === undefined) {
1083
- throw new Error("Unknown setting name: " + name);
1084
- }
1085
- var value = settings_named[name];
1086
-
1087
- frame_payload.push(...writeVarInt(id));
1088
- frame_payload.push(...writeVarInt(value));
1089
- }
1090
-
1091
- return new Uint8Array(frame_payload);
1092
- }
1093
-
1094
-
1095
-
1096
- function build_control_stream_old(settings_named) {
1097
- var setting_ids = {
1098
- SETTINGS_QPACK_MAX_TABLE_CAPACITY: 0x01,
1099
- SETTINGS_MAX_FIELD_SECTION_SIZE: 0x06,
1100
- SETTINGS_ENABLE_WEBTRANSPORT: 0x2b603742, // תקני לפי draft
1101
- SETTINGS_H3_DATAGRAM: 0x33, // תקני לפי RFC 9297
1102
- SETTINGS_NO_RFC9114_LEGACY_CODEPOINT: 0x0d,
1103
- SETTINGS_ENABLE_CONNECT_PROTOCOL: 0x08, // תקני לפי RFC 9220
1104
- SETTINGS_WT_MAX_SESSIONS: 0x14E9CD29
1105
- };
1106
-
1107
- var frame_payload = [];
1108
-
1109
- for (var name in settings_named) {
1110
- var id = setting_ids[name];
1111
- if (id === undefined) {
1112
- throw new Error("Unknown setting name: " + name);
1113
- }
1114
-
1115
- var value = settings_named[name];
1116
- frame_payload.push(...writeVarInt(id));
1117
- frame_payload.push(...writeVarInt(value));
1118
- }
1119
-
1120
- var frame_header = [
1121
- ...writeVarInt(0x04), // SETTINGS frame type
1122
- ...writeVarInt(frame_payload.length)
1123
- ];
1124
-
1125
- return new Uint8Array([
1126
- 0x00, // Stream Type: Control Stream
1127
- ...frame_header,
1128
- ...frame_payload
1129
- ]);
1130
- }
1131
-
1132
-
1133
- function encodeInt(value, prefixBits) {
1134
- const max = (1 << prefixBits) - 1;
1135
- if (value < max) return [value]; // נכנס כולו בפריפיקס
1136
- const bytes = [max];
1137
- value -= max;
1138
- while (value >= 128) { // המשך varint (7-bit groups)
1139
- bytes.push((value & 0x7F) | 0x80);
1140
- value >>= 7;
1141
- }
1142
- bytes.push(value);
1143
- return bytes;
1144
- }
1145
-
1146
- function encodeStringLiteral(bytes, hFlag /* 0/1 */) {
1147
- const lenBytes = encodeInt(bytes.length, 7); // prefix-7
1148
- lenBytes[0] |= (hFlag << 7); // מוסיפים H
1149
- return lenBytes.concat(Array.from(bytes));
1150
- }
1151
-
1152
- /* ---------- בניית HEADERS (Literal) ---------- */
1153
- function build_http3_literal_headers_frame(headers) {
1154
- const out = [];
1155
- out.push(0x00, 0x00); // QPACK prefix
1156
-
1157
- for (var header_name in headers) {
1158
- const nameBytes = new TextEncoder().encode(header_name.toLowerCase());
1159
- const valueBytes = new TextEncoder().encode(String(headers[header_name]));
1160
-
1161
- /* בייט ראשון: 001 | N=0 | H=0 | NameLen(3+) */
1162
- const nameLenEnc = encodeInt(nameBytes.length, 3); // prefix-3
1163
- const firstByte = 0x20 | nameLenEnc[0]; // 0b0010_0000
1164
- out.push(firstByte, ...nameLenEnc.slice(1), ...nameBytes);
1165
-
1166
- /* value: H=0 + prefix-7 */
1167
- out.push(...encodeStringLiteral(valueBytes, 0));
1168
- }
1169
- return new Uint8Array(out);
1170
- }
1171
-
1172
-
1173
- function build_qpack_block_header_ack(stream_id) {
1174
- return concatUint8Arrays([
1175
- Uint8Array.from([0x81]), // instruction type
1176
- writeVarInt(stream_id) // full VarInt
1177
- ]);
1178
- }
1179
- function build_qpack_known_received_count(count) {
1180
- if (count <= 0) return null; // אין מה לשלוח
1181
- var buf = writeVarInt(count); // VarInt עם prefix-6
1182
- buf[0] &= 0x3F; // מוודא ששני הביטים העליונים 00
1183
- return buf;
1184
- }
1185
-
1186
-
1187
- function parse_webtransport_datagram(payload) {
1188
- var result = readVarInt(payload, 0);
1189
- if (!result) {
1190
- throw new Error("Invalid VarInt at beginning of payload");
1191
- }
1192
-
1193
- var stream_id = result.value;
1194
- var data = payload.slice(result.byteLength); // שאר ה־payload זה הנתונים
1195
-
1196
- return {
1197
- stream_id: stream_id,
1198
- data: data
1199
- };
1200
- }
1201
-
1202
- module.exports = {
1203
- build_h3_frames,
1204
- build_settings_frame,
1205
- parse_h3_settings_frame,
1206
- extract_qpack_encoder_instructions_from_chunks,
1207
- extract_h3_frames_from_chunks,
1208
- parse_qpack_header_block,
1209
- build_http3_literal_headers_frame,
1210
- parse_webtransport_datagram,
1211
- build_qpack_block_header_ack,
1212
- build_qpack_known_received_count,
1213
- qpack_static_table_entries
1214
- };