use std::io;
use std::num::Wrapping;
use super::STATIC_TABLE;
use super::HeaderTable;
pub fn encode_integer_into<W: io::Write>(
mut value: usize,
prefix_size: u8,
leading_bits: u8,
writer: &mut W)
-> io::Result<()> {
let Wrapping(mask) = if prefix_size >= 8 {
Wrapping(0xFF)
} else {
Wrapping(1u8 << prefix_size) - Wrapping(1)
};
let leading_bits = leading_bits & (!mask);
let mask = mask as usize;
if value < mask {
try!(writer.write_all(&[leading_bits | value as u8]));
return Ok(());
}
try!(writer.write_all(&[leading_bits | mask as u8]));
value -= mask;
while value >= 128 {
try!(writer.write_all(&[((value % 128) + 128) as u8]));
value = value / 128;
}
try!(writer.write_all(&[value as u8]));
Ok(())
}
pub fn encode_integer(value: usize, prefix_size: u8) -> Vec<u8> {
let mut res = Vec::new();
encode_integer_into(value, prefix_size, 0, &mut res).unwrap();
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<'b, I>(&mut self, headers: I) -> Vec<u8>
where I: IntoIterator<Item=(&'b [u8], &'b [u8])> {
let mut encoded: Vec<u8> = Vec::new();
self.encode_into(headers, &mut encoded).unwrap();
encoded
}
pub fn encode_into<'b, I, W>(&mut self, headers: I, writer: &mut W) -> io::Result<()>
where I: IntoIterator<Item=(&'b [u8], &'b [u8])>,
W: io::Write {
for header in headers {
try!(self.encode_header_into(header, writer));
}
Ok(())
}
pub fn encode_header_into<W: io::Write>(
&mut self,
header: (&[u8], &[u8]),
writer: &mut W)
-> io::Result<()> {
match self.header_table.find_header(header) {
None => {
try!(self.encode_literal(&header, true, writer));
self.header_table.add_header(header.0.to_vec(), header.1.to_vec());
},
Some((index, false)) => {
try!(self.encode_indexed_name((index, header.1), false, writer));
},
Some((index, true)) => {
try!(self.encode_indexed(index, writer));
}
};
Ok(())
}
fn encode_literal<W: io::Write>(
&mut self,
header: &(&[u8], &[u8]),
should_index: bool,
buf: &mut W)
-> io::Result<()> {
let mask = if should_index {
0x40
} else {
0x0
};
try!(buf.write_all(&[mask]));
try!(self.encode_string_literal(&header.0, buf));
try!(self.encode_string_literal(&header.1, buf));
Ok(())
}
fn encode_string_literal<W: io::Write>(
&mut self,
octet_str: &[u8],
buf: &mut W)
-> io::Result<()> {
try!(encode_integer_into(octet_str.len(), 7, 0, buf));
try!(buf.write_all(octet_str));
Ok(())
}
fn encode_indexed_name<W: io::Write>(
&mut self,
header: (usize, &[u8]),
should_index: bool,
buf: &mut W)
-> io::Result<()> {
let (mask, prefix) = if should_index {
(0x40, 6)
} else {
(0x0, 4)
};
try!(encode_integer_into(header.0, prefix, mask, buf));
try!(self.encode_string_literal(&header.1, buf));
Ok(())
}
fn encode_indexed<W: io::Write>(&self, index: usize, buf: &mut W) -> io::Result<()> {
try!(encode_integer_into(index, 7, 0x80, buf));
Ok(())
}
}
#[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.iter().map(|h| (&h.0[..], &h.1[..])));
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.iter().map(|h| (&h.0[..], &h.1[..])));
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.iter().map(|h| (&h.0[..], &h.1[..])));
let result = encoder.encode(headers.iter().map(|h| (&h.0[..], &h.1[..])));
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", b"PUT"),
];
let result = encoder.encode(headers.iter().map(|h| (&h.0[..], &h.1[..])));
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.iter().map(|h| (&h.0[..], &h.1[..])));
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.iter().map(|h| (&h.0[..], &h.1[..])));
assert!(is_decodable(&result, &headers));
}
}