Skip to main content

trillium_http/
http_config.rs

1use fieldwork::Fieldwork;
2
3/// # Performance and security parameters for trillium-http.
4///
5/// Trillium's http implementation is built with sensible defaults, but applications differ in usage
6/// and this escape hatch allows an application to be tuned. It is best to tune these parameters in
7/// context of realistic benchmarks for your application.
8///
9/// Long term, trillium may export several standard defaults for different constraints and
10/// application types. In the distant future, these may turn into initial values and trillium will
11/// tune itself based on values seen at runtime.
12#[derive(Clone, Copy, Debug, Fieldwork)]
13#[fieldwork(get, get_mut, set, with, without)]
14pub struct HttpConfig {
15    /// The maximum length allowed before the http body begins for a given request.
16    ///
17    /// **Default**: `8kb` in bytes
18    ///
19    /// **Unit**: Byte count
20    pub(crate) head_max_len: usize,
21
22    /// The maximum length of a received body
23    ///
24    /// This limit applies regardless of whether the body is read all at once or streamed
25    /// incrementally, and regardless of transfer encoding (chunked or fixed-length). The correct
26    /// value will be application dependent.
27    ///
28    /// **Default**: `10mb` in bytes
29    ///
30    /// **Unit**: Byte count
31    pub(crate) received_body_max_len: u64,
32
33    #[field = false] // this one is private for now
34    pub(crate) max_headers: usize,
35
36    /// The initial buffer allocated for the response.
37    ///
38    /// Ideally this would be exactly the length of the combined response headers and body, if the
39    /// body is short. If the value is shorter than the headers plus the body, multiple transport
40    /// writes will be performed, and if the value is longer, unnecessary memory will be allocated
41    /// for each conn. Although a tcp packet can be up to 64kb, it is probably better to use a
42    /// value less than 1.5kb.
43    ///
44    /// **Default**: `512`
45    ///
46    /// **Unit**: byte count
47    pub(crate) response_buffer_len: usize,
48
49    /// Maximum size the response buffer may grow to absorb backpressure.
50    ///
51    /// When the transport cannot accept data as fast as the response body is produced, the buffer
52    /// absorbs the remainder up to this limit. Once the limit is reached, writes apply
53    /// backpressure to the body source. This prevents a slow client from causing unbounded memory
54    /// growth.
55    ///
56    /// **Default**: `2mb` in bytes
57    ///
58    /// **Unit**: byte count
59    pub(crate) response_buffer_max_len: usize,
60
61    /// The initial buffer allocated for the request headers.
62    ///
63    /// Ideally this is the length of the request headers. It will grow nonlinearly until
64    /// `max_head_len` or the end of the headers are reached, whichever happens first.
65    ///
66    /// **Default**: `128`
67    ///
68    /// **Unit**: byte count
69    pub(crate) request_buffer_initial_len: usize,
70
71    /// The number of response headers to allocate space for on conn creation.
72    ///
73    /// Headers will grow on insertion when they reach this size.
74    ///
75    /// **Default**: `16`
76    ///
77    /// **Unit**: Header count
78    pub(crate) response_header_initial_capacity: usize,
79
80    /// A sort of cooperative task yielding knob.
81    ///
82    /// Decreasing this number will improve tail latencies at a slight cost to total throughput for
83    /// fast clients. This will have more of an impact on servers that spend a lot of time in IO
84    /// compared to app handlers.
85    ///
86    /// **Default**: `16`
87    ///
88    /// **Unit**: the number of consecutive `Poll::Ready` async writes to perform before yielding
89    /// the task back to the runtime.
90    pub(crate) copy_loops_per_yield: usize,
91
92    /// The initial buffer capacity allocated when reading a chunked http body to bytes or string.
93    ///
94    /// Ideally this would be the size of the http body, which is highly application dependent. As
95    /// with other initial buffer lengths, further allocation will be performed until the necessary
96    /// length is achieved. A smaller number will result in more vec resizing, and a larger number
97    /// will result in unnecessary allocation.
98    ///
99    /// **Default**: `128`
100    ///
101    /// **Unit**: byte count
102    pub(crate) received_body_initial_len: usize,
103
104    /// Maximum size to pre-allocate based on content-length for buffering a complete request body
105    ///
106    /// When we receive a fixed-length (not chunked-encoding) body that is smaller than this size,
107    /// we can allocate a buffer with exactly the right size before we receive the body.  However,
108    /// if this is unbounded, malicious clients can issue headers with large content-length and
109    /// then keep the connection open without sending any bytes, allowing them to allocate
110    /// memory faster than their bandwidth usage. This does not limit the ability to receive
111    /// fixed-length bodies larger than this, but the memory allocation will grow as with
112    /// chunked bodies. Note that this has no impact on chunked bodies. If this is set higher
113    /// than the `received_body_max_len`, this parameter has no effect. This parameter only
114    /// impacts [`ReceivedBody::read_string`](crate::ReceivedBody::read_string) and
115    /// [`ReceivedBody::read_bytes`](crate::ReceivedBody::read_bytes).
116    ///
117    /// **Default**: `1mb` in bytes
118    ///
119    /// **Unit**: Byte count
120    pub(crate) received_body_max_preallocate: usize,
121
122    /// The maximum size of a field section (header block) the peer may send in HTTP/3
123    ///
124    /// This is a protocol-level setting and is communicated to the peer.
125    ///
126    /// **Default**: 8kb
127    ///
128    /// **Unit**: Byte count
129    pub(crate) h3_max_field_section_size: u64,
130
131    /// whether [datagrams](https://www.rfc-editor.org/rfc/rfc9297.html) are enabled for HTTP/3
132    ///
133    /// This is a protocol-level setting and is communicated to the peer as well as enforced.
134    ///
135    /// **Default**: false
136    pub(crate) h3_datagrams_enabled: bool,
137
138    /// whether [webtransport](https://datatracker.ietf.org/doc/html/draft-ietf-webtrans-http3)
139    /// (`draft-ietf-webtrans-http3`) is enabled for HTTP/3
140    ///
141    /// This is a protocol-level setting and is communicated to the peer. You do not need to
142    /// manually configure this if using
143    /// [`trillium-webtransport`](https://docs.rs/trillium-webtransport)
144    ///
145    /// **Default**: false
146    pub(crate) webtransport_enabled: bool,
147
148    /// whether to panic when a response header with an invalid value (containing `\r`, `\n`, or
149    /// `\0`) is encountered.
150    ///
151    /// Invalid header values are always skipped to prevent header injection. When this is `true`,
152    /// Trillium will additionally panic, surfacing the bug loudly. When `false`, the skip is only
153    /// logged (to the `log` backend) at error level.
154    ///
155    /// **Default**: `true` when compiled with `debug_assertions` (i.e. debug builds), `false` in
156    /// release builds. Override to `true` in release if you want strict production behavior, or to
157    /// `false` in debug if you prefer not to panic during development.
158    pub(crate) panic_on_invalid_response_headers: bool,
159}
160
161impl HttpConfig {
162    /// Default Config
163    pub const DEFAULT: Self = HttpConfig {
164        response_buffer_len: 512,
165        response_buffer_max_len: 2 * 1024 * 1024,
166        request_buffer_initial_len: 128,
167        head_max_len: 8 * 1024,
168        max_headers: 128,
169        response_header_initial_capacity: 16,
170        copy_loops_per_yield: 16,
171        received_body_max_len: 10 * 1024 * 1024,
172        received_body_initial_len: 128,
173        received_body_max_preallocate: 1024 * 1024,
174        h3_max_field_section_size: 8 * 1024,
175        h3_datagrams_enabled: false,
176        webtransport_enabled: false,
177        panic_on_invalid_response_headers: cfg!(debug_assertions),
178    };
179}
180
181impl Default for HttpConfig {
182    fn default() -> Self {
183        HttpConfig::DEFAULT
184    }
185}