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