1 use std::fmt;
2 
3 use crate::frame::{util, Error, Frame, FrameSize, Head, Kind, StreamId};
4 use bytes::{BufMut, BytesMut};
5 
6 #[derive(Clone, Default, Eq, PartialEq)]
7 pub struct Settings {
8     flags: SettingsFlags,
9     // Fields
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 }
18 
19 /// An enum that lists all valid settings that can be sent in a SETTINGS
20 /// frame.
21 ///
22 /// Each setting has a value that is a 32 bit unsigned integer (6.5.1.).
23 #[derive(Debug)]
24 pub enum Setting {
25     HeaderTableSize(u32),
26     EnablePush(u32),
27     MaxConcurrentStreams(u32),
28     InitialWindowSize(u32),
29     MaxFrameSize(u32),
30     MaxHeaderListSize(u32),
31     EnableConnectProtocol(u32),
32 }
33 
34 #[derive(Copy, Clone, Eq, PartialEq, Default)]
35 pub struct SettingsFlags(u8);
36 
37 const ACK: u8 = 0x1;
38 const ALL: u8 = ACK;
39 
40 /// The default value of SETTINGS_HEADER_TABLE_SIZE
41 pub const DEFAULT_SETTINGS_HEADER_TABLE_SIZE: usize = 4_096;
42 
43 /// The default value of SETTINGS_INITIAL_WINDOW_SIZE
44 pub const DEFAULT_INITIAL_WINDOW_SIZE: u32 = 65_535;
45 
46 /// The default value of MAX_FRAME_SIZE
47 pub const DEFAULT_MAX_FRAME_SIZE: FrameSize = 16_384;
48 
49 /// INITIAL_WINDOW_SIZE upper bound
50 pub const MAX_INITIAL_WINDOW_SIZE: usize = (1 << 31) - 1;
51 
52 /// MAX_FRAME_SIZE upper bound
53 pub const MAX_MAX_FRAME_SIZE: FrameSize = (1 << 24) - 1;
54 
55 // ===== impl Settings =====
56 
57 impl Settings {
ack() -> Settings58     pub fn ack() -> Settings {
59         Settings {
60             flags: SettingsFlags::ack(),
61             ..Settings::default()
62         }
63     }
64 
is_ack(&self) -> bool65     pub fn is_ack(&self) -> bool {
66         self.flags.is_ack()
67     }
68 
initial_window_size(&self) -> Option<u32>69     pub fn initial_window_size(&self) -> Option<u32> {
70         self.initial_window_size
71     }
72 
set_initial_window_size(&mut self, size: Option<u32>)73     pub fn set_initial_window_size(&mut self, size: Option<u32>) {
74         self.initial_window_size = size;
75     }
76 
max_concurrent_streams(&self) -> Option<u32>77     pub fn max_concurrent_streams(&self) -> Option<u32> {
78         self.max_concurrent_streams
79     }
80 
set_max_concurrent_streams(&mut self, max: Option<u32>)81     pub fn set_max_concurrent_streams(&mut self, max: Option<u32>) {
82         self.max_concurrent_streams = max;
83     }
84 
max_frame_size(&self) -> Option<u32>85     pub fn max_frame_size(&self) -> Option<u32> {
86         self.max_frame_size
87     }
88 
set_max_frame_size(&mut self, size: Option<u32>)89     pub fn set_max_frame_size(&mut self, size: Option<u32>) {
90         if let Some(val) = size {
91             assert!(DEFAULT_MAX_FRAME_SIZE <= val && val <= MAX_MAX_FRAME_SIZE);
92         }
93         self.max_frame_size = size;
94     }
95 
max_header_list_size(&self) -> Option<u32>96     pub fn max_header_list_size(&self) -> Option<u32> {
97         self.max_header_list_size
98     }
99 
set_max_header_list_size(&mut self, size: Option<u32>)100     pub fn set_max_header_list_size(&mut self, size: Option<u32>) {
101         self.max_header_list_size = size;
102     }
103 
is_push_enabled(&self) -> Option<bool>104     pub fn is_push_enabled(&self) -> Option<bool> {
105         self.enable_push.map(|val| val != 0)
106     }
107 
set_enable_push(&mut self, enable: bool)108     pub fn set_enable_push(&mut self, enable: bool) {
109         self.enable_push = Some(enable as u32);
110     }
111 
is_extended_connect_protocol_enabled(&self) -> Option<bool>112     pub fn is_extended_connect_protocol_enabled(&self) -> Option<bool> {
113         self.enable_connect_protocol.map(|val| val != 0)
114     }
115 
set_enable_connect_protocol(&mut self, val: Option<u32>)116     pub fn set_enable_connect_protocol(&mut self, val: Option<u32>) {
117         self.enable_connect_protocol = val;
118     }
119 
header_table_size(&self) -> Option<u32>120     pub fn header_table_size(&self) -> Option<u32> {
121         self.header_table_size
122     }
123 
set_header_table_size(&mut self, size: Option<u32>)124     pub fn set_header_table_size(&mut self, size: Option<u32>) {
125         self.header_table_size = size;
126     }
127 
load(head: Head, payload: &[u8]) -> Result<Settings, Error>128     pub fn load(head: Head, payload: &[u8]) -> Result<Settings, Error> {
129         use self::Setting::*;
130 
131         debug_assert_eq!(head.kind(), crate::frame::Kind::Settings);
132 
133         if !head.stream_id().is_zero() {
134             return Err(Error::InvalidStreamId);
135         }
136 
137         // Load the flag
138         let flag = SettingsFlags::load(head.flag());
139 
140         if flag.is_ack() {
141             // Ensure that the payload is empty
142             if !payload.is_empty() {
143                 return Err(Error::InvalidPayloadLength);
144             }
145 
146             // Return the ACK frame
147             return Ok(Settings::ack());
148         }
149 
150         // Ensure the payload length is correct, each setting is 6 bytes long.
151         if payload.len() % 6 != 0 {
152             tracing::debug!("invalid settings payload length; len={:?}", payload.len());
153             return Err(Error::InvalidPayloadAckSettings);
154         }
155 
156         let mut settings = Settings::default();
157         debug_assert!(!settings.flags.is_ack());
158 
159         for raw in payload.chunks(6) {
160             match Setting::load(raw) {
161                 Some(HeaderTableSize(val)) => {
162                     settings.header_table_size = Some(val);
163                 }
164                 Some(EnablePush(val)) => match val {
165                     0 | 1 => {
166                         settings.enable_push = Some(val);
167                     }
168                     _ => {
169                         return Err(Error::InvalidSettingValue);
170                     }
171                 },
172                 Some(MaxConcurrentStreams(val)) => {
173                     settings.max_concurrent_streams = Some(val);
174                 }
175                 Some(InitialWindowSize(val)) => {
176                     if val as usize > MAX_INITIAL_WINDOW_SIZE {
177                         return Err(Error::InvalidSettingValue);
178                     } else {
179                         settings.initial_window_size = Some(val);
180                     }
181                 }
182                 Some(MaxFrameSize(val)) => {
183                     if DEFAULT_MAX_FRAME_SIZE <= val && val <= MAX_MAX_FRAME_SIZE {
184                         settings.max_frame_size = Some(val);
185                     } else {
186                         return Err(Error::InvalidSettingValue);
187                     }
188                 }
189                 Some(MaxHeaderListSize(val)) => {
190                     settings.max_header_list_size = Some(val);
191                 }
192                 Some(EnableConnectProtocol(val)) => match val {
193                     0 | 1 => {
194                         settings.enable_connect_protocol = Some(val);
195                     }
196                     _ => {
197                         return Err(Error::InvalidSettingValue);
198                     }
199                 },
200                 None => {}
201             }
202         }
203 
204         Ok(settings)
205     }
206 
payload_len(&self) -> usize207     fn payload_len(&self) -> usize {
208         let mut len = 0;
209         self.for_each(|_| len += 6);
210         len
211     }
212 
encode(&self, dst: &mut BytesMut)213     pub fn encode(&self, dst: &mut BytesMut) {
214         // Create & encode an appropriate frame head
215         let head = Head::new(Kind::Settings, self.flags.into(), StreamId::zero());
216         let payload_len = self.payload_len();
217 
218         tracing::trace!("encoding SETTINGS; len={}", payload_len);
219 
220         head.encode(payload_len, dst);
221 
222         // Encode the settings
223         self.for_each(|setting| {
224             tracing::trace!("encoding setting; val={:?}", setting);
225             setting.encode(dst)
226         });
227     }
228 
for_each<F: FnMut(Setting)>(&self, mut f: F)229     fn for_each<F: FnMut(Setting)>(&self, mut f: F) {
230         use self::Setting::*;
231 
232         if let Some(v) = self.header_table_size {
233             f(HeaderTableSize(v));
234         }
235 
236         if let Some(v) = self.enable_push {
237             f(EnablePush(v));
238         }
239 
240         if let Some(v) = self.max_concurrent_streams {
241             f(MaxConcurrentStreams(v));
242         }
243 
244         if let Some(v) = self.initial_window_size {
245             f(InitialWindowSize(v));
246         }
247 
248         if let Some(v) = self.max_frame_size {
249             f(MaxFrameSize(v));
250         }
251 
252         if let Some(v) = self.max_header_list_size {
253             f(MaxHeaderListSize(v));
254         }
255 
256         if let Some(v) = self.enable_connect_protocol {
257             f(EnableConnectProtocol(v));
258         }
259     }
260 }
261 
262 impl<T> From<Settings> for Frame<T> {
from(src: Settings) -> Frame<T>263     fn from(src: Settings) -> Frame<T> {
264         Frame::Settings(src)
265     }
266 }
267 
268 impl fmt::Debug for Settings {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result269     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
270         let mut builder = f.debug_struct("Settings");
271         builder.field("flags", &self.flags);
272 
273         self.for_each(|setting| match setting {
274             Setting::EnablePush(v) => {
275                 builder.field("enable_push", &v);
276             }
277             Setting::HeaderTableSize(v) => {
278                 builder.field("header_table_size", &v);
279             }
280             Setting::InitialWindowSize(v) => {
281                 builder.field("initial_window_size", &v);
282             }
283             Setting::MaxConcurrentStreams(v) => {
284                 builder.field("max_concurrent_streams", &v);
285             }
286             Setting::MaxFrameSize(v) => {
287                 builder.field("max_frame_size", &v);
288             }
289             Setting::MaxHeaderListSize(v) => {
290                 builder.field("max_header_list_size", &v);
291             }
292             Setting::EnableConnectProtocol(v) => {
293                 builder.field("enable_connect_protocol", &v);
294             }
295         });
296 
297         builder.finish()
298     }
299 }
300 
301 // ===== impl Setting =====
302 
303 impl Setting {
304     /// Creates a new `Setting` with the correct variant corresponding to the
305     /// given setting id, based on the settings IDs defined in section
306     /// 6.5.2.
from_id(id: u16, val: u32) -> Option<Setting>307     pub fn from_id(id: u16, val: u32) -> Option<Setting> {
308         use self::Setting::*;
309 
310         match id {
311             1 => Some(HeaderTableSize(val)),
312             2 => Some(EnablePush(val)),
313             3 => Some(MaxConcurrentStreams(val)),
314             4 => Some(InitialWindowSize(val)),
315             5 => Some(MaxFrameSize(val)),
316             6 => Some(MaxHeaderListSize(val)),
317             8 => Some(EnableConnectProtocol(val)),
318             _ => None,
319         }
320     }
321 
322     /// Creates a new `Setting` by parsing the given buffer of 6 bytes, which
323     /// contains the raw byte representation of the setting, according to the
324     /// "SETTINGS format" defined in section 6.5.1.
325     ///
326     /// The `raw` parameter should have length at least 6 bytes, since the
327     /// length of the raw setting is exactly 6 bytes.
328     ///
329     /// # Panics
330     ///
331     /// If given a buffer shorter than 6 bytes, the function will panic.
load(raw: &[u8]) -> Option<Setting>332     fn load(raw: &[u8]) -> Option<Setting> {
333         let id: u16 = (u16::from(raw[0]) << 8) | u16::from(raw[1]);
334         let val: u32 = unpack_octets_4!(raw, 2, u32);
335 
336         Setting::from_id(id, val)
337     }
338 
encode(&self, dst: &mut BytesMut)339     fn encode(&self, dst: &mut BytesMut) {
340         use self::Setting::*;
341 
342         let (kind, val) = match *self {
343             HeaderTableSize(v) => (1, v),
344             EnablePush(v) => (2, v),
345             MaxConcurrentStreams(v) => (3, v),
346             InitialWindowSize(v) => (4, v),
347             MaxFrameSize(v) => (5, v),
348             MaxHeaderListSize(v) => (6, v),
349             EnableConnectProtocol(v) => (8, v),
350         };
351 
352         dst.put_u16(kind);
353         dst.put_u32(val);
354     }
355 }
356 
357 // ===== impl SettingsFlags =====
358 
359 impl SettingsFlags {
empty() -> SettingsFlags360     pub fn empty() -> SettingsFlags {
361         SettingsFlags(0)
362     }
363 
load(bits: u8) -> SettingsFlags364     pub fn load(bits: u8) -> SettingsFlags {
365         SettingsFlags(bits & ALL)
366     }
367 
ack() -> SettingsFlags368     pub fn ack() -> SettingsFlags {
369         SettingsFlags(ACK)
370     }
371 
is_ack(&self) -> bool372     pub fn is_ack(&self) -> bool {
373         self.0 & ACK == ACK
374     }
375 }
376 
377 impl From<SettingsFlags> for u8 {
from(src: SettingsFlags) -> u8378     fn from(src: SettingsFlags) -> u8 {
379         src.0
380     }
381 }
382 
383 impl fmt::Debug for SettingsFlags {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result384     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
385         util::debug_flags(f, self.0)
386             .flag_if(self.is_ack(), "ACK")
387             .finish()
388     }
389 }
390