ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
h3_frame.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4#ifndef PROTOCORE_H3_FRAME_H
5#define PROTOCORE_H3_FRAME_H
6
7#include "protocore_config.h" // the entry point: protocore_types.h for the widths
8
10
11/**
12 * @file h3_frame.h
13 * @brief HTTP/3 framing (RFC 9114 sec 7) over QUIC varints.
14 *
15 * An HTTP/3 frame is `Type (varint) | Length (varint) | Frame Payload`. This module parses that
16 * header and builds the frames a server uses (DATA, HEADERS carrying a QPACK field section,
17 * SETTINGS, GOAWAY), reads a SETTINGS payload, and flags the reserved HTTP/2 frame types that
18 * must be treated as a connection error. Pure and host-tested.
19 *
20 * @c work is bytes the CALLER holds. This module reads none of them: it carries nothing
21 * between calls, so there is no state to keep and nothing to wipe. The parameter is there so
22 * a caller drives every namespace the same way.
23 *
24 * @author Douglas Quigg (dstroy0)
25 * @date 2026
26 */
27
28// PROTOCORE_H3_FRAME_BORROW - the bytes this module runs out of - is stated in protocore_config.h, which sums
29// it into its arena. Its size and its offset are each a static_assert, so a feature
30// combination that does not fit fails to compile rather than overrunning at run time.
31
32/** @brief HTTP/3 frame types (RFC 9114 sec 7.2 / 11.2.1). */
33#define H3_DATA 0x00
34#define H3_HEADERS 0x01
35#define H3_CANCEL_PUSH 0x03
36#define H3_SETTINGS 0x04
37#define H3_PUSH_PROMISE 0x05
38#define H3_GOAWAY 0x07
39#define H3_MAX_PUSH_ID 0x0d
40
41/**
42 * @brief HTTP/3 error codes (RFC 9114 sec 8.1).
43 *
44 * These travel in a CONNECTION_CLOSE of type 0x1d, whose error code comes from the application
45 * protocol's space. Sent in the transport variant (0x1c) they would be read against RFC 9000
46 * sec 20.1 instead, where 0x0100-0x01ff is CRYPTO_ERROR plus a TLS alert.
47 */
48#define H3_NO_ERROR 0x0100
49#define H3_GENERAL_PROTOCOL_ERROR 0x0101
50#define H3_INTERNAL_ERROR 0x0102
51#define H3_STREAM_CREATION_ERROR 0x0103
52#define H3_CLOSED_CRITICAL_STREAM 0x0104
53#define H3_FRAME_UNEXPECTED 0x0105
54#define H3_FRAME_ERROR 0x0106
55#define H3_EXCESSIVE_LOAD 0x0107
56#define H3_ID_ERROR 0x0108
57#define H3_SETTINGS_ERROR 0x0109
58#define H3_MISSING_SETTINGS 0x010a
59#define H3_REQUEST_REJECTED 0x010b
60#define H3_REQUEST_CANCELLED 0x010c
61#define H3_REQUEST_INCOMPLETE 0x010d
62#define H3_MESSAGE_ERROR 0x010e
63#define H3_CONNECT_ERROR 0x010f
64#define H3_VERSION_FALLBACK 0x0110
65
66/** @brief SETTINGS parameter identifiers (RFC 9114 sec 7.2.4.1 + RFC 9204). */
67#define H3_SETTINGS_QPACK_MAX_TABLE_CAPACITY 0x01
68#define H3_SETTINGS_MAX_FIELD_SECTION_SIZE 0x06
69#define H3_SETTINGS_QPACK_BLOCKED_STREAMS 0x07
70
71/** @brief A parsed frame header (payload begins at buf + header_len). */
72typedef struct
73{
74 uint64_t type; ///< frame type
75 uint64_t length; ///< payload length
76 size_t header_len; ///< bytes of the type + length varints
78
79/** @brief The settings we track, with defaults after ::H3FrameNs::settings_defaults. */
80typedef struct
81{
82 uint64_t qpack_max_table_capacity; ///< default 0
83 uint64_t max_field_section_size; ///< default "unlimited"
84 uint64_t qpack_blocked_streams; ///< default 0
86
87/** @brief Dispatch table. Addressed by offset, so the layout is asserted below. */
88typedef struct
89{
90 proto_bool (*parse_header)(uint8_t *, const uint8_t *, size_t, H3FrameHeader *);
91 size_t (*write_header)(uint8_t *, uint8_t *, size_t, uint64_t, uint64_t);
92 proto_bool (*type_reserved)(uint8_t *, uint64_t);
93 void (*settings_defaults)(uint8_t *, H3Settings *);
94 proto_bool (*parse_settings)(uint8_t *, const uint8_t *, size_t, H3Settings *);
95 size_t (*build_data)(uint8_t *, uint8_t *, size_t, const uint8_t *, size_t);
96 size_t (*build_headers)(uint8_t *, uint8_t *, size_t, const uint8_t *, size_t);
97 size_t (*build_settings)(uint8_t *, uint8_t *, size_t, const uint64_t *, const uint64_t *, size_t);
98 size_t (*build_goaway)(uint8_t *, uint8_t *, size_t, uint64_t);
99} H3FrameNs;
100PROTOCORE_NS_LAYOUT(H3FrameNs, parse_header, write_header, type_reserved, settings_defaults, parse_settings, build_data,
101 build_headers, build_settings, build_goaway);
102
103/**
104 * @brief Parse a frame header (type + length varints) at buf. false if .
105 * @param work PROTOCORE_H3_FRAME_BORROW bytes the caller took. Not held past the call.
106 * @param buf Buf
107 * @param len Len
108 * @param out Out
109 * @return PROTO_TRUE on success.
110 */
111proto_bool protocore_h3_frame_parse_header(uint8_t *work, const uint8_t *buf, size_t len, H3FrameHeader *out);
112/**
113 * @brief Write a frame header (type + length varints). bytes written, or 0 .
114 * @param work PROTOCORE_H3_FRAME_BORROW bytes the caller took. Not held past the call.
115 * @param out Out
116 * @param cap Cap
117 * @param type Type
118 * @param length Length
119 * @return The size_t.
120 */
121size_t protocore_h3_frame_write_header(uint8_t *work, uint8_t *out, size_t cap, uint64_t type, uint64_t length);
122/**
123 * @brief True if type is a reserved HTTP/2 frame type (0x02/0x06/0x08/0x09) .
124 * @param work PROTOCORE_H3_FRAME_BORROW bytes the caller took. Not held past the call.
125 * @param type Type
126 * @return PROTO_TRUE on success.
127 */
128proto_bool protocore_h3_frame_type_reserved(uint8_t *work, uint64_t type);
129/**
130 * @brief Fill s with the RFC default settings.
131 * @param work PROTOCORE_H3_FRAME_BORROW bytes the caller took. Not held past the call.
132 * @param s S
133 */
135/**
136 * @brief Apply a SETTINGS payload (id, value varint pairs) to s. false if .
137 * @param work PROTOCORE_H3_FRAME_BORROW bytes the caller took. Not held past the call.
138 * @param payload Payload
139 * @param len Len
140 * @param s S
141 * @return PROTO_TRUE on success.
142 */
143proto_bool protocore_h3_frame_parse_settings(uint8_t *work, const uint8_t *payload, size_t len, H3Settings *s);
144/**
145 * @brief DATA frame wrapping data.
146 * @param work PROTOCORE_H3_FRAME_BORROW bytes the caller took. Not held past the call.
147 * @param out Out
148 * @param cap Cap
149 * @param data Data
150 * @param len Len
151 * @return The size_t.
152 */
153size_t protocore_h3_frame_build_data(uint8_t *work, uint8_t *out, size_t cap, const uint8_t *data, size_t len);
154/**
155 * @brief HEADERS frame wrapping a QPACK-encoded field section block.
156 * @param work PROTOCORE_H3_FRAME_BORROW bytes the caller took. Not held past the call.
157 * @param out Out
158 * @param cap Cap
159 * @param block Block
160 * @param len Len
161 * @return The size_t.
162 */
163size_t protocore_h3_frame_build_headers(uint8_t *work, uint8_t *out, size_t cap, const uint8_t *block, size_t len);
164/**
165 * @brief SETTINGS frame from n (id, value) pairs.
166 * @param work PROTOCORE_H3_FRAME_BORROW bytes the caller took. Not held past the call.
167 * @param out Out
168 * @param cap Cap
169 * @param ids Ids
170 * @param vals Vals
171 * @param n N
172 * @return The size_t.
173 */
174size_t protocore_h3_frame_build_settings(uint8_t *work, uint8_t *out, size_t cap, const uint64_t *ids,
175 const uint64_t *vals, size_t n);
176/**
177 * @brief GOAWAY frame carrying stream_id (RFC 9114 sec 7.2.6).
178 * @param work PROTOCORE_H3_FRAME_BORROW bytes the caller took. Not held past the call.
179 * @param out Out
180 * @param cap Cap
181 * @param stream_id Stream id
182 * @return The size_t.
183 */
184size_t protocore_h3_frame_build_goaway(uint8_t *work, uint8_t *out, size_t cap, uint64_t stream_id);
185
186/** @brief Module namespace. */
196
198
199#endif // PROTOCORE_H3_FRAME_H
size_t protocore_h3_frame_write_header(uint8_t *work, uint8_t *out, size_t cap, uint64_t type, uint64_t length)
Write a frame header (type + length varints). bytes written, or 0 .
size_t protocore_h3_frame_build_data(uint8_t *work, uint8_t *out, size_t cap, const uint8_t *data, size_t len)
DATA frame wrapping data.
PROTOCORE_NS H3FrameNs H3Frame PROTOCORE_UNUSED
Module namespace.
Definition h3_frame.h:187
proto_bool protocore_h3_frame_type_reserved(uint8_t *work, uint64_t type)
True if type is a reserved HTTP/2 frame type (0x02/0x06/0x08/0x09) .
size_t protocore_h3_frame_build_goaway(uint8_t *work, uint8_t *out, size_t cap, uint64_t stream_id)
GOAWAY frame carrying stream_id (RFC 9114 sec 7.2.6).
void protocore_h3_frame_settings_defaults(uint8_t *work, H3Settings *s)
Fill s with the RFC default settings.
proto_bool protocore_h3_frame_parse_header(uint8_t *work, const uint8_t *buf, size_t len, H3FrameHeader *out)
Parse a frame header (type + length varints) at buf. false if .
proto_bool protocore_h3_frame_parse_settings(uint8_t *work, const uint8_t *payload, size_t len, H3Settings *s)
Apply a SETTINGS payload (id, value varint pairs) to s. false if .
size_t protocore_h3_frame_build_settings(uint8_t *work, uint8_t *out, size_t cap, const uint64_t *ids, const uint64_t *vals, size_t n)
SETTINGS frame from n (id, value) pairs.
size_t protocore_h3_frame_build_headers(uint8_t *work, uint8_t *out, size_t cap, const uint8_t *block, size_t len)
HEADERS frame wrapping a QPACK-encoded field section block.
#define PROTOCORE_NS_LAYOUT(T,...)
Pin every dispatch slot of a table that is nothing but function pointers.
#define PROTOCORE_NS
Storage for a dispatch table. The const is load bearing.
A parsed frame header (payload begins at buf + header_len).
Definition h3_frame.h:73
size_t header_len
bytes of the type + length varints
Definition h3_frame.h:76
uint64_t type
frame type
Definition h3_frame.h:74
uint64_t length
payload length
Definition h3_frame.h:75
Dispatch table. Addressed by offset, so the layout is asserted below.
Definition h3_frame.h:89
proto_bool(* parse_header)(uint8_t *, const uint8_t *, size_t, H3FrameHeader *)
Definition h3_frame.h:90
The settings we track, with defaults after H3FrameNs::settings_defaults.
Definition h3_frame.h:81
uint64_t max_field_section_size
default "unlimited"
Definition h3_frame.h:83
uint64_t qpack_blocked_streams
default 0
Definition h3_frame.h:84
uint64_t qpack_max_table_capacity
default 0
Definition h3_frame.h:82
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97