1use std::fmt;
2
3use crate::frame::{util, Error, Frame, FrameSize, Head, Kind, StreamId};
4use bytes::{BufMut, BytesMut};
5use smallvec::SmallVec;
6
7#[derive(Clone, Default, Eq, PartialEq)]
8pub struct Settings {
9 flags: SettingsFlags,
10 header_table_size: Option<u32>,
11 enable_push: Option<u32>,
12 max_concurrent_streams: Option<u32>,
13 initial_window_size: Option<u32>,
14 max_frame_size: Option<u32>,
15 max_header_list_size: Option<u32>,
16 enable_connect_protocol: Option<u32>,
17 no_rfc7540_priorities: Option<u32>,
18 settings_order: SettingsOrder,
19}
20
21#[derive(Debug, Clone, Eq, PartialEq)]
26pub enum Setting {
27 HeaderTableSize(u32),
28 EnablePush(u32),
29 MaxConcurrentStreams(u32),
30 InitialWindowSize(u32),
31 MaxFrameSize(u32),
32 MaxHeaderListSize(u32),
33 EnableConnectProtocol(u32),
34 NoRfc7540Priorities(u32),
35}
36
37define_enum_with_values! {
38 @U16
45 pub enum SettingId {
46 HeaderTableSize => 0x0001,
52
53 EnablePush => 0x0002,
55
56 MaxConcurrentStreams => 0x0003,
58
59 InitialWindowSize => 0x0004,
61
62 MaxFrameSize => 0x0005,
64
65 MaxHeaderListSize => 0x0006,
67
68 EnableConnectProtocol => 0x0008,
70
71 NoRfc7540Priorities => 0x0009,
73 }
74}
75
76#[derive(Clone, Debug, PartialEq, Eq)]
86pub struct SettingsOrder {
87 ids: SmallVec<[SettingId; SettingId::DEFAULT_STACK_SIZE]>,
88}
89
90#[derive(Debug)]
97pub struct SettingsOrderBuilder {
98 ids: SmallVec<[SettingId; SettingId::DEFAULT_STACK_SIZE]>,
99 mask: u16,
100}
101
102impl SettingsOrder {
105 pub fn builder() -> SettingsOrderBuilder {
106 SettingsOrderBuilder {
107 ids: SmallVec::new(),
108 mask: 0,
109 }
110 }
111}
112
113impl Default for SettingsOrder {
114 fn default() -> Self {
115 SettingsOrder {
116 ids: SmallVec::from(SettingId::DEFAULT_IDS),
117 }
118 }
119}
120
121impl<'a> IntoIterator for &'a SettingsOrder {
122 type Item = &'a SettingId;
123 type IntoIter = std::slice::Iter<'a, SettingId>;
124
125 fn into_iter(self) -> Self::IntoIter {
126 self.ids.iter()
127 }
128}
129
130impl SettingsOrderBuilder {
133 pub fn push(mut self, id: SettingId) -> Self {
134 let mask_id = id.mask_id();
135 if mask_id != 0 {
136 if self.mask & mask_id == 0 {
137 self.mask |= mask_id;
138 self.ids.push(id);
139 } else {
140 tracing::trace!("duplicate setting ID ignored: {id:?}");
141 }
142 }
143 self
144 }
145
146 pub fn extend(mut self, iter: impl IntoIterator<Item = SettingId>) -> Self {
147 for id in iter {
148 self = self.push(id);
149 }
150 self
151 }
152
153 pub fn build(mut self) -> SettingsOrder {
154 if self.ids.len() != SettingId::DEFAULT_IDS.len() {
155 self = self.extend(SettingId::DEFAULT_IDS);
156 }
157 SettingsOrder { ids: self.ids }
158 }
159
160 pub fn build_without_extend(self) -> SettingsOrder {
166 SettingsOrder { ids: self.ids }
167 }
168}
169
170#[derive(Copy, Clone, Eq, PartialEq, Default)]
171pub struct SettingsFlags(u8);
172
173const ACK: u8 = 0x1;
174const ALL: u8 = ACK;
175
176pub const DEFAULT_SETTINGS_HEADER_TABLE_SIZE: usize = 4_096;
178
179pub const DEFAULT_INITIAL_WINDOW_SIZE: u32 = 65_535;
181
182pub const DEFAULT_MAX_FRAME_SIZE: FrameSize = 16_384;
184
185pub const MAX_INITIAL_WINDOW_SIZE: usize = (1 << 31) - 1;
187
188pub const MAX_MAX_FRAME_SIZE: FrameSize = (1 << 24) - 1;
190
191impl Settings {
194 pub fn ack() -> Settings {
195 Settings {
196 flags: SettingsFlags::ack(),
197 ..Settings::default()
198 }
199 }
200
201 pub fn is_ack(&self) -> bool {
202 self.flags.is_ack()
203 }
204
205 pub fn initial_window_size(&self) -> Option<u32> {
206 self.initial_window_size
207 }
208
209 pub fn set_initial_window_size(&mut self, size: Option<u32>) {
210 self.initial_window_size = size;
211 }
212
213 pub fn max_concurrent_streams(&self) -> Option<u32> {
214 self.max_concurrent_streams
215 }
216
217 pub fn set_max_concurrent_streams(&mut self, max: Option<u32>) {
218 self.max_concurrent_streams = max;
219 }
220
221 pub fn max_frame_size(&self) -> Option<u32> {
222 self.max_frame_size
223 }
224
225 pub fn set_max_frame_size(&mut self, size: Option<u32>) {
226 if let Some(val) = size {
227 assert!(DEFAULT_MAX_FRAME_SIZE <= val && val <= MAX_MAX_FRAME_SIZE);
228 }
229 self.max_frame_size = size;
230 }
231
232 pub fn max_header_list_size(&self) -> Option<u32> {
233 self.max_header_list_size
234 }
235
236 pub fn set_max_header_list_size(&mut self, size: Option<u32>) {
237 self.max_header_list_size = size;
238 }
239
240 pub fn is_push_enabled(&self) -> Option<bool> {
241 self.enable_push.map(|val| val != 0)
242 }
243
244 pub fn set_enable_push(&mut self, enable: bool) {
245 self.enable_push = Some(enable as u32);
246 }
247
248 pub fn is_extended_connect_protocol_enabled(&self) -> Option<bool> {
249 self.enable_connect_protocol.map(|val| val != 0)
250 }
251
252 pub fn set_enable_connect_protocol(&mut self, val: Option<u32>) {
253 self.enable_connect_protocol = val;
254 }
255
256 pub fn no_rfc7540_priorities(&self) -> Option<u32> {
257 self.no_rfc7540_priorities
258 }
259
260 pub fn set_no_rfc7540_priorities(&mut self, val: Option<u32>) {
261 self.no_rfc7540_priorities = val;
262 }
263
264 pub fn header_table_size(&self) -> Option<u32> {
265 self.header_table_size
266 }
267
268 pub fn set_header_table_size(&mut self, size: Option<u32>) {
269 self.header_table_size = size;
270 }
271
272 pub fn load(head: Head, payload: &[u8]) -> Result<Settings, Error> {
273 use self::Setting::*;
274
275 debug_assert_eq!(head.kind(), crate::frame::Kind::Settings);
276
277 if !head.stream_id().is_zero() {
278 return Err(Error::InvalidStreamId);
279 }
280
281 let flag = SettingsFlags::load(head.flag());
283
284 if flag.is_ack() {
285 if !payload.is_empty() {
287 return Err(Error::InvalidPayloadLength);
288 }
289
290 return Ok(Settings::ack());
292 }
293
294 if !payload.len().is_multiple_of(6) {
296 tracing::debug!("invalid settings payload length; len={:?}", payload.len());
297 return Err(Error::InvalidPayloadAckSettings);
298 }
299
300 let mut settings = Settings::default();
301 debug_assert!(!settings.flags.is_ack());
302
303 for raw in payload.chunks(6) {
304 match Setting::load(raw) {
305 Some(HeaderTableSize(val)) => {
306 settings.header_table_size = Some(val);
307 }
308 Some(EnablePush(val)) => match val {
309 0 | 1 => {
310 settings.enable_push = Some(val);
311 }
312 _ => {
313 return Err(Error::InvalidSettingValue);
314 }
315 },
316 Some(MaxConcurrentStreams(val)) => {
317 settings.max_concurrent_streams = Some(val);
318 }
319 Some(InitialWindowSize(val)) => {
320 if val as usize > MAX_INITIAL_WINDOW_SIZE {
321 return Err(Error::InvalidSettingValue);
322 } else {
323 settings.initial_window_size = Some(val);
324 }
325 }
326 Some(MaxFrameSize(val)) => {
327 if DEFAULT_MAX_FRAME_SIZE <= val && val <= MAX_MAX_FRAME_SIZE {
328 settings.max_frame_size = Some(val);
329 } else {
330 return Err(Error::InvalidSettingValue);
331 }
332 }
333 Some(MaxHeaderListSize(val)) => {
334 settings.max_header_list_size = Some(val);
335 }
336 Some(EnableConnectProtocol(val)) => match val {
337 0 | 1 => {
338 settings.enable_connect_protocol = Some(val);
339 }
340 _ => {
341 return Err(Error::InvalidSettingValue);
342 }
343 },
344 Some(NoRfc7540Priorities(val)) => {
345 settings.no_rfc7540_priorities = Some(val);
346 }
347 None => {}
348 }
349 }
350
351 Ok(settings)
352 }
353
354 fn payload_len(&self) -> usize {
355 let mut len = 0;
356 self.for_each(|_| len += 6);
357 len
358 }
359
360 pub fn set_settings_order(&mut self, settings_order: SettingsOrder) {
361 self.settings_order = settings_order;
362 }
363
364 pub fn encode(&self, dst: &mut BytesMut) {
365 let head = Head::new(Kind::Settings, self.flags.into(), StreamId::zero());
367 let payload_len = self.payload_len();
368
369 tracing::debug!(
370 "encoding SETTINGS; len={}, order={:?}, header_table_size={:?}, enable_push={:?}, initial_window_size={:?}, max_frame_size={:?}, max_header_list_size={:?}",
371 payload_len,
372 self.settings_order,
373 self.header_table_size,
374 self.enable_push,
375 self.initial_window_size,
376 self.max_frame_size,
377 self.max_header_list_size,
378 );
379
380 head.encode(payload_len, dst);
381
382 self.for_each(|setting| {
384 tracing::debug!("encoding setting; val={:?}", setting);
385 setting.encode(dst)
386 });
387 }
388
389 fn for_each<F: FnMut(Setting)>(&self, mut f: F) {
390 use self::Setting::*;
391
392 for id in &self.settings_order {
393 match id {
394 SettingId::HeaderTableSize => {
395 if let Some(v) = self.header_table_size {
396 f(HeaderTableSize(v));
397 }
398 }
399 SettingId::EnablePush => {
400 if let Some(v) = self.enable_push {
401 f(EnablePush(v));
402 }
403 }
404 SettingId::MaxConcurrentStreams => {
405 if let Some(v) = self.max_concurrent_streams {
406 f(MaxConcurrentStreams(v));
407 }
408 }
409 SettingId::InitialWindowSize => {
410 if let Some(v) = self.initial_window_size {
411 f(InitialWindowSize(v));
412 }
413 }
414 SettingId::MaxFrameSize => {
415 if let Some(v) = self.max_frame_size {
416 f(MaxFrameSize(v));
417 }
418 }
419 SettingId::MaxHeaderListSize => {
420 if let Some(v) = self.max_header_list_size {
421 f(MaxHeaderListSize(v));
422 }
423 }
424 SettingId::EnableConnectProtocol => {
425 if let Some(v) = self.enable_connect_protocol {
426 f(EnableConnectProtocol(v));
427 }
428 }
429 SettingId::NoRfc7540Priorities => {
430 if let Some(v) = self.no_rfc7540_priorities {
431 f(NoRfc7540Priorities(v));
432 }
433 }
434 }
435 }
436 }
437}
438
439impl<T> From<Settings> for Frame<T> {
440 fn from(src: Settings) -> Frame<T> {
441 Frame::Settings(src)
442 }
443}
444
445impl fmt::Debug for Settings {
446 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
447 let mut builder = f.debug_struct("Settings");
448 builder.field("flags", &self.flags);
449
450 self.for_each(|setting| match setting {
451 Setting::EnablePush(v) => {
452 builder.field("enable_push", &v);
453 }
454 Setting::HeaderTableSize(v) => {
455 builder.field("header_table_size", &v);
456 }
457 Setting::InitialWindowSize(v) => {
458 builder.field("initial_window_size", &v);
459 }
460 Setting::MaxConcurrentStreams(v) => {
461 builder.field("max_concurrent_streams", &v);
462 }
463 Setting::MaxFrameSize(v) => {
464 builder.field("max_frame_size", &v);
465 }
466 Setting::MaxHeaderListSize(v) => {
467 builder.field("max_header_list_size", &v);
468 }
469 Setting::EnableConnectProtocol(v) => {
470 builder.field("enable_connect_protocol", &v);
471 }
472 Setting::NoRfc7540Priorities(v) => {
473 builder.field("no_rfc7540_priorities", &v);
474 }
475 });
476
477 builder.finish()
478 }
479}
480
481impl Setting {
484 pub fn id(&self) -> u16 {
486 match *self {
487 Setting::HeaderTableSize(_) => 1,
488 Setting::EnablePush(_) => 2,
489 Setting::MaxConcurrentStreams(_) => 3,
490 Setting::InitialWindowSize(_) => 4,
491 Setting::MaxFrameSize(_) => 5,
492 Setting::MaxHeaderListSize(_) => 6,
493 Setting::EnableConnectProtocol(_) => 8,
494 Setting::NoRfc7540Priorities(_) => 9,
495 }
496 }
497
498 pub fn from_id(id: u16, val: u32) -> Option<Setting> {
502 use self::Setting::*;
503
504 match id {
505 1 => Some(HeaderTableSize(val)),
506 2 => Some(EnablePush(val)),
507 3 => Some(MaxConcurrentStreams(val)),
508 4 => Some(InitialWindowSize(val)),
509 5 => Some(MaxFrameSize(val)),
510 6 => Some(MaxHeaderListSize(val)),
511 8 => Some(EnableConnectProtocol(val)),
512 9 => Some(NoRfc7540Priorities(val)),
513 _ => None,
514 }
515 }
516
517 fn load(raw: &[u8]) -> Option<Setting> {
528 let id: u16 = (u16::from(raw[0]) << 8) | u16::from(raw[1]);
529 let val: u32 = unpack_octets_4!(raw, 2, u32);
530
531 Setting::from_id(id, val)
532 }
533
534 fn encode(&self, dst: &mut BytesMut) {
535 use self::Setting::*;
536
537 let (kind, val) = match *self {
538 HeaderTableSize(v) => (1, v),
539 EnablePush(v) => (2, v),
540 MaxConcurrentStreams(v) => (3, v),
541 InitialWindowSize(v) => (4, v),
542 MaxFrameSize(v) => (5, v),
543 MaxHeaderListSize(v) => (6, v),
544 EnableConnectProtocol(v) => (8, v),
545 NoRfc7540Priorities(v) => (9, v),
546 };
547
548 dst.put_u16(kind);
549 dst.put_u32(val);
550 }
551}
552
553impl SettingsFlags {
556 pub fn empty() -> SettingsFlags {
557 SettingsFlags(0)
558 }
559
560 pub fn load(bits: u8) -> SettingsFlags {
561 SettingsFlags(bits & ALL)
562 }
563
564 pub fn ack() -> SettingsFlags {
565 SettingsFlags(ACK)
566 }
567
568 pub fn is_ack(&self) -> bool {
569 self.0 & ACK == ACK
570 }
571}
572
573impl From<SettingsFlags> for u8 {
574 fn from(src: SettingsFlags) -> u8 {
575 src.0
576 }
577}
578
579impl fmt::Debug for SettingsFlags {
580 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
581 util::debug_flags(f, self.0)
582 .flag_if(self.is_ack(), "ACK")
583 .finish()
584 }
585}