DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
h3_conn.h
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 h3_conn.h
6 * @brief HTTP/3 application engine over QUIC streams (RFC 9114).
7 *
8 * Sits on top of the QUIC transport engine (quic_conn) and speaks HTTP/3: on the handshake
9 * completing it opens the server's unidirectional control stream (sending SETTINGS) and the two
10 * QPACK encoder / decoder streams, reads the client's control stream, and on each client-initiated
11 * bidirectional request stream reassembles the HTTP/3 frames - QPACK-decoding the HEADERS field
12 * section into a request (method / path / authority + a small header set) and collecting the DATA
13 * body - then hands the finished request to the application through a callback. h3_conn_respond()
14 * serializes a response (HEADERS + DATA) back onto the request stream and finishes it.
15 *
16 * QPACK is static-table only (we advertise QPACK_MAX_TABLE_CAPACITY = 0), so no dynamic-table state
17 * is needed and the encoder / decoder streams carry only their stream-type byte. Fixed storage, no
18 * heap; host-testable by feeding it decoded stream bytes through the quic_conn callback seam.
19 *
20 * @author Douglas Quigg (dstroy0)
21 * @date 2026
22 */
23
24#ifndef DETERMINISTICESPASYNCWEBSERVER_H3_CONN_H
25#define DETERMINISTICESPASYNCWEBSERVER_H3_CONN_H
26
27#include "ServerConfig.h"
28
29#if DETWS_ENABLE_HTTP3
30
33#include <stddef.h>
34#include <stdint.h>
35
36#ifndef DETWS_H3_STREAM_BUF
37#define DETWS_H3_STREAM_BUF 2048 ///< per-request-stream reassembly buffer (HEADERS + DATA)
38#endif
39#ifndef DETWS_H3_METHOD_LEN
40#define DETWS_H3_METHOD_LEN 16 ///< captured :method length cap
41#endif
42#ifndef DETWS_H3_PATH_LEN
43#define DETWS_H3_PATH_LEN 256 ///< captured :path length cap
44#endif
45#ifndef DETWS_H3_AUTHORITY_LEN
46#define DETWS_H3_AUTHORITY_LEN 128 ///< captured :authority length cap
47#endif
48
49struct H3Conn;
50
51/**
52 * @brief A completed request delivered to the application.
53 * @param body / body_len the request body (may be empty); valid only during the call.
54 */
55typedef void (*H3RequestFn)(void *app, H3Conn *h3, uint64_t stream_id, const char *method, const char *path,
56 const char *authority, const uint8_t *body, size_t body_len);
57
58/** @brief HTTP/3 stream roles (a mutually-exclusive internal role, not a wire value). */
59enum class H3StreamRole : uint8_t
60{
61 H3_ROLE_FREE = 0,
62 H3_ROLE_REQUEST, ///< client-initiated bidirectional request stream
63 H3_ROLE_CONTROL, ///< client control stream (type 0x00)
64 H3_ROLE_QPACK_ENC, ///< client QPACK encoder stream (type 0x02)
65 H3_ROLE_QPACK_DEC, ///< client QPACK decoder stream (type 0x03)
66 H3_ROLE_OTHER_UNI, ///< an unknown unidirectional stream (drained/ignored)
67};
68
69/** @brief Per-stream HTTP/3 state. */
70struct H3Stream
71{
72 uint64_t id; ///< stream id (UINT64_MAX = free)
73 H3StreamRole role; ///< stream role
74 bool type_read; ///< a unidirectional stream's type varint has been consumed
75 bool responded; ///< a response has been sent on this request stream
76 uint8_t buf[DETWS_H3_STREAM_BUF];
77 size_t buf_len;
78 char method[DETWS_H3_METHOD_LEN];
79 char path[DETWS_H3_PATH_LEN];
80 char authority[DETWS_H3_AUTHORITY_LEN];
81 bool have_headers; ///< a HEADERS frame has been decoded
82 size_t body_off; ///< where the accumulated body begins within buf (after the last HEADERS)
83};
84
85/** @brief One HTTP/3 connection (wraps a QuicConn). */
86struct H3Conn
87{
88 QuicConn *qc;
89 H3RequestFn on_request;
90 void *app;
91 H3Settings peer_settings;
92 bool control_opened; ///< our control + QPACK streams have been opened
93 uint64_t next_uni_id; ///< next server-initiated unidirectional stream id (3, 7, 11, ...)
94 H3Stream streams[DETWS_H3_MAX_STREAMS];
95};
96
97/**
98 * @brief Initialize an HTTP/3 connection over @p qc.
99 *
100 * Registers the QUIC stream / handshake callbacks on @p qc (so @p qc->cb is overwritten with this
101 * engine's hooks; pass the app callback here instead). @p on_request is invoked for each completed
102 * request.
103 */
104void h3_conn_init(H3Conn *h3, QuicConn *qc, H3RequestFn on_request, void *app);
105
106/**
107 * @brief Serialize and send a response on @p stream_id: a HEADERS field section (QPACK) with
108 * :status and optional content-type / content-length, then a DATA frame with @p body, and finish
109 * the stream. @return false on a bad stream or serialization overflow.
110 */
111bool h3_conn_respond(H3Conn *h3, uint64_t stream_id, int status, const char *content_type, const uint8_t *body,
112 size_t body_len);
113
114#endif // DETWS_ENABLE_HTTP3
115#endif // DETERMINISTICESPASYNCWEBSERVER_H3_CONN_H
User-facing configuration for DeterministicESPAsyncWebServer.
#define DETWS_H3_MAX_STREAMS
Maximum concurrent request streams per HTTP/3 connection.
HTTP/3 framing (RFC 9114 sec 7) over QUIC varints.
Stateful QUIC v1 server connection engine (RFC 9000 / RFC 9001).