1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 //! HTTP configure module.
15 #[cfg(feature = "http3")]
16 use crate::ErrorKind;
17 
18 /// Options and flags which can be used to configure `HTTP` related logic.
19 #[derive(Clone)]
20 pub(crate) struct HttpConfig {
21     pub(crate) version: HttpVersion,
22 
23     #[cfg(feature = "http2")]
24     pub(crate) http2_config: http2::H2Config,
25 
26     #[cfg(feature = "http3")]
27     pub(crate) http3_config: http3::H3Config,
28 }
29 
30 impl HttpConfig {
31     /// Creates a new, default `HttpConfig`.
32     pub(crate) fn new() -> Self {
33         Self {
34             version: HttpVersion::Negotiate,
35 
36             #[cfg(feature = "http2")]
37             http2_config: http2::H2Config::new(),
38 
39             #[cfg(feature = "http3")]
40             http3_config: http3::H3Config::new(),
41         }
42     }
43 }
44 
45 impl Default for HttpConfig {
defaultnull46     fn default() -> Self {
47         Self::new()
48     }
49 }
50 
51 /// `HTTP` version to use.
52 #[derive(PartialEq, Eq, Clone)]
53 pub enum HttpVersion {
54     /// Enforces `HTTP/1.1` or `HTTP/1.0` requests.
55     Http1,
56 
57     #[cfg(feature = "http2")]
58     /// Enforce `HTTP/2.0` requests without `HTTP/1.1` Upgrade or ALPN.
59     Http2,
60 
61     #[cfg(feature = "http3")]
62     /// Enforces `HTTP/3` requests.
63     Http3,
64 
65     /// Negotiate the protocol version through the ALPN.
66     Negotiate,
67 }
68 
69 #[cfg(feature = "http3")]
70 impl TryFrom<&[u8]> for HttpVersion {
71     type Error = ErrorKind;
72 
try_fromnull73     fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
74         if value == b"h1" {
75             return Ok(HttpVersion::Http1);
76         }
77         #[cfg(feature = "http2")]
78         if value == b"h2" {
79             return Ok(HttpVersion::Http2);
80         }
81         if value == b"h3" {
82             Ok(HttpVersion::Http3)
83         } else {
84             Err(ErrorKind::Other)
85         }
86     }
87 }
88 
89 #[cfg(feature = "http2")]
90 pub(crate) mod http2 {
91     const DEFAULT_MAX_FRAME_SIZE: u32 = 16 * 1024;
92     const DEFAULT_HEADER_TABLE_SIZE: u32 = 4096;
93     const DEFAULT_MAX_HEADER_LIST_SIZE: u32 = 16 * 1024;
94     // window size at the client connection level
95     // The initial value specified in rfc9113 is 64kb,
96     // but the default value is 1mb for performance purposes and is synchronized
97     // using WINDOW_UPDATE after sending SETTINGS.
98     const DEFAULT_CONN_WINDOW_SIZE: u32 = 10 * 1024 * 1024;
99     const DEFAULT_STREAM_WINDOW_SIZE: u32 = 2 * 1024 * 1024;
100 
101     /// Settings which can be used to configure a http2 connection.
102     #[derive(Clone)]
103     pub(crate) struct H2Config {
104         max_frame_size: u32,
105         max_header_list_size: u32,
106         header_table_size: u32,
107         init_conn_window_size: u32,
108         init_stream_window_size: u32,
109         enable_push: bool,
110         allowed_cache_frame_size: usize,
111         use_huffman: bool,
112     }
113 
114     impl H2Config {
115         /// `H2Config` constructor.
116         pub(crate) fn new() -> Self {
117             Self::default()
118         }
119 
120         /// Sets the SETTINGS_MAX_FRAME_SIZE.
121         pub(crate) fn set_max_frame_size(&mut self, size: u32) {
122             self.max_frame_size = size;
123         }
124 
125         /// Sets the SETTINGS_MAX_HEADER_LIST_SIZE.
126         pub(crate) fn set_max_header_list_size(&mut self, size: u32) {
127             self.max_header_list_size = size;
128         }
129 
130         /// Sets the SETTINGS_HEADER_TABLE_SIZE.
131         pub(crate) fn set_header_table_size(&mut self, size: u32) {
132             self.header_table_size = size;
133         }
134 
135         pub(crate) fn set_conn_window_size(&mut self, size: u32) {
136             self.init_conn_window_size = size;
137         }
138 
139         pub(crate) fn set_stream_window_size(&mut self, size: u32) {
140             self.init_stream_window_size = size;
141         }
142 
143         pub(crate) fn set_allowed_cache_frame_size(&mut self, size: usize) {
144             self.allowed_cache_frame_size = size;
145         }
146 
147         pub(crate) fn set_use_huffman_coding(&mut self, use_huffman: bool) {
148             self.use_huffman = use_huffman;
149         }
150 
151         /// Gets the SETTINGS_MAX_FRAME_SIZE.
152         pub(crate) fn max_frame_size(&self) -> u32 {
153             self.max_frame_size
154         }
155 
156         /// Gets the SETTINGS_MAX_HEADER_LIST_SIZE.
157         pub(crate) fn max_header_list_size(&self) -> u32 {
158             self.max_header_list_size
159         }
160 
161         /// Gets the SETTINGS_MAX_FRAME_SIZE.
162         pub(crate) fn header_table_size(&self) -> u32 {
163             self.header_table_size
164         }
165 
166         pub(crate) fn enable_push(&self) -> bool {
167             self.enable_push
168         }
169 
170         pub(crate) fn conn_window_size(&self) -> u32 {
171             self.init_conn_window_size
172         }
173 
174         pub(crate) fn stream_window_size(&self) -> u32 {
175             self.init_stream_window_size
176         }
177 
178         pub(crate) fn allowed_cache_frame_size(&self) -> usize {
179             self.allowed_cache_frame_size
180         }
181 
182         pub(crate) fn use_huffman_coding(&self) -> bool {
183             self.use_huffman
184         }
185     }
186 
187     impl Default for H2Config {
defaultnull188         fn default() -> Self {
189             Self {
190                 max_frame_size: DEFAULT_MAX_FRAME_SIZE,
191                 max_header_list_size: DEFAULT_MAX_HEADER_LIST_SIZE,
192                 header_table_size: DEFAULT_HEADER_TABLE_SIZE,
193                 init_conn_window_size: DEFAULT_CONN_WINDOW_SIZE,
194                 init_stream_window_size: DEFAULT_STREAM_WINDOW_SIZE,
195                 enable_push: false,
196                 allowed_cache_frame_size: 5,
197                 use_huffman: true,
198             }
199         }
200     }
201 }
202 
203 #[cfg(feature = "http3")]
204 pub(crate) mod http3 {
205     const DEFAULT_MAX_FIELD_SECTION_SIZE: u64 = 16 * 1024;
206     const DEFAULT_QPACK_MAX_TABLE_CAPACITY: u64 = 16 * 1024;
207     const DEFAULT_QPACK_BLOCKED_STREAMS: u64 = 10;
208 
209     // todo: which settings should be pub to user
210     #[derive(Clone)]
211     pub(crate) struct H3Config {
212         max_field_section_size: u64,
213         qpack_max_table_capacity: u64,
214         qpack_blocked_streams: u64,
215         connect_protocol_enabled: Option<u64>,
216         additional_settings: Option<Vec<(u64, u64)>>,
217     }
218 
219     impl H3Config {
220         /// `H3Config` constructor.
221 
222         pub(crate) fn new() -> Self {
223             Self::default()
224         }
225 
226         pub(crate) fn set_max_field_section_size(&mut self, size: u64) {
227             self.max_field_section_size = size;
228         }
229 
230         pub(crate) fn set_qpack_max_table_capacity(&mut self, size: u64) {
231             self.qpack_max_table_capacity = size;
232         }
233 
234         pub(crate) fn set_qpack_blocked_streams(&mut self, size: u64) {
235             self.qpack_blocked_streams = size;
236         }
237 
238         #[allow(unused)]
set_connect_protocol_enablednull239         fn set_connect_protocol_enabled(&mut self, size: u64) {
240             self.connect_protocol_enabled = Some(size);
241         }
242 
243         #[allow(unused)]
insert_additional_settingsnull244         fn insert_additional_settings(&mut self, key: u64, value: u64) {
245             if let Some(vec) = &mut self.additional_settings {
246                 vec.push((key, value));
247             } else {
248                 self.additional_settings = Some(vec![(key, value)]);
249             }
250         }
251 
252         pub(crate) fn max_field_section_size(&self) -> u64 {
253             self.max_field_section_size
254         }
255 
256         pub(crate) fn qpack_max_table_capacity(&self) -> u64 {
257             self.qpack_max_table_capacity
258         }
259 
260         pub(crate) fn qpack_blocked_streams(&self) -> u64 {
261             self.qpack_blocked_streams
262         }
263 
264         #[allow(unused)]
connect_protocol_enablednull265         fn connect_protocol_enabled(&mut self) -> Option<u64> {
266             self.connect_protocol_enabled
267         }
268 
269         #[allow(unused)]
additional_settingsnull270         fn additional_settings(&mut self) -> Option<Vec<(u64, u64)>> {
271             self.additional_settings.clone()
272         }
273     }
274 
275     impl Default for H3Config {
defaultnull276         fn default() -> Self {
277             Self {
278                 max_field_section_size: DEFAULT_MAX_FIELD_SECTION_SIZE,
279                 qpack_max_table_capacity: DEFAULT_QPACK_MAX_TABLE_CAPACITY,
280                 qpack_blocked_streams: DEFAULT_QPACK_BLOCKED_STREAMS,
281                 connect_protocol_enabled: None,
282                 additional_settings: None,
283             }
284         }
285     }
286 }
287