Skip to main content

vibeio_http/h2/
options.rs

1use std::time::Duration;
2
3use crate::h2::codec::{DEFAULT_INITIAL_WINDOW_SIZE, DEFAULT_MAX_FRAME_SIZE};
4
5/// HTTP/2 server configuration.
6///
7/// Build one with [`Http2Options::default`] and override individual fields
8/// with the builder methods, then hand it to [`Http2::new`](crate::Http2::new).
9///
10/// Unlike the framing/header limits below, the connection window settings
11/// ([`initial_stream_window_size`](Http2Options::initial_stream_window_size)
12/// and [`initial_connection_window_size`](Http2Options::initial_connection_window_size))
13/// are advisory: a client may shrink them with its own `SETTINGS`, and the
14/// server honours the smaller value.
15#[derive(Debug, Clone)]
16pub struct Http2Options {
17    /// Max time to wait for the client's preface before giving up.
18    pub(crate) handshake_timeout: Option<Duration>,
19    /// Send a `100 Continue` response as soon as a request's headers arrive,
20    /// before its body has been fully read.
21    pub(crate) send_continue_response: bool,
22    /// Insert a `Date` header into every response when absent.
23    pub(crate) send_date_header: bool,
24    /// Maximum number of concurrent streams the server allows.
25    pub(crate) max_concurrent_streams: u32,
26    /// Initial per-stream flow-control window the server advertises.
27    pub(crate) initial_stream_window_size: u32,
28    /// Initial connection-level flow-control window the server uses.
29    pub(crate) initial_connection_window_size: u32,
30    /// Largest frame payload the server will send or receive.
31    pub(crate) max_frame_size: u32,
32    /// Largest uncompressed header list the server will accept.
33    pub(crate) max_header_list_size: u32,
34    /// Whether to enable Extended CONNECT
35    pub(crate) enable_connect_protocol: bool,
36    /// Close a connection after this long with no frame from the peer
37    /// (RFC 9113 Section 10.5). `None` disables the idle timeout.
38    pub(crate) idle_timeout: Option<Duration>,
39    /// Maximum number of RST_STREAM frames this endpoint sends in
40    /// response to protocol errors made by the peer across the lifetime
41    /// of the connection. `None` disables the limit.
42    pub(crate) max_local_error_reset_streams: Option<usize>,
43    /// Maximum number of streams the peer reset before this endpoint
44    /// accepted them (their request was never dispatched). `None`
45    /// disables the limit.
46    pub(crate) max_pending_accept_reset_streams: Option<usize>,
47    /// Maximum number of frames that may make up a single, not-yet-finalized
48    /// header field block (HEADERS or PUSH_PROMISE without END_HEADERS
49    /// followed by CONTINUATION frames). A peer that keeps a field block
50    /// open across more frames than this is running a CONTINUATION flood
51    /// (CVE-2024-27919 et al.) and the offending stream is reset with
52    /// `RST_STREAM` `PROTOCOL_ERROR`. `None` selects a safe default derived
53    /// from `max_header_list_size` / `max_frame_size` plus a packing buffer.
54    pub(crate) max_continuation_frames: Option<usize>,
55}
56
57impl Default for Http2Options {
58    #[inline]
59    fn default() -> Self {
60        Http2Options {
61            handshake_timeout: Some(Duration::from_secs(10)),
62            send_continue_response: true,
63            send_date_header: true,
64            max_concurrent_streams: 200,
65            initial_stream_window_size: DEFAULT_INITIAL_WINDOW_SIZE,
66            initial_connection_window_size: DEFAULT_INITIAL_WINDOW_SIZE,
67            max_frame_size: DEFAULT_MAX_FRAME_SIZE as u32,
68            max_header_list_size: 1024 * 16,
69            enable_connect_protocol: false,
70            idle_timeout: None,
71            max_local_error_reset_streams: Some(1024),
72            max_pending_accept_reset_streams: Some(20),
73            max_continuation_frames: None,
74        }
75    }
76}
77
78impl Http2Options {
79    /// Sets the maximum time to wait for a client to send the HTTP/2
80    /// preface before aborting the connection.
81    #[inline]
82    pub fn handshake_timeout(mut self, handshake_timeout: Option<Duration>) -> Self {
83        self.handshake_timeout = handshake_timeout;
84        self
85    }
86
87    /// Sends `100 Continue` responses automatically when a request has a body.
88    ///
89    /// Defaults to `true`.
90    #[inline]
91    pub fn send_continue_response(mut self, send_continue_response: bool) -> Self {
92        self.send_continue_response = send_continue_response;
93        self
94    }
95
96    /// Inserts a `Date` header into responses that lack one.
97    ///
98    /// Defaults to `true`.
99    #[inline]
100    pub fn send_date_header(mut self, send_date_header: bool) -> Self {
101        self.send_date_header = send_date_header;
102        self
103    }
104
105    /// Sets the maximum number of concurrent streams allowed on a connection.
106    ///
107    /// Defaults to `200`.
108    #[inline]
109    pub fn max_concurrent_streams(mut self, max_concurrent_streams: u32) -> Self {
110        self.max_concurrent_streams = max_concurrent_streams;
111        self
112    }
113
114    /// Sets the initial per-stream flow-control window size advertised to the
115    /// client. Defaults to `1_048_576`.
116    #[inline]
117    pub fn initial_stream_window_size(mut self, initial_stream_window_size: u32) -> Self {
118        self.initial_stream_window_size = initial_stream_window_size;
119        self
120    }
121
122    /// Sets the initial connection-level flow-control window size.
123    /// Defaults to `1_048_576`.
124    #[inline]
125    pub fn initial_connection_window_size(mut self, initial_connection_window_size: u32) -> Self {
126        self.initial_connection_window_size = initial_connection_window_size;
127        self
128    }
129
130    /// Sets the maximum frame size the server will send or receive.
131    /// Defaults to the RFC 9113 default (`16_384`); must not exceed
132    /// `2^24 - 1`.
133    #[inline]
134    pub fn max_frame_size(mut self, max_frame_size: u32) -> Self {
135        self.max_frame_size = max_frame_size;
136        self
137    }
138
139    /// Sets the maximum size of an uncompressed header list the server will
140    /// accept. Defaults to `16_384`.
141    #[inline]
142    pub fn max_header_list_size(mut self, max_header_list_size: u32) -> Self {
143        self.max_header_list_size = max_header_list_size;
144        self
145    }
146
147    /// Sets whether to enable the Extended CONNECT protocol, allowing for
148    /// example for tunneling WebSockets over HTTP/2. Defaults to `false`.
149    #[inline]
150    pub fn enable_connect_protocol(mut self, enable: bool) -> Self {
151        self.enable_connect_protocol = enable;
152        self
153    }
154
155    /// Sets the idle timeout: a connection that receives no frame from the
156    /// peer for this long is closed gracefully with a `GOAWAY` (RFC 9113
157    /// Section 10.5). Defaults to `None` (no idle timeout).
158    #[inline]
159    pub fn idle_timeout(mut self, idle_timeout: Option<Duration>) -> Self {
160        self.idle_timeout = idle_timeout;
161        self
162    }
163
164    /// Sets the maximum number of RST_STREAM frames this endpoint sends in
165    /// response to protocol errors made by the peer across the lifetime of
166    /// the connection. When the peer keeps producing protocol errors past
167    /// this many local resets, the connection is closed with a GOAWAY of
168    /// type `ENHANCE_YOUR_CALM` (RFC 9113 Section 10.5.2). `None` disables
169    /// the limit. Defaults to `Some(1024)`.
170    #[inline]
171    pub fn max_local_error_reset_streams(mut self, max: Option<usize>) -> Self {
172        self.max_local_error_reset_streams = max;
173        self
174    }
175
176    /// Sets the maximum number of streams the peer reset before this endpoint
177    /// accepted them (their request was never dispatched) that may be
178    /// counted at a time. When the peer keeps opening and resetting streams
179    /// faster than they are consumed, the connection is closed with a GOAWAY
180    /// of type `ENHANCE_YOUR_CALM` (RFC 9113 Section 10.5.2). `None` disables
181    /// the limit. Defaults to `Some(20)`.
182    #[inline]
183    pub fn max_pending_accept_reset_streams(mut self, max: Option<usize>) -> Self {
184        self.max_pending_accept_reset_streams = max;
185        self
186    }
187
188    /// Sets the maximum number of frames that may compose a single header
189    /// field block that has not yet been terminated by END_HEADERS. A field
190    /// block is opened by a HEADERS (or PUSH_PROMISE) frame without
191    /// END_HEADERS and continued by CONTINUATION frames. When a peer keeps
192    /// one open past this many frames, it is a CONTINUATION flood and the
193    /// stream is reset with `RST_STREAM` `PROTOCOL_ERROR`.
194    ///
195    /// `None` (the default) computes a safe bound automatically: the
196    /// configured `max_header_list_size` divided by `max_frame_size`,
197    /// plus a ~20% packing buffer and a fixed slack of 10 frames. This is
198    /// enough for any honestly-packed header block while catching floods
199    /// that never close the block.
200    ///
201    /// Defaults to `None`.
202    #[inline]
203    pub fn max_continuation_frames(mut self, max: Option<usize>) -> Self {
204        self.max_continuation_frames = max;
205        self
206    }
207}