use super::STATIC_TABLE;
use super::HeaderTable;
pub fn encode_integer(mut value: usize, prefix_size: u8) -> Vec<u8> {
let Wrapping(mask) = if prefix_size >= 8 {
Wrapping(0xFF)
} else {
Wrapping(1u8 << prefix_size) - Wrapping(1)
};
let mask = mask as usize;
if value < mask {
return vec![value as u8];
}
let mut res: Vec<u8> = Vec::new();
res.push(mask as u8);
value -= mask;
while value >= 128 {
res.push(((value % 128) + 128) as u8);
value = value / 128;
}
res.push(value as u8);
res
}
pub struct Encoder<'a> {
header_table: HeaderTable<'a>,
}
impl<'a> Encoder<'a> {
pub fn new() -> Encoder<'a> {
Encoder {
header_table: HeaderTable::with_static_table(STATIC_TABLE),
}
}
pub fn encode(&mut self, headers: &Vec<(Vec<u8>, Vec<u8>)>) -> Vec<u8> {
let mut encoded: Vec<u8> = Vec::new();
for header in headers.iter() {
match self.header_table.find_header((&header.0, &header.1)) {
None => {
self.encode_literal(header, true, &mut encoded);
self.header_table.add_header(header.0.clone(), header.1.clone());
},
Some((index, false)) => {
self.encode_indexed_name((index, &header.1), false, &mut encoded);
},
Some((index, true)) => {
self.encode_indexed(index, &mut encoded);
}
};
}
encoded
}
fn encode_literal(&mut self,
header: &(Vec<u8>, Vec<u8>),
should_index: bool,
buf: &mut Vec<u8>) {
let mask = if should_index {
0x40
} else {
0x0
};
buf.push(mask);
self.encode_string_literal(&header.0, buf);
self.encode_string_literal(&header.1, buf);
}
fn encode_string_literal(&mut self, octet_str: &[u8], buf: &mut Vec<u8>) {
buf.extend(encode_integer(octet_str.len(), 7).into_iter());
buf.extend(octet_str.to_vec().into_iter());
}
fn encode_indexed_name(&mut self, header: (usize, &Vec<u8>), should_index: bool, buf: &mut Vec<u8>) {
let (mask, prefix) = if should_index {
(0x40, 6)
} else {
(0x0, 4)
};
let mut encoded_index = encode_integer(header.0, prefix);
encoded_index[0] |= mask;
buf.extend(encoded_index.into_iter());
self.encode_string_literal(&header.1, buf);
}
fn encode_indexed(&self, index: usize, buf: &mut Vec<u8>) {
let mut encoded = encode_integer(index, 7);
encoded[0] |= 0x80;
buf.extend(encoded.into_iter());
}
}
#[cfg(test)]
mod tests {
use super::encode_integer;
use super::Encoder;
use super::super::Decoder;
#[test]
fn test_encode_integer() {
assert_eq!(encode_integer(10, 5), [10]);
assert_eq!(encode_integer(1337, 5), [31, 154, 10]);
assert_eq!(encode_integer(127, 7), [127, 0]);
assert_eq!(encode_integer(255, 8), [255, 0]);
assert_eq!(encode_integer(254, 8), [254]);
assert_eq!(encode_integer(1, 8), [1]);
assert_eq!(encode_integer(0, 8), [0]);
assert_eq!(encode_integer(255, 7), [127, 128, 1]);
}
fn is_decodable(buf: &Vec<u8>, headers: &Vec<(Vec<u8>, Vec<u8>)>) -> bool {
let mut decoder = Decoder::new();
match decoder.decode(buf).ok() {
Some(h) => h == *headers,
None => false,
}
}
#[test]
fn test_encode_only_method() {
let mut encoder: Encoder = Encoder::new();
let headers = vec![
(b":method".to_vec(), b"GET".to_vec()),
];
let result = encoder.encode(&headers);
debug!("{:?}", result);
assert!(is_decodable(&result, &headers));
}
#[test]
fn test_custom_header_gets_indexed() {
let mut encoder: Encoder = Encoder::new();
let headers = vec![
(b"custom-key".to_vec(), b"custom-value".to_vec()),
];
let result = encoder.encode(&headers);
assert!(is_decodable(&result, &headers));
assert_eq!(encoder.header_table.dynamic_table.to_vec(), headers);
assert!(0x40 == (0x40 & result[0]));
debug!("{:?}", result);
}
#[test]
fn test_uses_index_on_second_iteration() {
let mut encoder: Encoder = Encoder::new();
let headers = vec![
(b"custom-key".to_vec(), b"custom-value".to_vec()),
];
let _ = encoder.encode(&headers);
let result = encoder.encode(&headers);
assert_eq!(encoder.header_table.dynamic_table.to_vec(), headers);
assert_eq!(result.len(), 1);
assert_eq!(0x80 & result[0], 0x80);
assert_eq!(result[0] ^ 0x80, 62);
assert_eq!(
encoder.header_table.get_from_table(62).unwrap(),
(&headers[0].0[..], &headers[0].1[..]));
}
#[test]
fn test_name_indexed_value_not() {
{
let mut encoder: Encoder = Encoder::new();
let headers = vec![
(b":method".to_vec(), b"PUT".to_vec()),
];
let result = encoder.encode(&headers);
assert_eq!(result[0], 3);
assert_eq!(&result[1..], &[3, b'P', b'U', b'T']);
}
{
let mut encoder: Encoder = Encoder::new();
let headers = vec![
(b":authority".to_vec(), b"example.com".to_vec()),
];
let result = encoder.encode(&headers);
assert_eq!(result[0], 1);
assert_eq!(
&result[1..],
&[11, b'e', b'x', b'a', b'm', b'p', b'l', b'e', b'.', b'c', b'o', b'm'])
}
}
#[test]
fn test_multiple_headers_encoded() {
let mut encoder = Encoder::new();
let headers = vec![
(b"custom-key".to_vec(), b"custom-value".to_vec()),
(b":method".to_vec(), b"GET".to_vec()),
(b":path".to_vec(), b"/some/path".to_vec()),
];
let result = encoder.encode(&headers);
assert!(is_decodable(&result, &headers));
}
}