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/README.md +308 -70
- package/index.cjs +45 -0
- package/index.d.ts +158 -0
- package/index.js +46 -2631
- package/package.json +69 -14
- package/src/agent.js +275 -0
- package/src/client.js +439 -0
- package/src/crypto.js +519 -0
- package/src/h3.js +911 -0
- package/src/h3_client.js +317 -0
- package/src/h3_server.js +523 -0
- package/src/quic_connection.js +1238 -0
- package/src/server.js +346 -0
- package/src/streams.js +471 -0
- package/src/tls_bridge.js +211 -0
- package/src/transport.js +651 -0
- package/src/utils.js +290 -0
- package/src/webtransport.js +708 -0
- package/CHANGELOG.md +0 -25
- package/examples/webtransport_datagram_echo_server/client.html +0 -58
- package/examples/webtransport_datagram_echo_server/server.js +0 -29
- package/libs/crypto.js +0 -2107
- package/libs/h3.js +0 -1214
- package/libs/utils.js +0 -404
- package/quico.svg +0 -1
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
|
-
};
|