1// Copyright (C) 2025, Cloudflare, Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright notice,
9// this list of conditions and the following disclaimer.
10//
11// * Redistributions in binary form must reproduce the above copyright
12// notice, this list of conditions and the following disclaimer in the
13// documentation and/or other materials provided with the distribution.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2627use std::sync::Arc;
2829use tokio::sync::mpsc;
3031use super::datagram;
32use super::DriverHooks;
33use super::H3Command;
34use super::H3ConnectionError;
35use super::H3ConnectionResult;
36use super::H3Controller;
37use super::H3Driver;
38use super::H3Event;
39use super::InboundHeaders;
40use super::IncomingH3Headers;
41use super::StreamCtx;
42use super::STREAM_CAPACITY;
43use crate::http3::settings::Http3Settings;
44use crate::http3::settings::Http3SettingsEnforcer;
45use crate::http3::settings::Http3TimeoutType;
46use crate::http3::settings::TimeoutKey;
47use crate::quic::HandshakeInfo;
48use crate::quic::QuicCommand;
49use crate::quic::QuicheConnection;
5051/// An [H3Driver] for a server-side HTTP/3 connection. See [H3Driver] for
52/// details. Emits [`ServerH3Event`]s and expects [`ServerH3Command`]s for
53/// control.
54pub type ServerH3Driver = H3Driver<ServerHooks>;
55/// The [H3Controller] type paired with [ServerH3Driver]. See [H3Controller] for
56/// details.
57pub type ServerH3Controller = H3Controller<ServerHooks>;
58/// Receives [`ServerH3Event`]s from a [ServerH3Driver]. This is the control
59/// stream which describes what is happening on the connection, but does not
60/// transfer data.
61pub type ServerEventStream = mpsc::UnboundedReceiver<ServerH3Event>;
6263/// Events produced by [ServerH3Driver].
64#[derive(Debug)]
65pub enum ServerH3Event {
66 Core(H3Event),
67}
6869impl From<H3Event> for ServerH3Event {
70fn from(ev: H3Event) -> Self {
71Self::Core(ev)
72 }
73}
7475/// Commands accepted by [ServerH3Driver].
76#[derive(Debug)]
77pub enum ServerH3Command {
78 Core(H3Command),
79}
8081impl From<H3Command> for ServerH3Command {
82fn from(cmd: H3Command) -> Self {
83Self::Core(cmd)
84 }
85}
8687impl From<QuicCommand> for ServerH3Command {
88fn from(cmd: QuicCommand) -> Self {
89Self::Core(H3Command::QuicCmd(cmd))
90 }
91}
9293pub struct ServerHooks {
94/// Helper to enforce limits and timeouts on an HTTP/3 connection.
95settings_enforcer: Http3SettingsEnforcer,
96/// Tracks the number of requests that have been handled by this driver.
97requests: u64,
9899/// Handle to the post-accept timeout entry. If present, the server must
100 /// receive a HEADERS frame before this timeout.
101post_accept_timeout: Option<TimeoutKey>,
102}
103104impl ServerHooks {
105/// Handles a new request, creating a stream context, checking for a
106 /// potential DATAGRAM flow (CONNECT-{UDP,IP}) and sending a relevant
107 /// [`H3Event`] to the [ServerH3Controller] for application-level
108 /// processing.
109fn handle_request(
110 driver: &mut H3Driver<Self>, headers: InboundHeaders,
111 ) -> H3ConnectionResult<()> {
112let InboundHeaders {
113 stream_id,
114 headers,
115 has_body,
116 } = headers;
117118// Multiple HEADERS frames can be received on a single stream, but only
119 // the first one is an actual request. For now ignore any additional
120 // HEADERS (e.g. "trailers").
121if driver.stream_map.contains_key(&stream_id) {
122return Ok(());
123 }
124125let (mut stream_ctx, send, recv) =
126 StreamCtx::new(stream_id, STREAM_CAPACITY);
127128if let Some(flow_id) = datagram::extract_flow_id(stream_id, &headers) {
129let _ = driver.get_or_insert_flow(flow_id)?;
130 stream_ctx.associated_dgram_flow_id = Some(flow_id);
131 }
132133let headers = IncomingH3Headers {
134 stream_id,
135 headers,
136 send,
137 recv,
138 read_fin: !has_body,
139 h3_audit_stats: Arc::clone(&stream_ctx.audit_stats),
140 };
141142 driver
143 .waiting_streams
144 .push(stream_ctx.wait_for_recv(stream_id));
145 driver.insert_stream(stream_id, stream_ctx);
146147 driver
148 .h3_event_sender
149 .send(H3Event::IncomingHeaders(headers).into())
150 .map_err(|_| H3ConnectionError::ControllerWentAway)?;
151 driver.hooks.requests += 1;
152153Ok(())
154 }
155}
156157#[allow(private_interfaces)]
158impl DriverHooks for ServerHooks {
159type Command = ServerH3Command;
160type Event = ServerH3Event;
161162fn new(settings: &Http3Settings) -> Self {
163Self {
164 settings_enforcer: settings.into(),
165 requests: 0,
166 post_accept_timeout: None,
167 }
168 }
169170fn conn_established(
171 driver: &mut H3Driver<Self>, qconn: &mut QuicheConnection,
172 handshake_info: &HandshakeInfo,
173 ) -> H3ConnectionResult<()> {
174assert!(
175 qconn.is_server(),
176"ServerH3Driver requires a server-side QUIC connection"
177);
178179if let Some(post_accept_timeout) =
180 driver.hooks.settings_enforcer.post_accept_timeout()
181 {
182let remaining = post_accept_timeout
183 .checked_sub(handshake_info.elapsed())
184 .ok_or(H3ConnectionError::PostAcceptTimeout)?;
185186let key = driver
187 .hooks
188 .settings_enforcer
189 .add_timeout(Http3TimeoutType::PostAccept, remaining);
190 driver.hooks.post_accept_timeout = Some(key);
191 }
192193Ok(())
194 }
195196fn headers_received(
197 driver: &mut H3Driver<Self>, qconn: &mut QuicheConnection,
198 headers: InboundHeaders,
199 ) -> H3ConnectionResult<()> {
200if driver
201 .hooks
202 .settings_enforcer
203 .enforce_requests_limit(driver.hooks.requests)
204 {
205let _ =
206 qconn.close(true, quiche::h3::WireErrorCode::NoError as u64, &[]);
207return Ok(());
208 }
209210if let Some(timeout) = driver.hooks.post_accept_timeout.take() {
211// We've seen the first Headers event for the connection,
212 // so we can abort the post-accept timeout
213driver.hooks.settings_enforcer.cancel_timeout(timeout);
214 }
215216Self::handle_request(driver, headers)
217 }
218219fn conn_command(
220 driver: &mut H3Driver<Self>, qconn: &mut QuicheConnection,
221 cmd: Self::Command,
222 ) -> H3ConnectionResult<()> {
223let ServerH3Command::Core(cmd) = cmd;
224 driver.handle_core_command(qconn, cmd)
225 }
226227fn has_wait_action(driver: &mut H3Driver<Self>) -> bool {
228 driver.hooks.settings_enforcer.has_pending_timeouts()
229 }
230231async fn wait_for_action(
232&mut self, qconn: &mut QuicheConnection,
233 ) -> H3ConnectionResult<()> {
234self.settings_enforcer.enforce_timeouts(qconn).await?;
235Err(H3ConnectionError::PostAcceptTimeout)
236 }
237}