Skip to main content

net_wire/http2/
settings.rs

1use super::error::Http2ParseError;
2use super::frame::Http2Frame;
3use super::layout::{validate_type, validate_zero_stream};
4use super::types::{Http2FrameType, Http2SettingId};
5use core::iter::FusedIterator;
6
7/// A raw-preserving HTTP/2 SETTINGS parameter.
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9pub struct Http2Setting {
10    id: Http2SettingId,
11    value: u32,
12}
13
14impl Http2Setting {
15    /// Creates a setting from a raw-preserving identifier and encoded value.
16    pub const fn new(id: Http2SettingId, value: u32) -> Self {
17        Self { id, value }
18    }
19
20    fn parse(bytes: &[u8]) -> Self {
21        Self {
22            id: Http2SettingId::new(u16::from_be_bytes([bytes[0], bytes[1]])),
23            value: u32::from_be_bytes([bytes[2], bytes[3], bytes[4], bytes[5]]),
24        }
25    }
26
27    pub(super) const fn has_valid_intrinsic_value(self) -> bool {
28        match self.id {
29            Http2SettingId::ENABLE_PUSH | Http2SettingId::ENABLE_CONNECT_PROTOCOL => {
30                self.value <= 1
31            }
32            Http2SettingId::INITIAL_WINDOW_SIZE => self.value <= 0x7fff_ffff,
33            Http2SettingId::MAX_FRAME_SIZE => self.value >= 0x4000 && self.value <= 0x00ff_ffff,
34            _ => true,
35        }
36    }
37
38    /// Returns the raw-preserving setting identifier.
39    pub const fn id(self) -> Http2SettingId {
40        self.id
41    }
42
43    /// Returns the raw encoded setting value.
44    pub const fn value(self) -> u32 {
45        self.value
46    }
47}
48
49/// A validated borrowed HTTP/2 SETTINGS frame.
50#[derive(Clone, Copy, Debug, Eq, PartialEq)]
51pub struct Http2Settings<'a> {
52    frame: Http2Frame<'a>,
53}
54
55impl<'a> Http2Settings<'a> {
56    pub(super) fn from_validated(frame: Http2Frame<'a>) -> Self {
57        Self { frame }
58    }
59
60    /// Parses the first complete SETTINGS frame, enforcing the caller-provided payload maximum.
61    pub fn parse(bytes: &'a [u8], maximum_payload: usize) -> Result<Self, Http2ParseError> {
62        Self::from_frame(Http2Frame::parse(bytes, maximum_payload)?)
63    }
64
65    /// Validates a raw SETTINGS frame's intrinsic layout.
66    pub fn from_frame(frame: Http2Frame<'a>) -> Result<Self, Http2ParseError> {
67        validate_type(frame, Http2FrameType::SETTINGS)?;
68        validate_zero_stream(frame)?;
69        let actual = frame.payload().len();
70        if frame.flags() & 0x1 != 0 && actual != 0 {
71            return Err(Http2ParseError::SettingsAckPayload { actual });
72        }
73        if !actual.is_multiple_of(6) {
74            return Err(Http2ParseError::SettingsPayloadLength { actual });
75        }
76        for bytes in frame.payload().chunks_exact(6) {
77            let setting = Http2Setting::parse(bytes);
78            if !setting.has_valid_intrinsic_value() {
79                return Err(Http2ParseError::InvalidSettingValue {
80                    id: setting.id(),
81                    value: setting.value(),
82                });
83            }
84        }
85        Ok(Self { frame })
86    }
87
88    /// Returns the validated raw frame.
89    pub const fn frame(&self) -> Http2Frame<'a> {
90        self.frame
91    }
92
93    /// Returns the exact represented frame bytes.
94    pub fn as_bytes(&self) -> &'a [u8] {
95        self.frame.as_bytes()
96    }
97
98    /// Returns whether the ACK flag is set.
99    pub fn is_ack(&self) -> bool {
100        self.frame.flags() & 0x1 != 0
101    }
102
103    /// Iterates SETTINGS parameters in wire order without combining duplicates.
104    pub fn settings(&self) -> Http2SettingsIter<'a> {
105        Http2SettingsIter {
106            bytes: self.frame.payload(),
107        }
108    }
109}
110
111/// Iterator over validated HTTP/2 SETTINGS parameters.
112#[derive(Clone, Debug)]
113pub struct Http2SettingsIter<'a> {
114    bytes: &'a [u8],
115}
116
117impl<'a> Iterator for Http2SettingsIter<'a> {
118    type Item = Http2Setting;
119
120    fn next(&mut self) -> Option<Self::Item> {
121        let (setting, remaining) = self.bytes.split_first_chunk::<6>()?;
122        self.bytes = remaining;
123        Some(Http2Setting::parse(setting))
124    }
125}
126
127impl FusedIterator for Http2SettingsIter<'_> {}