ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
h3_frame.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file pc_h3_frame.cpp
6 * @brief HTTP/3 framing - implementation. See pc_h3_frame.h.
7 */
8
10
11#if PC_ENABLE_HTTP3
12
14#include <string.h>
15
16bool pc_h3_frame_parse(const uint8_t *buf, size_t len, H3Frame *out)
17{
18 size_t c1 = 0;
19 size_t c2 = 0;
20 uint64_t type = 0;
21 uint64_t length = 0;
22 if (!pc_quic_varint_decode(buf, len, &type, &c1))
23 {
24 return false;
25 }
26 if (!pc_quic_varint_decode(buf + c1, len - c1, &length, &c2))
27 {
28 return false;
29 }
30 out->type = type;
31 out->length = length;
32 out->header_len = c1 + c2;
33 return true;
34}
35
36size_t pc_h3_frame_write_header(uint8_t *out, size_t cap, uint64_t type, uint64_t length)
37{
38 size_t n = pc_quic_varint_encode(out, cap, type);
39 if (!n)
40 {
41 return 0;
42 }
43 size_t m = pc_quic_varint_encode(out + n, cap - n, length);
44 if (!m)
45 {
46 return 0;
47 }
48 return n + m;
49}
50
51bool pc_h3_frame_type_reserved(uint64_t type)
52{
53 // The HTTP/2 frame types that have no HTTP/3 meaning (RFC 9114 sec 11.2.1).
54 return type == 0x02 || type == 0x06 || type == 0x08 || type == 0x09;
55}
56
57void pc_h3_settings_defaults(H3Settings *s)
58{
59 s->pc_qpack_max_table_capacity = 0;
60 s->max_field_section_size = 0xFFFFFFFFFFFFFFFFULL; // unlimited
61 s->pc_qpack_blocked_streams = 0;
62}
63
64bool pc_h3_parse_settings(const uint8_t *payload, size_t len, H3Settings *s)
65{
66 size_t off = 0;
67 while (off < len)
68 {
69 size_t c1 = 0;
70 size_t c2 = 0;
71 uint64_t id = 0;
72 uint64_t val = 0;
73 if (!pc_quic_varint_decode(payload + off, len - off, &id, &c1))
74 {
75 return false;
76 }
77 off += c1;
78 if (!pc_quic_varint_decode(payload + off, len - off, &val, &c2))
79 {
80 return false;
81 }
82 off += c2;
83 switch (id)
84 {
85 case H3Setting::H3_SETTINGS_QPACK_MAX_TABLE_CAPACITY:
86 s->pc_qpack_max_table_capacity = val;
87 break;
88 case H3Setting::H3_SETTINGS_MAX_FIELD_SECTION_SIZE:
89 s->max_field_section_size = val;
90 break;
91 case H3Setting::H3_SETTINGS_QPACK_BLOCKED_STREAMS:
92 s->pc_qpack_blocked_streams = val;
93 break;
94 case 0x02:
95 case 0x03:
96 case 0x04:
97 case 0x05:
98 return false; // reserved HTTP/2 settings identifiers (RFC 9114 sec 7.2.4.1)
99 default:
100 break; // unknown / greased settings are ignored
101 }
102 }
103 return true;
104}
105
106size_t pc_h3_build_data(uint8_t *out, size_t cap, const uint8_t *data, size_t len)
107{
108 size_t hn = pc_h3_frame_write_header(out, cap, H3FrameType::H3_DATA, len);
109 if (!hn || hn + len > cap)
110 {
111 return 0;
112 }
113 if (len)
114 {
115 memcpy(out + hn, data, len);
116 }
117 return hn + len;
118}
119
120size_t pc_h3_build_headers(uint8_t *out, size_t cap, const uint8_t *block, size_t len)
121{
122 size_t hn = pc_h3_frame_write_header(out, cap, H3FrameType::H3_HEADERS, len);
123 if (!hn || hn + len > cap)
124 {
125 return 0;
126 }
127 if (len)
128 {
129 memcpy(out + hn, block, len);
130 }
131 return hn + len;
132}
133
134size_t pc_h3_build_settings(uint8_t *out, size_t cap, const uint64_t *ids, const uint64_t *vals, size_t n)
135{
136 size_t plen = 0;
137 for (size_t i = 0; i < n; i++)
138 {
139 plen += pc_quic_varint_len(ids[i]) + pc_quic_varint_len(vals[i]);
140 }
141 size_t o = pc_h3_frame_write_header(out, cap, H3FrameType::H3_SETTINGS, plen);
142 if (!o)
143 {
144 return 0;
145 }
146 for (size_t i = 0; i < n; i++)
147 {
148 size_t a = pc_quic_varint_encode(out + o, cap - o, ids[i]);
149 if (!a)
150 {
151 return 0;
152 }
153 o += a;
154 size_t b = pc_quic_varint_encode(out + o, cap - o, vals[i]);
155 if (!b)
156 {
157 return 0;
158 }
159 o += b;
160 }
161 return o;
162}
163
164size_t pc_h3_build_goaway(uint8_t *out, size_t cap, uint64_t stream_id)
165{
166 size_t plen = pc_quic_varint_len(stream_id);
167 size_t o = pc_h3_frame_write_header(out, cap, H3FrameType::H3_GOAWAY, plen);
168 if (!o)
169 {
170 return 0;
171 }
172 size_t a = pc_quic_varint_encode(out + o, cap - o, stream_id);
173 if (!a)
174 {
175 return 0;
176 }
177 return o + a;
178}
179
180#endif // PC_ENABLE_HTTP3