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.
@@ -0,0 +1,651 @@
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
+
15
+ import {
16
+ concatUint8Arrays,
17
+ writeVarInt,
18
+ readVarInt
19
+ } from './utils.js';
20
+
21
+
22
+ // ============================================================
23
+ // QUIC Datagram → Packet splitting (RFC 9000 §12.2)
24
+ // ============================================================
25
+
26
+ /**
27
+ * Parse a single QUIC packet header (enough to get type + totalLength).
28
+ */
29
+ function parse_quic_packet(array, offset0) {
30
+ if (!(array instanceof Uint8Array)) return null;
31
+ if (offset0 === undefined) offset0 = 0;
32
+ if (offset0 >= array.length) return null;
33
+
34
+ var firstByte = array[offset0];
35
+ var isLong = (firstByte & 0x80) !== 0;
36
+
37
+ if (isLong) {
38
+ if (offset0 + 6 > array.length) return null;
39
+
40
+ var version = (
41
+ (array[offset0 + 1] << 24) |
42
+ (array[offset0 + 2] << 16) |
43
+ (array[offset0 + 3] << 8) |
44
+ array[offset0 + 4]
45
+ ) >>> 0;
46
+
47
+ var dcidLen = array[offset0 + 5];
48
+ var offset = offset0 + 6;
49
+
50
+ if (offset + dcidLen + 1 > array.length) return null;
51
+ var dcid = array.slice(offset, offset + dcidLen);
52
+ offset += dcidLen;
53
+
54
+ var scidLen = array[offset++];
55
+ if (offset + scidLen > array.length) return null;
56
+ var scid = array.slice(offset, offset + scidLen);
57
+ offset += scidLen;
58
+
59
+ // Version Negotiation
60
+ if (version === 0) {
61
+ var supportedVersions = [];
62
+ while (offset + 4 <= array.length) {
63
+ supportedVersions.push(
64
+ (array[offset] << 24) | (array[offset + 1] << 16) |
65
+ (array[offset + 2] << 8) | array[offset + 3]
66
+ );
67
+ offset += 4;
68
+ }
69
+ return {
70
+ form: 'long', type: 'version_negotiation',
71
+ version: version, dcid: dcid, scid: scid,
72
+ supportedVersions: supportedVersions,
73
+ totalLength: offset - offset0
74
+ };
75
+ }
76
+
77
+ var typeBits = (firstByte & 0x30) >> 4;
78
+ var typeMap = ['initial', '0rtt', 'handshake', 'retry'];
79
+ var packetType = typeMap[typeBits] || 'unknown';
80
+
81
+ if (packetType === 'retry') {
82
+ return {
83
+ form: 'long', type: 'retry',
84
+ version: version, dcid: dcid, scid: scid,
85
+ totalLength: array.length - offset0
86
+ };
87
+ }
88
+
89
+ // Initial: read token
90
+ var token = null;
91
+ if (packetType === 'initial') {
92
+ try {
93
+ var tokenLen = readVarInt(array, offset);
94
+ offset += tokenLen.byteLength;
95
+ if (offset + tokenLen.value > array.length) return null;
96
+ token = array.slice(offset, offset + tokenLen.value);
97
+ offset += tokenLen.value;
98
+ } catch (e) { return null; }
99
+ }
100
+
101
+ // Length field
102
+ try {
103
+ var lengthInfo = readVarInt(array, offset);
104
+ offset += lengthInfo.byteLength;
105
+ var totalLength = offset - offset0 + lengthInfo.value;
106
+ if (offset0 + totalLength > array.length) return null;
107
+
108
+ return {
109
+ form: 'long', type: packetType,
110
+ version: version, dcid: dcid, scid: scid, token: token,
111
+ totalLength: totalLength
112
+ };
113
+ } catch (e) { return null; }
114
+
115
+ } else {
116
+ // Short Header — Fixed Bit (0x40) MUST be 1 (RFC 9000 §17.3)
117
+ if ((firstByte & 0x40) === 0) return null; // padding or invalid
118
+ return {
119
+ form: 'short', type: '1rtt',
120
+ totalLength: array.length - offset0
121
+ };
122
+ }
123
+ }
124
+
125
+
126
+ /**
127
+ * Split a UDP datagram into QUIC packets.
128
+ */
129
+ function parse_quic_datagram(array) {
130
+ var packets = [];
131
+ var offset = 0;
132
+
133
+ while (offset < array.length) {
134
+ var pkt = parse_quic_packet(array, offset);
135
+ if (!pkt || !pkt.totalLength) break;
136
+
137
+ var start = offset;
138
+ var end = offset + pkt.totalLength;
139
+
140
+ pkt.raw = (start === 0 && end === array.length)
141
+ ? array
142
+ : array.slice(start, end);
143
+
144
+ if (packets.length > 0) {
145
+ console.log('[quic] coalesced pkt #' + packets.length + ' type=' + pkt.type + ' offset=' + start + ' len=' + pkt.totalLength + ' firstByte=0x' + array[start].toString(16).padStart(2,'0'));
146
+ }
147
+
148
+ packets.push(pkt);
149
+ offset = end;
150
+ }
151
+
152
+ return packets;
153
+ }
154
+
155
+
156
+ // ============================================================
157
+ // QUIC Frame encoding (RFC 9000 §12.4)
158
+ // ============================================================
159
+
160
+ function encode_quic_frames(frames) {
161
+ var parts = [];
162
+
163
+ for (var i = 0; i < frames.length; i++) {
164
+ var frame = frames[i];
165
+
166
+ if (frame.type === 'padding') {
167
+ parts.push(new Uint8Array(frame.length));
168
+
169
+ } else if (frame.type === 'ping') {
170
+ parts.push(new Uint8Array([0x01]));
171
+
172
+ } else if (frame.type === 'ack') {
173
+ var hasECN = frame.ecn !== null && frame.ecn !== undefined;
174
+ var typeByte = hasECN ? 0x03 : 0x02;
175
+ var temp = [
176
+ new Uint8Array([typeByte]),
177
+ writeVarInt(frame.largest),
178
+ writeVarInt(frame.delay),
179
+ writeVarInt(frame.ranges.length),
180
+ writeVarInt(frame.firstRange != null ? frame.firstRange : 0)
181
+ ];
182
+ for (var j = 0; j < frame.ranges.length; j++) {
183
+ temp.push(writeVarInt(frame.ranges[j].gap));
184
+ temp.push(writeVarInt(frame.ranges[j].length));
185
+ }
186
+ if (hasECN) {
187
+ temp.push(writeVarInt(frame.ecn.ect0));
188
+ temp.push(writeVarInt(frame.ecn.ect1));
189
+ temp.push(writeVarInt(frame.ecn.ce));
190
+ }
191
+ parts.push(concatUint8Arrays(temp));
192
+
193
+ } else if (frame.type === 'crypto') {
194
+ parts.push(concatUint8Arrays([
195
+ new Uint8Array([0x06]),
196
+ writeVarInt(frame.offset),
197
+ writeVarInt(frame.data.length),
198
+ frame.data
199
+ ]));
200
+
201
+ } else if (frame.type === 'stream') {
202
+ var typeByte = 0x08;
203
+ var hasOffset = (frame.offset != null && frame.offset > 0);
204
+ var hasLen = (frame.data && frame.data.length > 0);
205
+ var hasFin = !!frame.fin;
206
+
207
+ if (hasOffset) typeByte |= 0x04;
208
+ if (hasLen) typeByte |= 0x02;
209
+ if (hasFin) typeByte |= 0x01;
210
+
211
+ parts.push(concatUint8Arrays([
212
+ new Uint8Array([typeByte]),
213
+ writeVarInt(frame.id),
214
+ hasOffset ? writeVarInt(frame.offset) : new Uint8Array(0),
215
+ hasLen ? writeVarInt(frame.data.length) : new Uint8Array(0),
216
+ frame.data || new Uint8Array(0)
217
+ ]));
218
+
219
+ } else if (frame.type === 'new_token') {
220
+ parts.push(concatUint8Arrays([
221
+ new Uint8Array([0x07]),
222
+ writeVarInt(frame.token.length),
223
+ frame.token
224
+ ]));
225
+
226
+ } else if (frame.type === 'max_data') {
227
+ parts.push(concatUint8Arrays([
228
+ new Uint8Array([0x10]),
229
+ writeVarInt(frame.max)
230
+ ]));
231
+
232
+ } else if (frame.type === 'max_stream_data') {
233
+ parts.push(concatUint8Arrays([
234
+ new Uint8Array([0x11]),
235
+ writeVarInt(frame.id),
236
+ writeVarInt(frame.max)
237
+ ]));
238
+
239
+ } else if (frame.type === 'max_streams_bidi') {
240
+ parts.push(concatUint8Arrays([
241
+ new Uint8Array([0x12]),
242
+ writeVarInt(frame.max)
243
+ ]));
244
+
245
+ } else if (frame.type === 'max_streams_uni') {
246
+ parts.push(concatUint8Arrays([
247
+ new Uint8Array([0x13]),
248
+ writeVarInt(frame.max)
249
+ ]));
250
+
251
+ } else if (frame.type === 'connection_close') {
252
+ var code = frame.application ? 0x1d : 0x1c;
253
+ var errorCode = writeVarInt(frame.error || 0);
254
+ var frameType = frame.application ? new Uint8Array(0) : writeVarInt(frame.frameType || 0);
255
+ var reason = new TextEncoder().encode(frame.reason || '');
256
+ parts.push(concatUint8Arrays([
257
+ new Uint8Array([code]),
258
+ errorCode,
259
+ frameType,
260
+ writeVarInt(reason.length),
261
+ reason
262
+ ]));
263
+
264
+ } else if (frame.type === 'handshake_done') {
265
+ parts.push(new Uint8Array([0x1e]));
266
+
267
+ } else if (frame.type === 'new_connection_id') {
268
+ parts.push(concatUint8Arrays([
269
+ new Uint8Array([0x18]),
270
+ writeVarInt(frame.seq),
271
+ writeVarInt(frame.retire),
272
+ new Uint8Array([frame.connId.length]),
273
+ frame.connId,
274
+ frame.token
275
+ ]));
276
+
277
+ } else if (frame.type === 'retire_connection_id') {
278
+ parts.push(concatUint8Arrays([
279
+ new Uint8Array([0x19]),
280
+ writeVarInt(frame.seq)
281
+ ]));
282
+
283
+ } else if (frame.type === 'path_challenge' || frame.type === 'path_response') {
284
+ parts.push(concatUint8Arrays([
285
+ new Uint8Array([frame.type === 'path_challenge' ? 0x1a : 0x1b]),
286
+ frame.data
287
+ ]));
288
+
289
+ } else if (frame.type === 'reset_stream') {
290
+ parts.push(concatUint8Arrays([
291
+ new Uint8Array([0x04]),
292
+ writeVarInt(frame.id),
293
+ writeVarInt(frame.error),
294
+ writeVarInt(frame.finalSize)
295
+ ]));
296
+
297
+ } else if (frame.type === 'stop_sending') {
298
+ parts.push(concatUint8Arrays([
299
+ new Uint8Array([0x05]),
300
+ writeVarInt(frame.id),
301
+ writeVarInt(frame.error)
302
+ ]));
303
+
304
+ } else if (frame.type === 'data_blocked') {
305
+ parts.push(concatUint8Arrays([
306
+ new Uint8Array([0x14]),
307
+ writeVarInt(frame.limit)
308
+ ]));
309
+
310
+ } else if (frame.type === 'stream_data_blocked') {
311
+ parts.push(concatUint8Arrays([
312
+ new Uint8Array([0x15]),
313
+ writeVarInt(frame.id),
314
+ writeVarInt(frame.limit)
315
+ ]));
316
+
317
+ } else if (frame.type === 'datagram') {
318
+ if (frame.contextId != null) {
319
+ parts.push(concatUint8Arrays([
320
+ new Uint8Array([0x31]),
321
+ writeVarInt(frame.contextId),
322
+ frame.data
323
+ ]));
324
+ } else {
325
+ parts.push(concatUint8Arrays([
326
+ new Uint8Array([0x30]),
327
+ frame.data
328
+ ]));
329
+ }
330
+ }
331
+ }
332
+
333
+ return parts.length === 1 ? parts[0] : concatUint8Arrays(parts);
334
+ }
335
+
336
+
337
+ // ============================================================
338
+ // QUIC Frame parsing (RFC 9000 §12.4)
339
+ // ============================================================
340
+
341
+ function parse_quic_frames(buf) {
342
+ var offset = 0;
343
+ var frames = [];
344
+
345
+ function safeReadVarInt() {
346
+ if (offset >= buf.length) return null;
347
+ var res = readVarInt(buf, offset);
348
+ if (!res) return null;
349
+ offset += res.byteLength;
350
+ return res;
351
+ }
352
+
353
+ while (offset < buf.length) {
354
+ var type = buf[offset++];
355
+
356
+ // Multi-byte frame type
357
+ if (type >= 0x80) {
358
+ offset--;
359
+ var t = safeReadVarInt();
360
+ if (!t) break;
361
+ type = t.value;
362
+ }
363
+
364
+ if (type === 0x00) {
365
+ // PADDING — skip
366
+ } else if (type === 0x01) {
367
+ frames.push({ type: 'ping' });
368
+
369
+ } else if ((type & 0xfe) === 0x02) {
370
+ var hasECN = (type & 0x01) === 1;
371
+ var largest = safeReadVarInt(); if (!largest) break;
372
+ var delay = safeReadVarInt(); if (!delay) break;
373
+ var rangeCount = safeReadVarInt(); if (!rangeCount) break;
374
+ var firstRange = safeReadVarInt(); if (!firstRange) break;
375
+
376
+ var ranges = [];
377
+ for (var i = 0; i < rangeCount.value; i++) {
378
+ var gap = safeReadVarInt(); if (!gap) break;
379
+ var len = safeReadVarInt(); if (!len) break;
380
+ ranges.push({ gap: gap.value, length: len.value });
381
+ }
382
+
383
+ var ecn = null;
384
+ if (hasECN) {
385
+ var ect0 = safeReadVarInt(); if (!ect0) break;
386
+ var ect1 = safeReadVarInt(); if (!ect1) break;
387
+ var ce = safeReadVarInt(); if (!ce) break;
388
+ ecn = { ect0: ect0.value, ect1: ect1.value, ce: ce.value };
389
+ }
390
+
391
+ frames.push({
392
+ type: 'ack', largest: largest.value, delay: delay.value,
393
+ firstRange: firstRange.value, ranges: ranges, ecn: ecn
394
+ });
395
+
396
+ } else if (type === 0x04) {
397
+ var id = safeReadVarInt(); if (!id) break;
398
+ var error = safeReadVarInt(); if (!error) break;
399
+ var finalSize = safeReadVarInt(); if (!finalSize) break;
400
+ frames.push({ type: 'reset_stream', id: id.value, error: error.value, finalSize: finalSize.value });
401
+
402
+ } else if (type === 0x05) {
403
+ var id = safeReadVarInt(); if (!id) break;
404
+ var error = safeReadVarInt(); if (!error) break;
405
+ frames.push({ type: 'stop_sending', id: id.value, error: error.value });
406
+
407
+ } else if (type === 0x06) {
408
+ var off = safeReadVarInt(); if (!off) break;
409
+ var len = safeReadVarInt(); if (!len) break;
410
+ if (offset + len.value > buf.length) break;
411
+ var data = buf.slice(offset, offset + len.value); offset += len.value;
412
+ frames.push({ type: 'crypto', offset: off.value, data: data });
413
+
414
+ } else if (type === 0x07) {
415
+ var len = safeReadVarInt(); if (!len) break;
416
+ if (offset + len.value > buf.length) break;
417
+ var token = buf.slice(offset, offset + len.value); offset += len.value;
418
+ frames.push({ type: 'new_token', token: token });
419
+
420
+ } else if (type >= 0x08 && type <= 0x0f) {
421
+ var fin = !!(type & 0x01);
422
+ var lenb = !!(type & 0x02);
423
+ var offb = !!(type & 0x04);
424
+
425
+ var stream_id = safeReadVarInt(); if (!stream_id) break;
426
+ var offset_val = offb ? safeReadVarInt() : { value: 0 }; if (!offset_val) break;
427
+ var length_val = lenb ? safeReadVarInt() : { value: buf.length - offset }; if (!length_val) break;
428
+ if (offset + length_val.value > buf.length) break;
429
+
430
+ var data = buf.slice(offset, offset + length_val.value); offset += length_val.value;
431
+ frames.push({
432
+ type: 'stream', id: stream_id.value,
433
+ offset: offset_val.value, fin: fin, data: data
434
+ });
435
+
436
+ } else if (type === 0x10) {
437
+ var max = safeReadVarInt(); if (!max) break;
438
+ frames.push({ type: 'max_data', max: max.value });
439
+
440
+ } else if (type === 0x11) {
441
+ var id = safeReadVarInt(); if (!id) break;
442
+ var max = safeReadVarInt(); if (!max) break;
443
+ frames.push({ type: 'max_stream_data', id: id.value, max: max.value });
444
+
445
+ } else if (type === 0x12 || type === 0x13) {
446
+ var max = safeReadVarInt(); if (!max) break;
447
+ frames.push({ type: type === 0x12 ? 'max_streams_bidi' : 'max_streams_uni', max: max.value });
448
+
449
+ } else if (type === 0x14) {
450
+ var limit = safeReadVarInt(); if (!limit) break;
451
+ frames.push({ type: 'data_blocked', limit: limit.value });
452
+
453
+ } else if (type === 0x15) {
454
+ var id = safeReadVarInt(); if (!id) break;
455
+ var limit = safeReadVarInt(); if (!limit) break;
456
+ frames.push({ type: 'stream_data_blocked', id: id.value, limit: limit.value });
457
+
458
+ } else if (type === 0x16 || type === 0x17) {
459
+ var limit = safeReadVarInt(); if (!limit) break;
460
+ frames.push({ type: type === 0x16 ? 'streams_blocked_bidi' : 'streams_blocked_uni', limit: limit.value });
461
+
462
+ } else if (type === 0x18) {
463
+ var seq = safeReadVarInt(); if (!seq) break;
464
+ var retire = safeReadVarInt(); if (!retire) break;
465
+ if (offset >= buf.length) break;
466
+ var cidLen = buf[offset++];
467
+ if (offset + cidLen + 16 > buf.length) break;
468
+ var connId = buf.slice(offset, offset + cidLen); offset += cidLen;
469
+ var token = buf.slice(offset, offset + 16); offset += 16;
470
+ frames.push({ type: 'new_connection_id', seq: seq.value, retire: retire.value, connId: connId, token: token });
471
+
472
+ } else if (type === 0x19) {
473
+ var seq = safeReadVarInt(); if (!seq) break;
474
+ frames.push({ type: 'retire_connection_id', seq: seq.value });
475
+
476
+ } else if (type === 0x1a || type === 0x1b) {
477
+ if (offset + 8 > buf.length) break;
478
+ var data = buf.slice(offset, offset + 8); offset += 8;
479
+ frames.push({ type: type === 0x1a ? 'path_challenge' : 'path_response', data: data });
480
+
481
+ } else if (type === 0x1c || type === 0x1d) {
482
+ var error = safeReadVarInt(); if (!error) break;
483
+ var frameType = null;
484
+ if (type === 0x1c) {
485
+ var ft = safeReadVarInt(); if (!ft) break;
486
+ frameType = ft.value;
487
+ }
488
+ var reasonLen = safeReadVarInt(); if (!reasonLen) break;
489
+ if (offset + reasonLen.value > buf.length) break;
490
+ var reason = new TextDecoder().decode(buf.slice(offset, offset + reasonLen.value));
491
+ offset += reasonLen.value;
492
+ frames.push({
493
+ type: 'connection_close', application: type === 0x1d,
494
+ error: error.value, frameType: frameType, reason: reason
495
+ });
496
+
497
+ } else if (type === 0x1e) {
498
+ frames.push({ type: 'handshake_done' });
499
+
500
+ } else if (type === 0x30 || type === 0x31) {
501
+ var contextId = null;
502
+ if (type === 0x31) {
503
+ var cid = safeReadVarInt(); if (!cid) break;
504
+ contextId = cid.value;
505
+ }
506
+ var data = buf.slice(offset); offset = buf.length;
507
+ frames.push({ type: 'datagram', contextId: contextId, data: data });
508
+
509
+ } else {
510
+ // Unknown frame — stop
511
+ frames.push({ type: 'unknown', frameType: type });
512
+ break;
513
+ }
514
+ }
515
+
516
+ return frames;
517
+ }
518
+
519
+
520
+ // ============================================================
521
+ // Transport Parameters (RFC 9000 §18)
522
+ // ============================================================
523
+
524
+ function build_transport_params(params) {
525
+ var out = [];
526
+
527
+ function addParam(id, value) {
528
+ var idBytes = writeVarInt(id);
529
+ var valueBytes;
530
+
531
+ if (typeof value === 'number') {
532
+ valueBytes = writeVarInt(value);
533
+ } else if (value instanceof Uint8Array) {
534
+ valueBytes = Array.from(value);
535
+ } else if (value === true) {
536
+ valueBytes = [];
537
+ } else {
538
+ throw new Error('Unsupported param value type for id ' + id);
539
+ }
540
+
541
+ var lengthBytes = writeVarInt(valueBytes.length);
542
+ out.push.apply(out, Array.from(idBytes));
543
+ out.push.apply(out, Array.from(lengthBytes));
544
+ out.push.apply(out, valueBytes);
545
+ }
546
+
547
+ if (params.original_destination_connection_id)
548
+ addParam(0x00, params.original_destination_connection_id);
549
+ if (params.max_idle_timeout)
550
+ addParam(0x01, params.max_idle_timeout);
551
+ if (params.stateless_reset_token)
552
+ addParam(0x02, params.stateless_reset_token);
553
+ if (params.max_udp_payload_size)
554
+ addParam(0x03, params.max_udp_payload_size);
555
+ if (params.initial_max_data)
556
+ addParam(0x04, params.initial_max_data);
557
+ if (params.initial_max_stream_data_bidi_local)
558
+ addParam(0x05, params.initial_max_stream_data_bidi_local);
559
+ if (params.initial_max_stream_data_bidi_remote)
560
+ addParam(0x06, params.initial_max_stream_data_bidi_remote);
561
+ if (params.initial_max_stream_data_uni)
562
+ addParam(0x07, params.initial_max_stream_data_uni);
563
+ if (params.initial_max_streams_bidi)
564
+ addParam(0x08, params.initial_max_streams_bidi);
565
+ if (params.initial_max_streams_uni)
566
+ addParam(0x09, params.initial_max_streams_uni);
567
+ if (params.ack_delay_exponent !== undefined)
568
+ addParam(0x0a, params.ack_delay_exponent);
569
+ if (params.max_ack_delay !== undefined)
570
+ addParam(0x0b, params.max_ack_delay);
571
+ if (params.disable_active_migration)
572
+ addParam(0x0c, true);
573
+ if (params.active_connection_id_limit)
574
+ addParam(0x0e, params.active_connection_id_limit);
575
+ if (params.initial_source_connection_id)
576
+ addParam(0x0f, params.initial_source_connection_id);
577
+ if (params.retry_source_connection_id)
578
+ addParam(0x10, params.retry_source_connection_id);
579
+ if (params.max_datagram_frame_size)
580
+ addParam(0x20, params.max_datagram_frame_size);
581
+
582
+ return new Uint8Array(out);
583
+ }
584
+
585
+
586
+ function parse_transport_params(buf, start) {
587
+ if (!(buf instanceof Uint8Array)) throw new Error('Expect Uint8Array');
588
+ var offset = start || 0;
589
+ var end = buf.length;
590
+ var out = {};
591
+
592
+ while (offset < end) {
593
+ var idVar = readVarInt(buf, offset);
594
+ if (!idVar) break;
595
+ offset += idVar.byteLength;
596
+
597
+ var lenVar = readVarInt(buf, offset);
598
+ if (!lenVar) break;
599
+ offset += lenVar.byteLength;
600
+
601
+ if (offset + lenVar.value > end) break;
602
+ var valueBytes = buf.slice(offset, offset + lenVar.value);
603
+ offset += lenVar.value;
604
+
605
+ var id = idVar.value;
606
+
607
+ switch (id) {
608
+ case 0x00: out.original_destination_connection_id = valueBytes; break;
609
+ case 0x01: out.max_idle_timeout = readVarInt(valueBytes, 0).value; break;
610
+ case 0x02: out.stateless_reset_token = valueBytes; break;
611
+ case 0x03: out.max_udp_payload_size = readVarInt(valueBytes, 0).value; break;
612
+ case 0x04: out.initial_max_data = readVarInt(valueBytes, 0).value; break;
613
+ case 0x05: out.initial_max_stream_data_bidi_local = readVarInt(valueBytes, 0).value; break;
614
+ case 0x06: out.initial_max_stream_data_bidi_remote = readVarInt(valueBytes, 0).value; break;
615
+ case 0x07: out.initial_max_stream_data_uni = readVarInt(valueBytes, 0).value; break;
616
+ case 0x08: out.initial_max_streams_bidi = readVarInt(valueBytes, 0).value; break;
617
+ case 0x09: out.initial_max_streams_uni = readVarInt(valueBytes, 0).value; break;
618
+ case 0x0a: out.ack_delay_exponent = readVarInt(valueBytes, 0).value; break;
619
+ case 0x0b: out.max_ack_delay = readVarInt(valueBytes, 0).value; break;
620
+ case 0x0c: out.disable_active_migration = true; break;
621
+ case 0x0e: out.active_connection_id_limit = readVarInt(valueBytes, 0).value; break;
622
+ case 0x0f: out.initial_source_connection_id = valueBytes; break;
623
+ case 0x10: out.retry_source_connection_id = valueBytes; break;
624
+ case 0x20: out.max_datagram_frame_size = readVarInt(valueBytes, 0).value; break;
625
+ default:
626
+ if (!out.unknown) out.unknown = [];
627
+ out.unknown.push({ id: id, bytes: valueBytes });
628
+ }
629
+ }
630
+
631
+ return out;
632
+ }
633
+
634
+
635
+ // ============================================================
636
+ // Exports
637
+ // ============================================================
638
+
639
+ export {
640
+ // Datagram/packet parsing
641
+ parse_quic_datagram,
642
+ parse_quic_packet,
643
+
644
+ // Frame encode/decode
645
+ encode_quic_frames,
646
+ parse_quic_frames,
647
+
648
+ // Transport parameters
649
+ build_transport_params,
650
+ parse_transport_params
651
+ };