use crate::courierust_error::{Error, Result};
use alloc::vec::Vec;
pub const SETTINGS_HEADER_TABLE_SIZE: u16 = 0x1;
pub const SETTINGS_ENABLE_PUSH: u16 = 0x2;
pub const SETTINGS_MAX_CONCURRENT_STREAMS: u16 = 0x3;
pub const SETTINGS_INITIAL_WINDOW_SIZE: u16 = 0x4;
pub const SETTINGS_MAX_FRAME_SIZE: u16 = 0x5;
pub const SETTINGS_MAX_HEADER_LIST_SIZE: u16 = 0x6;
pub const SETTINGS_NO_RFC7540_PRIORITIES: u16 = 0x9;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Setting {
pub id: u16,
pub value: u32,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Settings {
pub header_table_size: u32,
pub enable_push: u32,
pub max_concurrent_streams: u32,
pub initial_window_size: u32,
pub max_frame_size: u32,
pub max_header_list_size: u32,
pub no_rfc7540_priorities: u32,
}
impl Default for Settings {
fn default() -> Self {
Self {
header_table_size: 4096,
enable_push: 1,
max_concurrent_streams: 0,
initial_window_size: 65535,
max_frame_size: 16384,
max_header_list_size: 0,
no_rfc7540_priorities: 0,
}
}
}
impl Settings {
pub fn apply(&mut self, entries: &[Setting]) -> Result<()> {
for s in entries {
match s.id {
SETTINGS_HEADER_TABLE_SIZE => self.header_table_size = s.value,
SETTINGS_ENABLE_PUSH => {
if s.value > 1 {
return Err(Error::protocol("SETTINGS_ENABLE_PUSH must be 0 or 1"));
}
self.enable_push = s.value;
}
SETTINGS_MAX_CONCURRENT_STREAMS => self.max_concurrent_streams = s.value,
SETTINGS_INITIAL_WINDOW_SIZE => {
if s.value > 0x7fff_ffff {
return Err(Error::protocol("SETTINGS_INITIAL_WINDOW_SIZE too large"));
}
self.initial_window_size = s.value;
}
SETTINGS_MAX_FRAME_SIZE => {
if !(16_384..=16_777_215).contains(&s.value) {
return Err(Error::protocol("SETTINGS_MAX_FRAME_SIZE out of range"));
}
self.max_frame_size = s.value;
}
SETTINGS_MAX_HEADER_LIST_SIZE => self.max_header_list_size = s.value,
SETTINGS_NO_RFC7540_PRIORITIES => {
if s.value > 1 {
return Err(Error::protocol(
"SETTINGS_NO_RFC7540_PRIORITIES must be 0 or 1",
));
}
self.no_rfc7540_priorities = s.value;
}
_ => {} }
}
Ok(())
}
pub fn to_vec(&self) -> Vec<Setting> {
vec![
Setting {
id: SETTINGS_HEADER_TABLE_SIZE,
value: self.header_table_size,
},
Setting {
id: SETTINGS_ENABLE_PUSH,
value: self.enable_push,
},
Setting {
id: SETTINGS_MAX_CONCURRENT_STREAMS,
value: self.max_concurrent_streams,
},
Setting {
id: SETTINGS_INITIAL_WINDOW_SIZE,
value: self.initial_window_size,
},
Setting {
id: SETTINGS_MAX_FRAME_SIZE,
value: self.max_frame_size,
},
Setting {
id: SETTINGS_MAX_HEADER_LIST_SIZE,
value: self.max_header_list_size,
},
Setting {
id: SETTINGS_NO_RFC7540_PRIORITIES,
value: self.no_rfc7540_priorities,
},
]
}
pub fn to_wire(&self) -> Vec<u8> {
let entries = self.to_vec();
let mut out = Vec::with_capacity(entries.len() * 6);
for s in entries {
out.extend_from_slice(&s.id.to_be_bytes());
out.extend_from_slice(&s.value.to_be_bytes());
}
out
}
}