1use std::{
4 collections::HashMap,
5 fmt::Debug,
6 ops::{Deref, DerefMut},
7 sync::Arc,
8};
9
10use bytes::{Buf, BufMut, BytesMut};
11
12use thiserror::Error;
13use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
14
15use super::{Frame, UniStream, VarInt, VarIntUnexpectedEnd};
16use crate::grease::is_grease_value;
17const MAX_SETTINGS_FRAME_SIZE: usize = 16 * 1024;
18
19#[derive(Clone, Copy, PartialEq, Eq, Hash)]
20pub struct Setting(pub VarInt);
22
23impl Setting {
24 pub fn decode<B: Buf>(buf: &mut B) -> Result<Self, VarIntUnexpectedEnd> {
26 Ok(Setting(VarInt::decode(buf)?))
27 }
28
29 pub fn encode<B: BufMut>(&self, buf: &mut B) {
31 self.0.encode(buf)
32 }
33
34 pub fn size(&self) -> usize {
36 self.0.size()
37 }
38
39 pub fn is_grease(&self) -> bool {
42 is_grease_value(self.0.into_inner())
43 }
44}
45
46impl Debug for Setting {
47 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48 match *self {
49 Setting::QPACK_MAX_TABLE_CAPACITY => write!(f, "QPACK_MAX_TABLE_CAPACITY"),
50 Setting::MAX_FIELD_SECTION_SIZE => write!(f, "MAX_FIELD_SECTION_SIZE"),
51 Setting::QPACK_BLOCKED_STREAMS => write!(f, "QPACK_BLOCKED_STREAMS"),
52 Setting::ENABLE_CONNECT_PROTOCOL => write!(f, "ENABLE_CONNECT_PROTOCOL"),
53 Setting::ENABLE_DATAGRAM => write!(f, "ENABLE_DATAGRAM"),
54 Setting::ENABLE_DATAGRAM_DEPRECATED => write!(f, "ENABLE_DATAGRAM_DEPRECATED"),
55 Setting::WEBTRANSPORT_ENABLE_DEPRECATED => write!(f, "WEBTRANSPORT_ENABLE_DEPRECATED"),
56 Setting::WEBTRANSPORT_MAX_SESSIONS_DEPRECATED => {
57 write!(f, "WEBTRANSPORT_MAX_SESSIONS_DEPRECATED")
58 }
59 Setting::WEBTRANSPORT_MAX_SESSIONS => write!(f, "WEBTRANSPORT_MAX_SESSIONS"),
60 Setting::WT_ENABLED => write!(f, "WT_ENABLED"),
61 x if x.is_grease() => write!(f, "GREASE SETTING [{:x?}]", x.0.into_inner()),
62 x => write!(f, "UNKNOWN_SETTING [{:x?}]", x.0.into_inner()),
63 }
64 }
65}
66
67impl Setting {
68 pub const fn from_u32(value: u32) -> Self {
70 Self(VarInt::from_u32(value))
71 }
72
73 pub const QPACK_MAX_TABLE_CAPACITY: Setting = Setting::from_u32(0x1); pub const MAX_FIELD_SECTION_SIZE: Setting = Setting::from_u32(0x6);
78 pub const QPACK_BLOCKED_STREAMS: Setting = Setting::from_u32(0x7);
80
81 pub const ENABLE_CONNECT_PROTOCOL: Setting = Setting::from_u32(0x8);
84 pub const ENABLE_DATAGRAM: Setting = Setting::from_u32(0x33);
86 pub const ENABLE_DATAGRAM_DEPRECATED: Setting = Setting::from_u32(0xFFD277); pub const WEBTRANSPORT_ENABLE_DEPRECATED: Setting = Setting::from_u32(0x2b603742);
92 pub const WEBTRANSPORT_MAX_SESSIONS_DEPRECATED: Setting = Setting::from_u32(0x2b603743);
94
95 pub const WEBTRANSPORT_MAX_SESSIONS: Setting = Setting::from_u32(0xc671706a);
98 pub const WT_ENABLED: Setting = Setting::from_u32(0x2c7cf000);
100}
101
102#[derive(Error, Debug, Clone)]
103pub enum SettingsError {
105 #[error("unexpected end of input")]
107 UnexpectedEnd,
108
109 #[error("unexpected stream type {0:?}")]
111 UnexpectedStreamType(UniStream),
112
113 #[error("unexpected frame {0:?}")]
115 UnexpectedFrame(Frame),
116
117 #[error("invalid size")]
119 InvalidSize,
120
121 #[error("duplicate setting {0:?}")]
123 DuplicateSetting(Setting),
124
125 #[error("invalid value {1} for setting {0:?}")]
127 InvalidValue(Setting, VarInt),
128
129 #[error("SETTINGS frame exceeds the 16 KiB implementation limit")]
131 MessageTooLong,
132
133 #[error("io error: {0}")]
135 Io(Arc<std::io::Error>),
136}
137
138impl From<std::io::Error> for SettingsError {
139 fn from(err: std::io::Error) -> Self {
140 SettingsError::Io(Arc::new(err))
141 }
142}
143
144#[derive(Default, Debug)]
146pub struct Settings(HashMap<Setting, VarInt>);
148
149impl Settings {
150 pub fn decode<B: Buf>(buf: &mut B) -> Result<Self, SettingsError> {
152 let typ = UniStream::decode(buf).map_err(|_| SettingsError::UnexpectedEnd)?;
153 if typ != UniStream::CONTROL {
154 return Err(SettingsError::UnexpectedStreamType(typ));
155 }
156
157 let (typ, mut data) = Frame::read(buf).map_err(|_| SettingsError::UnexpectedEnd)?;
158 if typ != Frame::SETTINGS {
159 return Err(SettingsError::UnexpectedFrame(typ));
160 }
161
162 let mut settings = Settings::default();
163 while data.has_remaining() {
164 let id = Setting::decode(&mut data).map_err(|_| SettingsError::InvalidSize)?;
166 let value = VarInt::decode(&mut data).map_err(|_| SettingsError::InvalidSize)?;
167 if !id.is_grease() {
169 if settings.0.contains_key(&id) {
170 return Err(SettingsError::DuplicateSetting(id));
171 }
172 if matches!(
173 id,
174 Setting::ENABLE_CONNECT_PROTOCOL
175 | Setting::ENABLE_DATAGRAM
176 | Setting::ENABLE_DATAGRAM_DEPRECATED
177 | Setting::WEBTRANSPORT_ENABLE_DEPRECATED
178 | Setting::WT_ENABLED
179 ) && value.into_inner() > 1
180 {
181 return Err(SettingsError::InvalidValue(id, value));
182 }
183 settings.0.insert(id, value);
184 }
185 }
186
187 Ok(settings)
188 }
189
190 pub async fn read<S: AsyncRead + Unpin>(stream: &mut S) -> Result<Self, SettingsError> {
192 let stream_type = VarInt::read(stream)
193 .await
194 .map_err(|_| SettingsError::UnexpectedEnd)?;
195 let stream_type = UniStream(stream_type);
196 if stream_type != UniStream::CONTROL {
197 return Err(SettingsError::UnexpectedStreamType(stream_type));
198 }
199
200 loop {
201 let typ = VarInt::read(stream)
202 .await
203 .map_err(|_| SettingsError::UnexpectedEnd)?;
204 let length = VarInt::read(stream)
205 .await
206 .map_err(|_| SettingsError::UnexpectedEnd)?;
207 let length =
208 usize::try_from(length.into_inner()).map_err(|_| SettingsError::MessageTooLong)?;
209 if length > MAX_SETTINGS_FRAME_SIZE {
210 return Err(SettingsError::MessageTooLong);
211 }
212
213 let mut payload = vec![0; length];
214 stream.read_exact(&mut payload).await?;
215 let typ = Frame(typ);
216 if typ.is_grease() {
217 continue;
218 }
219
220 let mut frame =
221 Vec::with_capacity(stream_type.0.size() + typ.0.size() + VarInt::MAX_SIZE + length);
222 stream_type.encode(&mut frame);
223 typ.encode(&mut frame);
224 VarInt::try_from(length)
225 .map_err(|_| SettingsError::MessageTooLong)?
226 .encode(&mut frame);
227 frame.extend_from_slice(&payload);
228 return Self::decode(&mut frame.as_slice());
229 }
230 }
231
232 pub fn encode<B: BufMut>(&self, buf: &mut B) {
234 UniStream::CONTROL.encode(buf);
235 Frame::SETTINGS.encode(buf);
236
237 let payload_len = self.payload_len();
238 VarInt::try_from(payload_len as u64)
239 .expect("settings payload length exceeds VarInt bounds")
240 .encode(buf);
241
242 for (id, value) in &self.0 {
243 id.encode(buf);
244 value.encode(buf);
245 }
246 }
247
248 pub async fn write<S: AsyncWrite + Unpin>(&self, stream: &mut S) -> Result<(), SettingsError> {
250 let mut buf = BytesMut::with_capacity(self.encoded_len());
251 self.encode(&mut buf);
252 stream.write_all_buf(&mut buf).await?;
253 Ok(())
254 }
255
256 pub fn enable_webtransport(&mut self, max_sessions: u32) {
258 self.enable_webtransport_internal(max_sessions, true);
259 }
260
261 pub fn enable_webtransport_latest(&mut self, max_sessions: u32) {
263 self.enable_webtransport_internal(max_sessions, false);
264 }
265
266 fn enable_webtransport_internal(&mut self, max_sessions: u32, include_deprecated: bool) {
267 let max = VarInt::from_u32(max_sessions);
268
269 self.insert(Setting::ENABLE_CONNECT_PROTOCOL, VarInt::from_u32(1));
270 self.insert(Setting::ENABLE_DATAGRAM, VarInt::from_u32(1));
271 self.insert(Setting::ENABLE_DATAGRAM_DEPRECATED, VarInt::from_u32(1));
272 self.insert(Setting::WT_ENABLED, VarInt::from_u32(1));
273 self.insert(Setting::WEBTRANSPORT_MAX_SESSIONS, max);
274
275 if include_deprecated {
276 self.insert(Setting::WEBTRANSPORT_MAX_SESSIONS_DEPRECATED, max);
277 self.insert(Setting::WEBTRANSPORT_ENABLE_DEPRECATED, VarInt::from_u32(1));
278 } else {
279 self.0
280 .remove(&Setting::WEBTRANSPORT_MAX_SESSIONS_DEPRECATED);
281 self.0.remove(&Setting::WEBTRANSPORT_ENABLE_DEPRECATED);
282 }
283 }
284
285 pub fn supports_webtransport(&self) -> u64 {
288 let enabled = self
289 .get(&Setting::WT_ENABLED)
290 .map(|value| value.into_inner());
291 if enabled == Some(1)
292 && self.get(&Setting::ENABLE_DATAGRAM).map(|v| v.into_inner()) == Some(1)
293 {
294 return 1;
295 }
296
297 let datagram = self
309 .get(&Setting::ENABLE_DATAGRAM)
310 .or(self.get(&Setting::ENABLE_DATAGRAM_DEPRECATED))
311 .map(|v| v.into_inner());
312
313 if datagram != Some(1) {
314 return 0;
315 }
316
317 if let Some(max) = self.get(&Setting::WEBTRANSPORT_MAX_SESSIONS) {
321 return max.into_inner();
322 }
323
324 let enabled = self
325 .get(&Setting::WEBTRANSPORT_ENABLE_DEPRECATED)
326 .map(|v| v.into_inner());
327 if enabled != Some(1) {
328 return 0;
329 }
330
331 self.get(&Setting::WEBTRANSPORT_MAX_SESSIONS_DEPRECATED)
333 .map(|v| v.into_inner())
334 .unwrap_or(1)
335 }
336
337 pub fn supports_webtransport_server(&self) -> bool {
340 (self.get(&Setting::WT_ENABLED).map(|v| v.into_inner()) == Some(1)
341 && self
342 .get(&Setting::ENABLE_CONNECT_PROTOCOL)
343 .map(|v| v.into_inner())
344 == Some(1)
345 && self.get(&Setting::ENABLE_DATAGRAM).map(|v| v.into_inner()) == Some(1))
346 || (self.supports_webtransport() > 0 && self.get(&Setting::WT_ENABLED).is_none())
347 }
348
349 pub fn supports_webtransport_client(&self) -> bool {
352 (self.get(&Setting::WT_ENABLED).map(|v| v.into_inner()) == Some(1)
353 && self.get(&Setting::ENABLE_DATAGRAM).map(|v| v.into_inner()) == Some(1))
354 || (self.supports_webtransport() > 0 && self.get(&Setting::WT_ENABLED).is_none())
355 }
356
357 fn payload_len(&self) -> usize {
358 self.0
359 .iter()
360 .map(|(id, value)| id.size() + value.size())
361 .sum()
362 }
363
364 fn encoded_len(&self) -> usize {
365 let payload_len = self.payload_len();
366 UniStream::CONTROL.0.size()
367 + Frame::SETTINGS.0.size()
368 + VarInt::try_from(payload_len as u64)
369 .expect("settings payload length exceeds VarInt bounds")
370 .size()
371 + payload_len
372 }
373}
374
375impl Deref for Settings {
376 type Target = HashMap<Setting, VarInt>;
377
378 fn deref(&self) -> &Self::Target {
379 &self.0
380 }
381}
382
383impl DerefMut for Settings {
384 fn deref_mut(&mut self) -> &mut Self::Target {
385 &mut self.0
386 }
387}
388
389#[cfg(test)]
390mod tests {
391 use super::*;
392
393 #[test]
394 fn latest_settings_enable_webtransport() {
395 let mut settings = Settings::default();
396 settings.enable_webtransport_latest(1);
397
398 assert_eq!(settings.supports_webtransport(), 1);
399 assert_eq!(
400 settings.get(&Setting::WT_ENABLED),
401 Some(&VarInt::from_u32(1))
402 );
403 }
404
405 #[test]
406 fn rejects_duplicate_settings() {
407 let mut data = Vec::new();
408 UniStream::CONTROL.encode(&mut data);
409 Frame::SETTINGS.encode(&mut data);
410 VarInt::from_u32(4).encode(&mut data);
411 Setting::ENABLE_DATAGRAM.encode(&mut data);
412 VarInt::from_u32(1).encode(&mut data);
413 Setting::ENABLE_DATAGRAM.encode(&mut data);
414 VarInt::from_u32(1).encode(&mut data);
415
416 let error = Settings::decode(&mut data.as_slice()).unwrap_err();
417 assert!(matches!(
418 error,
419 SettingsError::DuplicateSetting(Setting::ENABLE_DATAGRAM)
420 ));
421 }
422
423 #[test]
424 fn rejects_non_boolean_enabled_value() {
425 let mut data = Vec::new();
426 UniStream::CONTROL.encode(&mut data);
427 Frame::SETTINGS.encode(&mut data);
428 VarInt::from_u32(5).encode(&mut data);
429 Setting::WT_ENABLED.encode(&mut data);
430 VarInt::from_u32(2).encode(&mut data);
431
432 let error = Settings::decode(&mut data.as_slice()).unwrap_err();
433 assert!(matches!(
434 error,
435 SettingsError::InvalidValue(Setting::WT_ENABLED, _)
436 ));
437 }
438
439 #[test]
440 fn server_settings_require_extended_connect() {
441 let mut settings = Settings::default();
442 settings.insert(Setting::WT_ENABLED, VarInt::from_u32(1));
443 settings.insert(Setting::ENABLE_DATAGRAM, VarInt::from_u32(1));
444
445 assert!(settings.supports_webtransport_client());
446 assert!(!settings.supports_webtransport_server());
447
448 settings.insert(Setting::ENABLE_CONNECT_PROTOCOL, VarInt::from_u32(1));
449 assert!(settings.supports_webtransport_server());
450 }
451}