mod dynamic;
mod iter;
mod r#static;
pub use iter::TableIter;
use dynamic::DynamicTable;
use r#static::{StaticTable, STATIC_TABLE};
#[derive(Debug)]
pub struct Table<'a> {
static_table: StaticTable<'a>,
dynamic_table: DynamicTable,
}
impl<'a> Table<'a> {
pub fn with_dynamic_size(max_dynamic_size: u32) -> Self {
Self {
static_table: STATIC_TABLE,
dynamic_table: DynamicTable::with_size(max_dynamic_size),
}
}
pub fn len(&self) -> usize {
self.static_table.len() + self.dynamic_table.len()
}
pub fn dynamic_len(&self) -> usize {
self.dynamic_table.len()
}
pub fn dynamic_size(&self) -> u32 {
self.dynamic_table.size()
}
pub fn max_dynamic_size(&self) -> u32 {
self.dynamic_table.max_size()
}
pub fn update_max_dynamic_size(&mut self, size: u32) {
self.dynamic_table.update_max_size(size);
}
pub fn iter(&'a self) -> TableIter<'a> {
TableIter{ index: 1, table: &self }
}
pub fn get(&self, index: u32) -> Option<(&[u8], &[u8])> {
let index = if index == 0 {
return None;
} else {
index - 1
};
let static_len = self.static_table.len() as u32;
if index < static_len {
Some(self.static_table[index as usize])
} else {
self.dynamic_table.get(index - static_len)
}
}
pub fn find(&self, name: &[u8], value: &[u8]) -> Option<(usize, bool)> {
let mut name_match = None;
for (i, h) in self.iter().enumerate() {
if name == h.0 {
if value == h.1 {
return Some((i + 1, true)); } else if name_match.is_none() {
name_match = Some(i + 1); }
}
}
match name_match {
Some(i) => Some((i, false)),
None => None,
}
}
pub fn insert(&mut self, name: Vec<u8>, value: Vec<u8>) {
self.dynamic_table.insert(name, value);
}
}
impl<'a> Default for Table<'a> {
fn default() -> Self {
Self {
static_table: STATIC_TABLE,
dynamic_table: DynamicTable::default(),
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn inserts_new_headers() {
let mut tbl = Table::default();
assert_eq!(tbl.len(), 61);
assert_eq!(tbl.dynamic_len(), 0);
assert_eq!(tbl.dynamic_size(), 0);
tbl.insert(b"a0".to_vec(), b"b0".to_vec());
assert_eq!(tbl.len(), 62);
assert_eq!(tbl.dynamic_len(), 1);
assert_eq!(tbl.dynamic_size(), 36);
tbl.insert(b"a1".to_vec(), b"b1".to_vec());
assert_eq!(tbl.len(), 63);
assert_eq!(tbl.dynamic_len(), 2);
assert_eq!(tbl.dynamic_size(), 72);
}
#[test]
fn iters_through_all_headers() {
let mut tbl = Table::default();
tbl.insert(b"a0".to_vec(), b"b0".to_vec());
let iter = tbl.iter();
assert_eq!(iter.count(), 62); let last = iter.last().unwrap();
assert_eq!(vec![last.0, last.1], vec![b"a0", b"b0"]);
}
#[test]
fn find_header_by_index() {
let mut tbl = Table::default();
tbl.insert(b"a0".to_vec(), b"b0".to_vec());
assert_eq!(tbl.get(0), None); let h1 = tbl.get(1).unwrap();
assert_eq!(vec![h1.0, h1.1], vec![b":authority".to_vec(), vec![]]);
let h2 = tbl.get(2).unwrap();
assert_eq!(vec![h2.0, h2.1], vec![b":method".to_vec(), b"GET".to_vec()]);
let h61 = tbl.get(61).unwrap();
assert_eq!(vec![h61.0, h61.1], vec![b"www-authenticate".to_vec(), vec![]]);
let h62 = tbl.get(62).unwrap();
assert_eq!(vec![h62.0, h62.1], vec![b"a0", b"b0"]);
}
#[test]
fn find_header_match() {
let mut tbl = Table::default();
tbl.insert(b"a".to_vec(), b"b".to_vec()); tbl.insert(b"a".to_vec(), b"c".to_vec()); let m = tbl.find(b":method", b"POST").unwrap(); assert_eq!(m.0, 3); assert_eq!(m.1, true); let m = tbl.find(b"a", b"b").unwrap(); assert_eq!(m.0, 63); assert_eq!(m.1, true); let m = tbl.find(b":method", b"DELETE").unwrap(); assert_eq!(m.0, 2); assert_eq!(m.1, false); let m = tbl.find(b"a", b"x").unwrap(); assert_eq!(m.0, 62); assert_eq!(m.1, false); let m = tbl.find(b"x", b"x"); assert_eq!(m, None); }
}