webtrans_proto/
settings.rs1use 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, AsyncWrite, AsyncWriteExt};
14
15use super::{Frame, UniStream, VarInt, VarIntUnexpectedEnd};
16use crate::grease::is_grease_value;
17use crate::io::read_incremental;
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 x if x.is_grease() => write!(f, "GREASE SETTING [{:x?}]", x.0.into_inner()),
61 x => write!(f, "UNKNOWN_SETTING [{:x?}]", x.0.into_inner()),
62 }
63 }
64}
65
66impl Setting {
67 pub const fn from_u32(value: u32) -> Self {
69 Self(VarInt::from_u32(value))
70 }
71
72 pub const QPACK_MAX_TABLE_CAPACITY: Setting = Setting::from_u32(0x1); pub const MAX_FIELD_SECTION_SIZE: Setting = Setting::from_u32(0x6);
77 pub const QPACK_BLOCKED_STREAMS: Setting = Setting::from_u32(0x7);
79
80 pub const ENABLE_CONNECT_PROTOCOL: Setting = Setting::from_u32(0x8);
83 pub const ENABLE_DATAGRAM: Setting = Setting::from_u32(0x33);
85 pub const ENABLE_DATAGRAM_DEPRECATED: Setting = Setting::from_u32(0xFFD277); pub const WEBTRANSPORT_ENABLE_DEPRECATED: Setting = Setting::from_u32(0x2b603742);
91 pub const WEBTRANSPORT_MAX_SESSIONS_DEPRECATED: Setting = Setting::from_u32(0x2b603743);
93
94 pub const WEBTRANSPORT_MAX_SESSIONS: Setting = Setting::from_u32(0xc671706a);
97}
98
99#[derive(Error, Debug, Clone)]
100pub enum SettingsError {
102 #[error("unexpected end of input")]
104 UnexpectedEnd,
105
106 #[error("unexpected stream type {0:?}")]
108 UnexpectedStreamType(UniStream),
109
110 #[error("unexpected frame {0:?}")]
112 UnexpectedFrame(Frame),
113
114 #[error("invalid size")]
116 InvalidSize,
117
118 #[error("io error: {0}")]
120 Io(Arc<std::io::Error>),
121}
122
123impl From<std::io::Error> for SettingsError {
124 fn from(err: std::io::Error) -> Self {
125 SettingsError::Io(Arc::new(err))
126 }
127}
128
129#[derive(Default, Debug)]
131pub struct Settings(HashMap<Setting, VarInt>);
133
134impl Settings {
135 pub fn decode<B: Buf>(buf: &mut B) -> Result<Self, SettingsError> {
137 let typ = UniStream::decode(buf).map_err(|_| SettingsError::UnexpectedEnd)?;
138 if typ != UniStream::CONTROL {
139 return Err(SettingsError::UnexpectedStreamType(typ));
140 }
141
142 let (typ, mut data) = Frame::read(buf).map_err(|_| SettingsError::UnexpectedEnd)?;
143 if typ != Frame::SETTINGS {
144 return Err(SettingsError::UnexpectedFrame(typ));
145 }
146
147 let mut settings = Settings::default();
148 while data.has_remaining() {
149 let id = Setting::decode(&mut data).map_err(|_| SettingsError::InvalidSize)?;
151 let value = VarInt::decode(&mut data).map_err(|_| SettingsError::InvalidSize)?;
152 if !id.is_grease() {
154 settings.0.insert(id, value);
155 }
156 }
157
158 Ok(settings)
159 }
160
161 pub async fn read<S: AsyncRead + Unpin>(stream: &mut S) -> Result<Self, SettingsError> {
163 read_incremental(
164 stream,
165 |cursor| Self::decode(cursor),
166 |err| matches!(err, SettingsError::UnexpectedEnd),
167 SettingsError::UnexpectedEnd,
168 )
169 .await
170 }
171
172 pub fn encode<B: BufMut>(&self, buf: &mut B) {
174 UniStream::CONTROL.encode(buf);
175 Frame::SETTINGS.encode(buf);
176
177 let payload_len = self.payload_len();
178 VarInt::try_from(payload_len as u64)
179 .expect("settings payload length exceeds VarInt bounds")
180 .encode(buf);
181
182 for (id, value) in &self.0 {
183 id.encode(buf);
184 value.encode(buf);
185 }
186 }
187
188 pub async fn write<S: AsyncWrite + Unpin>(&self, stream: &mut S) -> Result<(), SettingsError> {
190 let mut buf = BytesMut::with_capacity(self.encoded_len());
191 self.encode(&mut buf);
192 stream.write_all_buf(&mut buf).await?;
193 Ok(())
194 }
195
196 pub fn enable_webtransport(&mut self, max_sessions: u32) {
198 self.enable_webtransport_internal(max_sessions, true);
199 }
200
201 pub fn enable_webtransport_latest(&mut self, max_sessions: u32) {
203 self.enable_webtransport_internal(max_sessions, false);
204 }
205
206 fn enable_webtransport_internal(&mut self, max_sessions: u32, include_deprecated: bool) {
207 let max = VarInt::from_u32(max_sessions);
208
209 self.insert(Setting::ENABLE_CONNECT_PROTOCOL, VarInt::from_u32(1));
210 self.insert(Setting::ENABLE_DATAGRAM, VarInt::from_u32(1));
211 self.insert(Setting::ENABLE_DATAGRAM_DEPRECATED, VarInt::from_u32(1));
212 self.insert(Setting::WEBTRANSPORT_MAX_SESSIONS, max);
213
214 if include_deprecated {
215 self.insert(Setting::WEBTRANSPORT_MAX_SESSIONS_DEPRECATED, max);
216 self.insert(Setting::WEBTRANSPORT_ENABLE_DEPRECATED, VarInt::from_u32(1));
217 } else {
218 self.0
219 .remove(&Setting::WEBTRANSPORT_MAX_SESSIONS_DEPRECATED);
220 self.0.remove(&Setting::WEBTRANSPORT_ENABLE_DEPRECATED);
221 }
222 }
223
224 pub fn supports_webtransport(&self) -> u64 {
227 let datagram = self
239 .get(&Setting::ENABLE_DATAGRAM)
240 .or(self.get(&Setting::ENABLE_DATAGRAM_DEPRECATED))
241 .map(|v| v.into_inner());
242
243 if datagram != Some(1) {
244 return 0;
245 }
246
247 if let Some(max) = self.get(&Setting::WEBTRANSPORT_MAX_SESSIONS) {
251 return max.into_inner();
252 }
253
254 let enabled = self
255 .get(&Setting::WEBTRANSPORT_ENABLE_DEPRECATED)
256 .map(|v| v.into_inner());
257 if enabled != Some(1) {
258 return 0;
259 }
260
261 self.get(&Setting::WEBTRANSPORT_MAX_SESSIONS_DEPRECATED)
263 .map(|v| v.into_inner())
264 .unwrap_or(1)
265 }
266
267 fn payload_len(&self) -> usize {
268 self.0
269 .iter()
270 .map(|(id, value)| id.size() + value.size())
271 .sum()
272 }
273
274 fn encoded_len(&self) -> usize {
275 let payload_len = self.payload_len();
276 UniStream::CONTROL.0.size()
277 + Frame::SETTINGS.0.size()
278 + VarInt::try_from(payload_len as u64)
279 .expect("settings payload length exceeds VarInt bounds")
280 .size()
281 + payload_len
282 }
283}
284
285impl Deref for Settings {
286 type Target = HashMap<Setting, VarInt>;
287
288 fn deref(&self) -> &Self::Target {
289 &self.0
290 }
291}
292
293impl DerefMut for Settings {
294 fn deref_mut(&mut self) -> &mut Self::Target {
295 &mut self.0
296 }
297}