quico 0.1.3 → 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 +381 -216
- package/index.cjs +45 -0
- package/index.d.ts +158 -0
- package/index.js +46 -23
- package/package.json +83 -60
- 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 -31
- package/examples/webtransport_datagram_echo_server/client.html +0 -58
- package/examples/webtransport_datagram_echo_server/server.js +0 -23
- package/h3_server.js +0 -416
- package/h3_socket.js +0 -473
- package/libs/crypto.js +0 -1841
- package/libs/h3.js +0 -1461
- package/libs/utils.js +0 -404
- package/quic_socket.js +0 -1550
- package/quico.svg +0 -1
package/libs/utils.js
DELETED
|
@@ -1,404 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
function writeVarInt(value) {
|
|
3
|
-
if (value < 0x40) {
|
|
4
|
-
// 1 byte, prefix 00
|
|
5
|
-
return new Uint8Array([value]); // אין צורך ב־& 0x3f
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
if (value < 0x4000) {
|
|
9
|
-
// 2 bytes, prefix 01
|
|
10
|
-
return new Uint8Array([
|
|
11
|
-
0x40 | (value >> 8),
|
|
12
|
-
value & 0xff
|
|
13
|
-
]);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
if (value < 0x40000000) {
|
|
17
|
-
// 4 bytes, prefix 10
|
|
18
|
-
return new Uint8Array([
|
|
19
|
-
0x80 | (value >> 24),
|
|
20
|
-
(value >> 16) & 0xff,
|
|
21
|
-
(value >> 8) & 0xff,
|
|
22
|
-
value & 0xff
|
|
23
|
-
]);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (value <= Number.MAX_SAFE_INTEGER) {
|
|
27
|
-
var hi = Math.floor(value / 2 ** 32);
|
|
28
|
-
var lo = value >>> 0;
|
|
29
|
-
return new Uint8Array([
|
|
30
|
-
0xC0 | (hi >> 24),
|
|
31
|
-
(hi >> 16) & 0xff,
|
|
32
|
-
(hi >> 8) & 0xff,
|
|
33
|
-
hi & 0xff,
|
|
34
|
-
(lo >> 24) & 0xff,
|
|
35
|
-
(lo >> 16) & 0xff,
|
|
36
|
-
(lo >> 8) & 0xff,
|
|
37
|
-
lo & 0xff
|
|
38
|
-
]);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
throw new Error("Value too large for QUIC VarInt");
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
function writeVarInt2(value) {
|
|
46
|
-
if (value < 0x40) {
|
|
47
|
-
// 1 byte
|
|
48
|
-
return new Uint8Array([value & 0x3f]);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (value < 0x4000) {
|
|
52
|
-
// 2 bytes
|
|
53
|
-
return new Uint8Array([
|
|
54
|
-
0x40 | ((value >> 8) & 0x3f),
|
|
55
|
-
value & 0xff
|
|
56
|
-
]);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (value < 0x40000000) {
|
|
60
|
-
// 4 bytes
|
|
61
|
-
return new Uint8Array([
|
|
62
|
-
0x80 | ((value >> 24) & 0x3f),
|
|
63
|
-
(value >> 16) & 0xff,
|
|
64
|
-
(value >> 8) & 0xff,
|
|
65
|
-
value & 0xff
|
|
66
|
-
]);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (value <= Number.MAX_SAFE_INTEGER) {
|
|
70
|
-
var hi = Math.floor(value / 2 ** 32);
|
|
71
|
-
var lo = value >>> 0;
|
|
72
|
-
return new Uint8Array([
|
|
73
|
-
0xC0 | ((hi >> 24) & 0x3f),
|
|
74
|
-
(hi >> 16) & 0xff,
|
|
75
|
-
(hi >> 8) & 0xff,
|
|
76
|
-
hi & 0xff,
|
|
77
|
-
(lo >> 24) & 0xff,
|
|
78
|
-
(lo >> 16) & 0xff,
|
|
79
|
-
(lo >> 8) & 0xff,
|
|
80
|
-
lo & 0xff
|
|
81
|
-
]);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
throw new Error("Value too large for QUIC VarInt");
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
function readVarInt(array, offset) {
|
|
90
|
-
if (offset >= array.length) return null;
|
|
91
|
-
|
|
92
|
-
var first = array[offset];
|
|
93
|
-
var prefix = first >> 6;
|
|
94
|
-
|
|
95
|
-
if (prefix === 0b00) {
|
|
96
|
-
return {
|
|
97
|
-
value: first & 0x3f,
|
|
98
|
-
byteLength: 1
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (prefix === 0b01) {
|
|
103
|
-
if (offset + 1 >= array.length) return null;
|
|
104
|
-
var value = ((first & 0x3f) << 8) | array[offset + 1];
|
|
105
|
-
return {
|
|
106
|
-
value,
|
|
107
|
-
byteLength: 2
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (prefix === 0b10) {
|
|
112
|
-
if (offset + 3 >= array.length) return null;
|
|
113
|
-
var value = (
|
|
114
|
-
((first & 0x3F) << 24) |
|
|
115
|
-
(array[offset + 1] << 16) |
|
|
116
|
-
(array[offset + 2] << 8) |
|
|
117
|
-
array[offset + 3]
|
|
118
|
-
) >>> 0;
|
|
119
|
-
return {
|
|
120
|
-
value,
|
|
121
|
-
byteLength: 4
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (prefix === 0b11) {
|
|
126
|
-
if (offset + 7 >= array.length) return null;
|
|
127
|
-
|
|
128
|
-
var hi = (
|
|
129
|
-
((first & 0x3F) << 24) |
|
|
130
|
-
(array[offset + 1] << 16) |
|
|
131
|
-
(array[offset + 2] << 8) |
|
|
132
|
-
array[offset + 3]
|
|
133
|
-
) >>> 0;
|
|
134
|
-
|
|
135
|
-
var lo = (
|
|
136
|
-
(array[offset + 4] << 24) |
|
|
137
|
-
(array[offset + 5] << 16) |
|
|
138
|
-
(array[offset + 6] << 8) |
|
|
139
|
-
array[offset + 7]
|
|
140
|
-
) >>> 0;
|
|
141
|
-
|
|
142
|
-
var full = BigInt(hi) * 4294967296n + BigInt(lo); // 2^32
|
|
143
|
-
|
|
144
|
-
if (full <= BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
145
|
-
return {
|
|
146
|
-
value: Number(full),
|
|
147
|
-
byteLength: 8
|
|
148
|
-
};
|
|
149
|
-
} else {
|
|
150
|
-
return {
|
|
151
|
-
value: full,
|
|
152
|
-
byteLength: 8
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return null;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
function concatUint8Arrays(arrays) {
|
|
163
|
-
var totalLength = 0;
|
|
164
|
-
for (var i = 0; i < arrays.length; i++) {
|
|
165
|
-
totalLength += arrays[i].length;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
var result = new Uint8Array(totalLength);
|
|
169
|
-
var offset = 0;
|
|
170
|
-
|
|
171
|
-
for (var i = 0; i < arrays.length; i++) {
|
|
172
|
-
result.set(arrays[i], offset);
|
|
173
|
-
offset += arrays[i].length;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return result;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function arraybufferEqual(buf1, buf2) {
|
|
180
|
-
//if (buf1 === buf2) {
|
|
181
|
-
//return true;
|
|
182
|
-
//}
|
|
183
|
-
|
|
184
|
-
if (buf1.byteLength !== buf2.byteLength) {
|
|
185
|
-
return false;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
var view1 = new DataView(buf1);
|
|
189
|
-
var view2 = new DataView(buf2);
|
|
190
|
-
|
|
191
|
-
for (var i = 0; i < buf1.byteLength; i++) {
|
|
192
|
-
if (view1.getUint8(i) !== view2.getUint8(i)) {
|
|
193
|
-
return false;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return true;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
function buildAckFrameFromPackets(packets, ecnStats, ackDelay) {
|
|
203
|
-
if (!packets || packets.length === 0) return null;
|
|
204
|
-
|
|
205
|
-
var sorted = packets.slice().sort((a, b) => b - a);
|
|
206
|
-
|
|
207
|
-
var ranges = [];
|
|
208
|
-
var rangeStart = sorted[0];
|
|
209
|
-
var rangeEnd = rangeStart;
|
|
210
|
-
var lastPn = rangeStart;
|
|
211
|
-
|
|
212
|
-
for (var i = 1; i < sorted.length; i++) {
|
|
213
|
-
var pn = sorted[i];
|
|
214
|
-
if (pn === lastPn - 1) {
|
|
215
|
-
lastPn = pn;
|
|
216
|
-
} else {
|
|
217
|
-
ranges.push({ start: lastPn, end: rangeEnd });
|
|
218
|
-
rangeEnd = pn;
|
|
219
|
-
lastPn = pn;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
ranges.push({ start: lastPn, end: rangeEnd });
|
|
223
|
-
|
|
224
|
-
var firstRange = ranges[0].end - ranges[0].start;
|
|
225
|
-
var ackRanges = [];
|
|
226
|
-
|
|
227
|
-
for (var i = 1; i < ranges.length; i++) {
|
|
228
|
-
var gap = ranges[i - 1].start - ranges[i].end - 1;
|
|
229
|
-
var length = ranges[i].end - ranges[i].start;
|
|
230
|
-
ackRanges.push({ gap: gap, length: length });
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
var frame = {
|
|
234
|
-
type: 'ack',
|
|
235
|
-
largest: sorted[0],
|
|
236
|
-
delay: ackDelay || 0, // ← כאן מכניסים את ה־delay שחושב
|
|
237
|
-
firstRange: firstRange,
|
|
238
|
-
ranges: ackRanges
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
if (ecnStats) {
|
|
242
|
-
frame.ecn = {
|
|
243
|
-
ect0: ecnStats.ect0 || 0,
|
|
244
|
-
ect1: ecnStats.ect1 || 0,
|
|
245
|
-
ce: ecnStats.ce || 0
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
return frame;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
function build_ack_info_from_ranges(flatRanges, ecnStats, ackDelay) {
|
|
253
|
-
if (!flatRanges || flatRanges.length === 0) return null;
|
|
254
|
-
if (flatRanges.length % 2 !== 0) throw new Error("flatRanges must be in [from, to, ...] pairs");
|
|
255
|
-
|
|
256
|
-
var ranges = [];
|
|
257
|
-
for (var i = 0; i < flatRanges.length; i += 2) {
|
|
258
|
-
var from = flatRanges[i];
|
|
259
|
-
var to = flatRanges[i + 1];
|
|
260
|
-
if (to < from) throw new Error("Range end must be >= start");
|
|
261
|
-
ranges.push({ start: from, end: to });
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Sort ranges from highest to lowest end
|
|
265
|
-
ranges.sort((a, b) => b.end - a.end);
|
|
266
|
-
|
|
267
|
-
// Merge overlapping or adjacent ranges
|
|
268
|
-
var merged = [ranges[0]];
|
|
269
|
-
for (var i = 1; i < ranges.length; i++) {
|
|
270
|
-
var last = merged[merged.length - 1];
|
|
271
|
-
var curr = ranges[i];
|
|
272
|
-
if (curr.end >= last.start - 1) {
|
|
273
|
-
// Merge them
|
|
274
|
-
last.start = Math.min(last.start, curr.start);
|
|
275
|
-
} else {
|
|
276
|
-
merged.push(curr);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
var largest = merged[0].end;
|
|
281
|
-
var firstRange = largest - merged[0].start;
|
|
282
|
-
var ackRanges = [];
|
|
283
|
-
|
|
284
|
-
for (var i = 1; i < merged.length; i++) {
|
|
285
|
-
var gap = merged[i - 1].start - merged[i].end - 1;
|
|
286
|
-
var length = merged[i].end - merged[i].start;
|
|
287
|
-
ackRanges.push({ gap: gap, length: length });
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
return {
|
|
291
|
-
type: 'ack',
|
|
292
|
-
largest: largest,
|
|
293
|
-
delay: ackDelay || 0,
|
|
294
|
-
firstRange: firstRange,
|
|
295
|
-
ranges: ackRanges,
|
|
296
|
-
ecn: ecnStats ? {
|
|
297
|
-
ect0: ecnStats.ect0 || 0,
|
|
298
|
-
ect1: ecnStats.ect1 || 0,
|
|
299
|
-
ce: ecnStats.ce || 0
|
|
300
|
-
} : null
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
function build_ack_info_from_ranges2(flatRanges, ecnStats, ackDelay) {
|
|
306
|
-
if (!flatRanges || flatRanges.length === 0) return null;
|
|
307
|
-
if (flatRanges.length % 2 !== 0) throw new Error("flatRanges must be in [from, to, ...] pairs");
|
|
308
|
-
|
|
309
|
-
// בניית טווחים מלאים
|
|
310
|
-
var ranges = [];
|
|
311
|
-
for (var i = 0; i < flatRanges.length; i += 2) {
|
|
312
|
-
var from = flatRanges[i];
|
|
313
|
-
var to = flatRanges[i + 1];
|
|
314
|
-
if (to < from) throw new Error("Range end must be >= start");
|
|
315
|
-
ranges.push({ start: from, end: to });
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// ממיינים מהגדול לקטן לפי end
|
|
319
|
-
ranges.sort(function (a, b) { return b.end - a.end; });
|
|
320
|
-
|
|
321
|
-
// הסרת טווחים חופפים או לא חוקיים
|
|
322
|
-
for (var i = 1; i < ranges.length; i++) {
|
|
323
|
-
if (ranges[i].end >= ranges[i - 1].start) {
|
|
324
|
-
throw new Error("Overlapping ranges are not allowed");
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
// התחלת ack מהטווח הגבוה ביותר
|
|
329
|
-
var largest = ranges[0].end;
|
|
330
|
-
var firstRange = largest - ranges[0].start;
|
|
331
|
-
|
|
332
|
-
var ackRanges = [];
|
|
333
|
-
var runningEnd = ranges[0].start - 1;
|
|
334
|
-
|
|
335
|
-
for (var i = 1; i < ranges.length; i++) {
|
|
336
|
-
var gap = runningEnd - ranges[i].end - 1;
|
|
337
|
-
var length = ranges[i].end - ranges[i].start;
|
|
338
|
-
|
|
339
|
-
// בדיקה אם הבלוק הבא יגלוש מתחת ל־0
|
|
340
|
-
var nextEnd = runningEnd - (gap + 1 + length);
|
|
341
|
-
if (nextEnd < 0) {
|
|
342
|
-
console.warn("Skipped range due to underflow risk:", ranges[i]);
|
|
343
|
-
continue; // לא מוסיפים את הטווח הזה
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
ackRanges.push({ gap: gap, length: length });
|
|
347
|
-
runningEnd = ranges[i].start - 1;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
var frame = {
|
|
351
|
-
type: 'ack',
|
|
352
|
-
largest: largest,
|
|
353
|
-
delay: ackDelay || 0,
|
|
354
|
-
firstRange: firstRange,
|
|
355
|
-
ranges: ackRanges,
|
|
356
|
-
ecn: ecnStats ? {
|
|
357
|
-
ect0: ecnStats.ect0 || 0,
|
|
358
|
-
ect1: ecnStats.ect1 || 0,
|
|
359
|
-
ce: ecnStats.ce || 0
|
|
360
|
-
} : null
|
|
361
|
-
};
|
|
362
|
-
|
|
363
|
-
return frame;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
function quic_acked_info_to_ranges(ackFrame) {
|
|
369
|
-
var flatRanges = [];
|
|
370
|
-
|
|
371
|
-
if (!ackFrame || ackFrame.type !== 'ack') return flatRanges;
|
|
372
|
-
|
|
373
|
-
var largest = ackFrame.largest;
|
|
374
|
-
var firstRange = ackFrame.firstRange;
|
|
375
|
-
|
|
376
|
-
// טווח ראשון: [largest - firstRange, largest]
|
|
377
|
-
var rangeEnd = largest;
|
|
378
|
-
var rangeStart = rangeEnd - firstRange;
|
|
379
|
-
flatRanges.push(rangeStart, rangeEnd);
|
|
380
|
-
|
|
381
|
-
// נתחיל לבנות את שאר הטווחים לפי gap+length
|
|
382
|
-
var ranges = ackFrame.ranges || [];
|
|
383
|
-
for (var i = 0; i < ranges.length; i++) {
|
|
384
|
-
var { gap, length } = ranges[i];
|
|
385
|
-
|
|
386
|
-
// מעבר אחורה לפי gap
|
|
387
|
-
rangeEnd = rangeStart - 1 - gap;
|
|
388
|
-
rangeStart = rangeEnd - length;
|
|
389
|
-
|
|
390
|
-
flatRanges.push(rangeStart, rangeEnd);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
return flatRanges;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
export {
|
|
398
|
-
concatUint8Arrays,
|
|
399
|
-
arraybufferEqual,
|
|
400
|
-
readVarInt,
|
|
401
|
-
writeVarInt,
|
|
402
|
-
quic_acked_info_to_ranges,
|
|
403
|
-
build_ack_info_from_ranges
|
|
404
|
-
};
|