1 use bytes::{BufMut, BytesMut}; 2 use frame::{Error, Frame, FrameSize, Head, Kind, StreamId}; 3 4 #[derive(Debug, Clone, Default, Eq, PartialEq)] 5 pub struct Settings { 6 flags: SettingsFlags, 7 // Fields 8 header_table_size: Option<u32>, 9 enable_push: Option<u32>, 10 max_concurrent_streams: Option<u32>, 11 initial_window_size: Option<u32>, 12 max_frame_size: Option<u32>, 13 max_header_list_size: Option<u32>, 14 } 15 16 /// An enum that lists all valid settings that can be sent in a SETTINGS 17 /// frame. 18 /// 19 /// Each setting has a value that is a 32 bit unsigned integer (6.5.1.). 20 #[derive(Debug)] 21 pub enum Setting { 22 HeaderTableSize(u32), 23 EnablePush(u32), 24 MaxConcurrentStreams(u32), 25 InitialWindowSize(u32), 26 MaxFrameSize(u32), 27 MaxHeaderListSize(u32), 28 } 29 30 #[derive(Debug, Copy, Clone, Eq, PartialEq, Default)] 31 pub struct SettingsFlags(u8); 32 33 const ACK: u8 = 0x1; 34 const ALL: u8 = ACK; 35 36 /// The default value of SETTINGS_HEADER_TABLE_SIZE 37 pub const DEFAULT_SETTINGS_HEADER_TABLE_SIZE: usize = 4_096; 38 39 /// The default value of SETTINGS_INITIAL_WINDOW_SIZE 40 pub const DEFAULT_INITIAL_WINDOW_SIZE: u32 = 65_535; 41 42 /// The default value of MAX_FRAME_SIZE 43 pub const DEFAULT_MAX_FRAME_SIZE: FrameSize = 16_384; 44 45 /// INITIAL_WINDOW_SIZE upper bound 46 pub const MAX_INITIAL_WINDOW_SIZE: usize = (1 << 31) - 1; 47 48 /// MAX_FRAME_SIZE upper bound 49 pub const MAX_MAX_FRAME_SIZE: FrameSize = (1 << 24) - 1; 50 51 // ===== impl Settings ===== 52 53 impl Settings { ack() -> Settings54 pub fn ack() -> Settings { 55 Settings { 56 flags: SettingsFlags::ack(), 57 ..Settings::default() 58 } 59 } 60 is_ack(&self) -> bool61 pub fn is_ack(&self) -> bool { 62 self.flags.is_ack() 63 } 64 initial_window_size(&self) -> Option<u32>65 pub fn initial_window_size(&self) -> Option<u32> { 66 self.initial_window_size 67 } 68 set_initial_window_size(&mut self, size: Option<u32>)69 pub fn set_initial_window_size(&mut self, size: Option<u32>) { 70 self.initial_window_size = size; 71 } 72 max_concurrent_streams(&self) -> Option<u32>73 pub fn max_concurrent_streams(&self) -> Option<u32> { 74 self.max_concurrent_streams 75 } 76 set_max_concurrent_streams(&mut self, max: Option<u32>)77 pub fn set_max_concurrent_streams(&mut self, max: Option<u32>) { 78 self.max_concurrent_streams = max; 79 } 80 max_frame_size(&self) -> Option<u32>81 pub fn max_frame_size(&self) -> Option<u32> { 82 self.max_frame_size 83 } 84 set_max_frame_size(&mut self, size: Option<u32>)85 pub fn set_max_frame_size(&mut self, size: Option<u32>) { 86 if let Some(val) = size { 87 assert!(DEFAULT_MAX_FRAME_SIZE <= val && val <= MAX_MAX_FRAME_SIZE); 88 } 89 self.max_frame_size = size; 90 } 91 max_header_list_size(&self) -> Option<u32>92 pub fn max_header_list_size(&self) -> Option<u32> { 93 self.max_header_list_size 94 } 95 set_max_header_list_size(&mut self, size: Option<u32>)96 pub fn set_max_header_list_size(&mut self, size: Option<u32>) { 97 self.max_header_list_size = size; 98 } 99 is_push_enabled(&self) -> bool100 pub fn is_push_enabled(&self) -> bool { 101 self.enable_push.unwrap_or(1) != 0 102 } 103 set_enable_push(&mut self, enable: bool)104 pub fn set_enable_push(&mut self, enable: bool) { 105 self.enable_push = Some(enable as u32); 106 } 107 load(head: Head, payload: &[u8]) -> Result<Settings, Error>108 pub fn load(head: Head, payload: &[u8]) -> Result<Settings, Error> { 109 use self::Setting::*; 110 111 debug_assert_eq!(head.kind(), ::frame::Kind::Settings); 112 113 if !head.stream_id().is_zero() { 114 return Err(Error::InvalidStreamId); 115 } 116 117 // Load the flag 118 let flag = SettingsFlags::load(head.flag()); 119 120 if flag.is_ack() { 121 // Ensure that the payload is empty 122 if payload.len() > 0 { 123 return Err(Error::InvalidPayloadLength); 124 } 125 126 // Return the ACK frame 127 return Ok(Settings::ack()); 128 } 129 130 // Ensure the payload length is correct, each setting is 6 bytes long. 131 if payload.len() % 6 != 0 { 132 debug!("invalid settings payload length; len={:?}", payload.len()); 133 return Err(Error::InvalidPayloadAckSettings); 134 } 135 136 let mut settings = Settings::default(); 137 debug_assert!(!settings.flags.is_ack()); 138 139 for raw in payload.chunks(6) { 140 match Setting::load(raw) { 141 Some(HeaderTableSize(val)) => { 142 settings.header_table_size = Some(val); 143 }, 144 Some(EnablePush(val)) => match val { 145 0 | 1 => { 146 settings.enable_push = Some(val); 147 }, 148 _ => { 149 return Err(Error::InvalidSettingValue); 150 }, 151 }, 152 Some(MaxConcurrentStreams(val)) => { 153 settings.max_concurrent_streams = Some(val); 154 }, 155 Some(InitialWindowSize(val)) => if val as usize > MAX_INITIAL_WINDOW_SIZE { 156 return Err(Error::InvalidSettingValue); 157 } else { 158 settings.initial_window_size = Some(val); 159 }, 160 Some(MaxFrameSize(val)) => { 161 if val < DEFAULT_MAX_FRAME_SIZE || val > MAX_MAX_FRAME_SIZE { 162 return Err(Error::InvalidSettingValue); 163 } else { 164 settings.max_frame_size = Some(val); 165 } 166 }, 167 Some(MaxHeaderListSize(val)) => { 168 settings.max_header_list_size = Some(val); 169 }, 170 None => {}, 171 } 172 } 173 174 Ok(settings) 175 } 176 payload_len(&self) -> usize177 fn payload_len(&self) -> usize { 178 let mut len = 0; 179 self.for_each(|_| len += 6); 180 len 181 } 182 encode(&self, dst: &mut BytesMut)183 pub fn encode(&self, dst: &mut BytesMut) { 184 // Create & encode an appropriate frame head 185 let head = Head::new(Kind::Settings, self.flags.into(), StreamId::zero()); 186 let payload_len = self.payload_len(); 187 188 trace!("encoding SETTINGS; len={}", payload_len); 189 190 head.encode(payload_len, dst); 191 192 // Encode the settings 193 self.for_each(|setting| { 194 trace!("encoding setting; val={:?}", setting); 195 setting.encode(dst) 196 }); 197 } 198 for_each<F: FnMut(Setting)>(&self, mut f: F)199 fn for_each<F: FnMut(Setting)>(&self, mut f: F) { 200 use self::Setting::*; 201 202 if let Some(v) = self.header_table_size { 203 f(HeaderTableSize(v)); 204 } 205 206 if let Some(v) = self.enable_push { 207 f(EnablePush(v)); 208 } 209 210 if let Some(v) = self.max_concurrent_streams { 211 f(MaxConcurrentStreams(v)); 212 } 213 214 if let Some(v) = self.initial_window_size { 215 f(InitialWindowSize(v)); 216 } 217 218 if let Some(v) = self.max_frame_size { 219 f(MaxFrameSize(v)); 220 } 221 222 if let Some(v) = self.max_header_list_size { 223 f(MaxHeaderListSize(v)); 224 } 225 } 226 } 227 228 impl<T> From<Settings> for Frame<T> { from(src: Settings) -> Frame<T>229 fn from(src: Settings) -> Frame<T> { 230 Frame::Settings(src) 231 } 232 } 233 234 // ===== impl Setting ===== 235 236 impl Setting { 237 /// Creates a new `Setting` with the correct variant corresponding to the 238 /// given setting id, based on the settings IDs defined in section 239 /// 6.5.2. from_id(id: u16, val: u32) -> Option<Setting>240 pub fn from_id(id: u16, val: u32) -> Option<Setting> { 241 use self::Setting::*; 242 243 match id { 244 1 => Some(HeaderTableSize(val)), 245 2 => Some(EnablePush(val)), 246 3 => Some(MaxConcurrentStreams(val)), 247 4 => Some(InitialWindowSize(val)), 248 5 => Some(MaxFrameSize(val)), 249 6 => Some(MaxHeaderListSize(val)), 250 _ => None, 251 } 252 } 253 254 /// Creates a new `Setting` by parsing the given buffer of 6 bytes, which 255 /// contains the raw byte representation of the setting, according to the 256 /// "SETTINGS format" defined in section 6.5.1. 257 /// 258 /// The `raw` parameter should have length at least 6 bytes, since the 259 /// length of the raw setting is exactly 6 bytes. 260 /// 261 /// # Panics 262 /// 263 /// If given a buffer shorter than 6 bytes, the function will panic. load(raw: &[u8]) -> Option<Setting>264 fn load(raw: &[u8]) -> Option<Setting> { 265 let id: u16 = ((raw[0] as u16) << 8) | (raw[1] as u16); 266 let val: u32 = unpack_octets_4!(raw, 2, u32); 267 268 Setting::from_id(id, val) 269 } 270 encode(&self, dst: &mut BytesMut)271 fn encode(&self, dst: &mut BytesMut) { 272 use self::Setting::*; 273 274 let (kind, val) = match *self { 275 HeaderTableSize(v) => (1, v), 276 EnablePush(v) => (2, v), 277 MaxConcurrentStreams(v) => (3, v), 278 InitialWindowSize(v) => (4, v), 279 MaxFrameSize(v) => (5, v), 280 MaxHeaderListSize(v) => (6, v), 281 }; 282 283 dst.put_u16_be(kind); 284 dst.put_u32_be(val); 285 } 286 } 287 288 // ===== impl SettingsFlags ===== 289 290 impl SettingsFlags { empty() -> SettingsFlags291 pub fn empty() -> SettingsFlags { 292 SettingsFlags(0) 293 } 294 load(bits: u8) -> SettingsFlags295 pub fn load(bits: u8) -> SettingsFlags { 296 SettingsFlags(bits & ALL) 297 } 298 ack() -> SettingsFlags299 pub fn ack() -> SettingsFlags { 300 SettingsFlags(ACK) 301 } 302 is_ack(&self) -> bool303 pub fn is_ack(&self) -> bool { 304 self.0 & ACK == ACK 305 } 306 } 307 308 impl From<SettingsFlags> for u8 { from(src: SettingsFlags) -> u8309 fn from(src: SettingsFlags) -> u8 { 310 src.0 311 } 312 } 313