Skip to main content

xitca_http/
config.rs

1//! Configuration for http service middlewares.
2
3use core::time::Duration;
4
5/// The default maximum read buffer size. If the head gets this big and
6/// a message is still not complete, a `TooLarge` error is triggered.
7///
8/// When handing request body ff the buffer gets this big a force yield
9/// from Io stream read would happen.
10pub const DEFAULT_READ_BUF_LIMIT: usize = 1024 * 1024;
11
12/// The default maximum write buffer size. If the buffer gets this big and
13/// a message is still not complete, a force draining of Io stream write
14/// would happen.
15pub const DEFAULT_WRITE_BUF_LIMIT: usize = 8192 + 4096 * 100;
16
17/// The default maximum request header fields possible for one request.
18///
19/// 64 chosen for no particular reason.
20pub const DEFAULT_HEADER_LIMIT: usize = 64;
21
22#[derive(Copy, Clone)]
23pub struct HttpServiceConfig<
24    const HEADER_LIMIT: usize = DEFAULT_HEADER_LIMIT,
25    const READ_BUF_LIMIT: usize = DEFAULT_READ_BUF_LIMIT,
26    const WRITE_BUF_LIMIT: usize = DEFAULT_WRITE_BUF_LIMIT,
27> {
28    pub(crate) vectored_write: bool,
29    pub(crate) keep_alive_timeout: Duration,
30    pub(crate) request_head_timeout: Duration,
31    pub(crate) tls_accept_timeout: Duration,
32    pub(crate) peek_protocol: bool,
33    pub(crate) h2_max_concurrent_streams: u32,
34    pub(crate) h2_initial_window_size: u32,
35    pub(crate) h2_max_frame_size: u32,
36    pub(crate) h2_max_header_list_size: u32,
37}
38
39impl Default for HttpServiceConfig {
40    fn default() -> Self {
41        Self::new()
42    }
43}
44
45impl HttpServiceConfig {
46    pub const fn new() -> Self {
47        Self {
48            vectored_write: true,
49            keep_alive_timeout: Duration::from_secs(5),
50            request_head_timeout: Duration::from_secs(5),
51            tls_accept_timeout: Duration::from_secs(3),
52            peek_protocol: false,
53            h2_max_concurrent_streams: 256,
54            h2_initial_window_size: 65_535,
55            h2_max_frame_size: 16_384,
56            h2_max_header_list_size: 16 * 1024 * 1024,
57        }
58    }
59}
60
61impl<const HEADER_LIMIT: usize, const READ_BUF_LIMIT: usize, const WRITE_BUF_LIMIT: usize>
62    HttpServiceConfig<HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT>
63{
64    /// Disable vectored write even when IO is able to perform it.
65    ///
66    /// This is beneficial when dealing with small size of response body.
67    pub const fn disable_vectored_write(mut self) -> Self {
68        self.vectored_write = false;
69        self
70    }
71
72    /// Define duration of how long an idle connection is kept alive.
73    ///
74    /// connection have not done any IO after duration would be closed. IO operation
75    /// can possibly result in reset of the duration.
76    pub const fn keep_alive_timeout(mut self, dur: Duration) -> Self {
77        self.keep_alive_timeout = dur;
78        self
79    }
80
81    /// Define duration of how long a connection must finish it's request head transferring.
82    /// starting from first byte(s) of current request(s) received from peer.
83    ///
84    /// connection can not make a single request after duration would be closed.
85    pub const fn request_head_timeout(mut self, dur: Duration) -> Self {
86        self.request_head_timeout = dur;
87        self
88    }
89
90    /// Define duration of how long a connection must finish it's tls handshake.
91    /// (If tls is enabled)
92    ///
93    /// Connection can not finish handshake after duration would be closed.
94    pub const fn tls_accept_timeout(mut self, dur: Duration) -> Self {
95        self.tls_accept_timeout = dur;
96        self
97    }
98
99    /// Define max read buffer size for a connection.
100    ///
101    /// See [DEFAULT_READ_BUF_LIMIT] for default value and behavior.
102    ///
103    /// # Panics
104    /// Panics when `READ_BUF_LIMIT_2 < 32` or when `READ_BUF_LIMIT_2 < h2_max_frame_size + 9`.
105    /// The read buffer must be large enough to hold a full HTTP/2 frame (max payload + 9 byte
106    /// header), otherwise the dispatcher would deadlock waiting for a frame that can never fit.
107    ///
108    /// When called in a const context (e.g. `const CFG: _ = HttpServiceConfig::new()...`)
109    /// a violation is reported as a compile-time error instead of a runtime panic.
110    pub const fn max_read_buf_size<const READ_BUF_LIMIT_2: usize>(
111        self,
112    ) -> HttpServiceConfig<HEADER_LIMIT, READ_BUF_LIMIT_2, WRITE_BUF_LIMIT> {
113        assert!(READ_BUF_LIMIT_2 >= 32, "READ_BUF_LIMIT must be no less than 32 bytes");
114        h2_frame_read_buf_check(READ_BUF_LIMIT_2, self.h2_max_frame_size as _);
115        self.mutate_const_generic::<HEADER_LIMIT, READ_BUF_LIMIT_2, WRITE_BUF_LIMIT>()
116    }
117
118    /// Define max write buffer size for a connection.
119    ///
120    /// See [DEFAULT_WRITE_BUF_LIMIT] for default value
121    /// and behavior.
122    pub const fn max_write_buf_size<const WRITE_BUF_LIMIT_2: usize>(
123        self,
124    ) -> HttpServiceConfig<HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT_2> {
125        self.mutate_const_generic::<HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT_2>()
126    }
127
128    /// Define max request header count for a connection.    
129    ///
130    /// See [DEFAULT_HEADER_LIMIT] for default value
131    /// and behavior.
132    pub const fn max_request_headers<const HEADER_LIMIT_2: usize>(
133        self,
134    ) -> HttpServiceConfig<HEADER_LIMIT_2, READ_BUF_LIMIT, WRITE_BUF_LIMIT> {
135        self.mutate_const_generic::<HEADER_LIMIT_2, READ_BUF_LIMIT, WRITE_BUF_LIMIT>()
136    }
137
138    /// Define the maximum number of concurrent HTTP/2 streams per connection.
139    pub const fn h2_max_concurrent_streams(mut self, val: u32) -> Self {
140        self.h2_max_concurrent_streams = val;
141        self
142    }
143
144    /// Define the initial flow-control window size for HTTP/2 streams.
145    ///
146    /// Must not exceed 2^31-1 (2,147,483,647).
147    pub const fn h2_initial_window_size(mut self, val: u32) -> Self {
148        self.h2_initial_window_size = val;
149        self
150    }
151
152    /// Define the maximum HTTP/2 frame size the server is willing to receive.
153    ///
154    /// Must be between 16,384 and 16,777,215 (inclusive).
155    ///
156    /// # Panics
157    /// Panics when `READ_BUF_LIMIT < val + 9`. The read buffer must be large enough to hold
158    /// a full HTTP/2 frame (payload + 9 byte header), otherwise the dispatcher would deadlock
159    /// waiting for a frame that can never fit. Raise the read buffer first via
160    /// [`max_read_buf_size`](Self::max_read_buf_size) when increasing the frame size.
161    ///
162    /// When called in a const context (e.g. `const CFG: _ = HttpServiceConfig::new()...`)
163    /// a violation is reported as a compile-time error instead of a runtime panic.
164    pub const fn h2_max_frame_size(mut self, val: u32) -> Self {
165        h2_frame_read_buf_check(READ_BUF_LIMIT, val as _);
166        self.h2_max_frame_size = val;
167        self
168    }
169
170    /// Define the maximum size of HTTP/2 header list the server is willing to accept.
171    pub const fn h2_max_header_list_size(mut self, val: u32) -> Self {
172        self.h2_max_header_list_size = val;
173        self
174    }
175
176    /// Enable peek into connection to figure out it's protocol regardless the outcome
177    /// of alpn negotiation.
178    ///
179    /// This API is used to bypass alpn setting from tls and enable Http/2 protocol over
180    /// plain Tcp connection.
181    pub const fn peek_protocol(mut self) -> Self {
182        self.peek_protocol = true;
183        self
184    }
185
186    #[doc(hidden)]
187    /// A shortcut for mutating const generic params.
188    pub const fn mutate_const_generic<
189        const HEADER_LIMIT2: usize,
190        const READ_BUF_LIMIT2: usize,
191        const WRITE_BUF_LIMIT2: usize,
192    >(
193        self,
194    ) -> HttpServiceConfig<HEADER_LIMIT2, READ_BUF_LIMIT2, WRITE_BUF_LIMIT2> {
195        HttpServiceConfig {
196            vectored_write: self.vectored_write,
197            keep_alive_timeout: self.keep_alive_timeout,
198            request_head_timeout: self.request_head_timeout,
199            tls_accept_timeout: self.tls_accept_timeout,
200            peek_protocol: self.peek_protocol,
201            h2_max_concurrent_streams: self.h2_max_concurrent_streams,
202            h2_initial_window_size: self.h2_initial_window_size,
203            h2_max_frame_size: self.h2_max_frame_size,
204            h2_max_header_list_size: self.h2_max_header_list_size,
205        }
206    }
207}
208
209const fn h2_frame_read_buf_check(read_buf_size: usize, h2_max_frame_size: usize) {
210    assert!(
211        read_buf_size >= (h2_max_frame_size + 9),
212        "max_read_buf_size must be at least h2_max_frame_size + 9 for HTTP2 to work"
213    );
214}