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 
124     /*
125     pub fn set_header_table_size(&mut self, size: Option<u32>) {
126         self.header_table_size = size;
127     }
128     */
129 
load(head: Head, payload: &[u8]) -> Result<Settings, Error>130     pub fn load(head: Head, payload: &[u8]) -> Result<Settings, Error> {
131         use self::Setting::*;
132 
133         debug_assert_eq!(head.kind(), crate::frame::Kind::Settings);
134 
135         if !head.stream_id().is_zero() {
136             return Err(Error::InvalidStreamId);
137         }
138 
139         // Load the flag
140         let flag = SettingsFlags::load(head.flag());
141 
142         if flag.is_ack() {
143             // Ensure that the payload is empty
144             if !payload.is_empty() {
145                 return Err(Error::InvalidPayloadLength);
146             }
147 
148             // Return the ACK frame
149             return Ok(Settings::ack());
150         }
151 
152         // Ensure the payload length is correct, each setting is 6 bytes long.
153         if payload.len() % 6 != 0 {
154             tracing::debug!("invalid settings payload length; len={:?}", payload.len());
155             return Err(Error::InvalidPayloadAckSettings);
156         }
157 
158         let mut settings = Settings::default();
159         debug_assert!(!settings.flags.is_ack());
160 
161         for raw in payload.chunks(6) {
162             match Setting::load(raw) {
163                 Some(HeaderTableSize(val)) => {
164                     settings.header_table_size = Some(val);
165                 }
166                 Some(EnablePush(val)) => match val {
167                     0 | 1 => {
168                         settings.enable_push = Some(val);
169                     }
170                     _ => {
171                         return Err(Error::InvalidSettingValue);
172                     }
173                 },
174                 Some(MaxConcurrentStreams(val)) => {
175                     settings.max_concurrent_streams = Some(val);
176                 }
177                 Some(InitialWindowSize(val)) => {
178                     if val as usize > MAX_INITIAL_WINDOW_SIZE {
179                         return Err(Error::InvalidSettingValue);
180                     } else {
181                         settings.initial_window_size = Some(val);
182                     }
183                 }
184                 Some(MaxFrameSize(val)) => {
185                     if val < DEFAULT_MAX_FRAME_SIZE || val > MAX_MAX_FRAME_SIZE {
186                         return Err(Error::InvalidSettingValue);
187                     } else {
188                         settings.max_frame_size = Some(val);
189                     }
190                 }
191                 Some(MaxHeaderListSize(val)) => {
192                     settings.max_header_list_size = Some(val);
193                 }
194                 Some(EnableConnectProtocol(val)) => match val {
195                     0 | 1 => {
196                         settings.enable_connect_protocol = Some(val);
197                     }
198                     _ => {
199                         return Err(Error::InvalidSettingValue);
200                     }
201                 },
202                 None => {}
203             }
204         }
205 
206         Ok(settings)
207     }
208 
payload_len(&self) -> usize209     fn payload_len(&self) -> usize {
210         let mut len = 0;
211         self.for_each(|_| len += 6);
212         len
213     }
214 
encode(&self, dst: &mut BytesMut)215     pub fn encode(&self, dst: &mut BytesMut) {
216         // Create & encode an appropriate frame head
217         let head = Head::new(Kind::Settings, self.flags.into(), StreamId::zero());
218         let payload_len = self.payload_len();
219 
220         tracing::trace!("encoding SETTINGS; len={}", payload_len);
221 
222         head.encode(payload_len, dst);
223 
224         // Encode the settings
225         self.for_each(|setting| {
226             tracing::trace!("encoding setting; val={:?}", setting);
227             setting.encode(dst)
228         });
229     }
230 
for_each<F: FnMut(Setting)>(&self, mut f: F)231     fn for_each<F: FnMut(Setting)>(&self, mut f: F) {
232         use self::Setting::*;
233 
234         if let Some(v) = self.header_table_size {
235             f(HeaderTableSize(v));
236         }
237 
238         if let Some(v) = self.enable_push {
239             f(EnablePush(v));
240         }
241 
242         if let Some(v) = self.max_concurrent_streams {
243             f(MaxConcurrentStreams(v));
244         }
245 
246         if let Some(v) = self.initial_window_size {
247             f(InitialWindowSize(v));
248         }
249 
250         if let Some(v) = self.max_frame_size {
251             f(MaxFrameSize(v));
252         }
253 
254         if let Some(v) = self.max_header_list_size {
255             f(MaxHeaderListSize(v));
256         }
257 
258         if let Some(v) = self.enable_connect_protocol {
259             f(EnableConnectProtocol(v));
260         }
261     }
262 }
263 
264 impl<T> From<Settings> for Frame<T> {
from(src: Settings) -> Frame<T>265     fn from(src: Settings) -> Frame<T> {
266         Frame::Settings(src)
267     }
268 }
269 
270 impl fmt::Debug for Settings {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result271     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
272         let mut builder = f.debug_struct("Settings");
273         builder.field("flags", &self.flags);
274 
275         self.for_each(|setting| match setting {
276             Setting::EnablePush(v) => {
277                 builder.field("enable_push", &v);
278             }
279             Setting::HeaderTableSize(v) => {
280                 builder.field("header_table_size", &v);
281             }
282             Setting::InitialWindowSize(v) => {
283                 builder.field("initial_window_size", &v);
284             }
285             Setting::MaxConcurrentStreams(v) => {
286                 builder.field("max_concurrent_streams", &v);
287             }
288             Setting::MaxFrameSize(v) => {
289                 builder.field("max_frame_size", &v);
290             }
291             Setting::MaxHeaderListSize(v) => {
292                 builder.field("max_header_list_size", &v);
293             }
294             Setting::EnableConnectProtocol(v) => {
295                 builder.field("enable_connect_protocol", &v);
296             }
297         });
298 
299         builder.finish()
300     }
301 }
302 
303 // ===== impl Setting =====
304 
305 impl Setting {
306     /// Creates a new `Setting` with the correct variant corresponding to the
307     /// given setting id, based on the settings IDs defined in section
308     /// 6.5.2.
from_id(id: u16, val: u32) -> Option<Setting>309     pub fn from_id(id: u16, val: u32) -> Option<Setting> {
310         use self::Setting::*;
311 
312         match id {
313             1 => Some(HeaderTableSize(val)),
314             2 => Some(EnablePush(val)),
315             3 => Some(MaxConcurrentStreams(val)),
316             4 => Some(InitialWindowSize(val)),
317             5 => Some(MaxFrameSize(val)),
318             6 => Some(MaxHeaderListSize(val)),
319             8 => Some(EnableConnectProtocol(val)),
320             _ => None,
321         }
322     }
323 
324     /// Creates a new `Setting` by parsing the given buffer of 6 bytes, which
325     /// contains the raw byte representation of the setting, according to the
326     /// "SETTINGS format" defined in section 6.5.1.
327     ///
328     /// The `raw` parameter should have length at least 6 bytes, since the
329     /// length of the raw setting is exactly 6 bytes.
330     ///
331     /// # Panics
332     ///
333     /// If given a buffer shorter than 6 bytes, the function will panic.
load(raw: &[u8]) -> Option<Setting>334     fn load(raw: &[u8]) -> Option<Setting> {
335         let id: u16 = (u16::from(raw[0]) << 8) | u16::from(raw[1]);
336         let val: u32 = unpack_octets_4!(raw, 2, u32);
337 
338         Setting::from_id(id, val)
339     }
340 
encode(&self, dst: &mut BytesMut)341     fn encode(&self, dst: &mut BytesMut) {
342         use self::Setting::*;
343 
344         let (kind, val) = match *self {
345             HeaderTableSize(v) => (1, v),
346             EnablePush(v) => (2, v),
347             MaxConcurrentStreams(v) => (3, v),
348             InitialWindowSize(v) => (4, v),
349             MaxFrameSize(v) => (5, v),
350             MaxHeaderListSize(v) => (6, v),
351             EnableConnectProtocol(v) => (8, v),
352         };
353 
354         dst.put_u16(kind);
355         dst.put_u32(val);
356     }
357 }
358 
359 // ===== impl SettingsFlags =====
360 
361 impl SettingsFlags {
empty() -> SettingsFlags362     pub fn empty() -> SettingsFlags {
363         SettingsFlags(0)
364     }
365 
load(bits: u8) -> SettingsFlags366     pub fn load(bits: u8) -> SettingsFlags {
367         SettingsFlags(bits & ALL)
368     }
369 
ack() -> SettingsFlags370     pub fn ack() -> SettingsFlags {
371         SettingsFlags(ACK)
372     }
373 
is_ack(&self) -> bool374     pub fn is_ack(&self) -> bool {
375         self.0 & ACK == ACK
376     }
377 }
378 
379 impl From<SettingsFlags> for u8 {
from(src: SettingsFlags) -> u8380     fn from(src: SettingsFlags) -> u8 {
381         src.0
382     }
383 }
384 
385 impl fmt::Debug for SettingsFlags {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result386     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
387         util::debug_flags(f, self.0)
388             .flag_if(self.is_ack(), "ACK")
389             .finish()
390     }
391 }
392