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