use crate::hpack::dynamic_table::DynamicTable;
use crate::hpack::huffman;
use crate::hpack::integer;
use crate::hpack::table::{HeaderField, STATIC_TABLE_SIZE, find_static_index};
#[derive(Debug)]
pub struct Encoder {
dynamic_table: DynamicTable,
use_huffman: bool,
}
impl Encoder {
#[must_use]
pub fn new(max_table_size: usize) -> Self {
Self {
dynamic_table: DynamicTable::new(max_table_size),
use_huffman: true,
}
}
pub fn set_huffman(&mut self, use_huffman: bool) {
self.use_huffman = use_huffman;
}
pub fn set_max_table_size(&mut self, max_size: usize) {
self.dynamic_table.set_max_size(max_size);
}
#[must_use]
pub fn dynamic_table(&self) -> &DynamicTable {
&self.dynamic_table
}
pub fn encode(&mut self, buf: &mut Vec<u8>, headers: &[HeaderField]) {
for header in headers {
if header.sensitive {
self.encode_header_sensitive(buf, &header.name, &header.value);
} else {
self.encode_header(buf, &header.name, &header.value, true);
}
}
}
pub fn encode_header(&mut self, buf: &mut Vec<u8>, name: &[u8], value: &[u8], indexing: bool) {
if let Some((index, exact)) = self.find_index(name, value) {
if exact {
self.encode_indexed(buf, index);
return;
}
if indexing {
self.encode_literal_indexed(buf, index, value);
self.dynamic_table.insert(name.to_vec(), value.to_vec());
} else {
self.encode_literal_without_indexing_indexed(buf, index, value);
}
} else if indexing {
self.encode_literal_new(buf, name, value);
self.dynamic_table.insert(name.to_vec(), value.to_vec());
} else {
self.encode_literal_without_indexing_new(buf, name, value);
}
}
pub fn encode_header_sensitive(&self, buf: &mut Vec<u8>, name: &[u8], value: &[u8]) {
if let Some((index, _exact)) = self.find_index(name, value) {
self.encode_never_indexed_with_name_index(buf, index, value);
} else {
self.encode_never_indexed_new(buf, name, value);
}
}
fn find_index(&self, name: &[u8], value: &[u8]) -> Option<(usize, bool)> {
if let Some((index, exact)) = find_static_index(name, value) {
if exact {
return Some((index, true));
}
if let Some((dyn_index, true)) = self.dynamic_table.find(name, value) {
return Some((STATIC_TABLE_SIZE + 1 + dyn_index, true));
}
return Some((index, false));
}
if let Some((dyn_index, exact)) = self.dynamic_table.find(name, value) {
return Some((STATIC_TABLE_SIZE + 1 + dyn_index, exact));
}
None
}
fn encode_indexed(&self, buf: &mut Vec<u8>, index: usize) {
let mut temp = [0u8; 16];
let len = integer::encode(&mut temp, index as u64, 7, 0x80)
.expect("16-byte buffer is sufficient for HPACK integer");
buf.extend_from_slice(&temp[..len]);
}
fn encode_literal_indexed(&self, buf: &mut Vec<u8>, name_index: usize, value: &[u8]) {
let mut temp = [0u8; 16];
let len = integer::encode(&mut temp, name_index as u64, 6, 0x40)
.expect("16-byte buffer is sufficient for HPACK integer");
buf.extend_from_slice(&temp[..len]);
self.encode_string(buf, value);
}
fn encode_literal_new(&self, buf: &mut Vec<u8>, name: &[u8], value: &[u8]) {
buf.push(0x40);
self.encode_string(buf, name);
self.encode_string(buf, value);
}
fn encode_literal_without_indexing_indexed(
&self,
buf: &mut Vec<u8>,
name_index: usize,
value: &[u8],
) {
let mut temp = [0u8; 16];
let len = integer::encode(&mut temp, name_index as u64, 4, 0x00)
.expect("16-byte buffer is sufficient for HPACK integer");
buf.extend_from_slice(&temp[..len]);
self.encode_string(buf, value);
}
fn encode_literal_without_indexing_new(&self, buf: &mut Vec<u8>, name: &[u8], value: &[u8]) {
buf.push(0x00);
self.encode_string(buf, name);
self.encode_string(buf, value);
}
fn encode_never_indexed_with_name_index(
&self,
buf: &mut Vec<u8>,
name_index: usize,
value: &[u8],
) {
let mut temp = [0u8; 16];
let len = integer::encode(&mut temp, name_index as u64, 4, 0x10)
.expect("16-byte buffer is sufficient for HPACK integer");
buf.extend_from_slice(&temp[..len]);
self.encode_string(buf, value);
}
fn encode_never_indexed_new(&self, buf: &mut Vec<u8>, name: &[u8], value: &[u8]) {
buf.push(0x10);
self.encode_string(buf, name);
self.encode_string(buf, value);
}
fn encode_string(&self, buf: &mut Vec<u8>, data: &[u8]) {
if self.use_huffman {
let encoded = huffman::encode_to_vec(data);
if encoded.len() < data.len() {
let mut temp = [0u8; 16];
let len = integer::encode(&mut temp, encoded.len() as u64, 7, 0x80)
.expect("16-byte buffer is sufficient for HPACK integer");
buf.extend_from_slice(&temp[..len]);
buf.extend_from_slice(&encoded);
return;
}
}
let mut temp = [0u8; 16];
let len = integer::encode(&mut temp, data.len() as u64, 7, 0x00)
.expect("16-byte buffer is sufficient for HPACK integer");
buf.extend_from_slice(&temp[..len]);
buf.extend_from_slice(data);
}
pub fn encode_size_update(&self, buf: &mut Vec<u8>, new_size: usize) {
let mut temp = [0u8; 16];
let len = integer::encode(&mut temp, new_size as u64, 5, 0x20)
.expect("16-byte buffer is sufficient for HPACK integer");
buf.extend_from_slice(&temp[..len]);
}
}
impl Default for Encoder {
fn default() -> Self {
Self::new(crate::settings::DEFAULT_HEADER_TABLE_SIZE as usize)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_encode_indexed() {
let encoder = Encoder::new(4096);
let mut buf = Vec::new();
encoder.encode_indexed(&mut buf, 2);
assert_eq!(buf, vec![0x82]);
}
#[test]
fn test_encode_literal_indexed() {
let encoder = Encoder::new(4096);
let mut buf = Vec::new();
encoder.encode_literal_indexed(&mut buf, 1, b"www.example.com");
assert_eq!(buf[0], 0x41);
}
#[test]
fn test_encode_header_list() {
let mut encoder = Encoder::new(4096);
let mut buf = Vec::new();
let headers = vec![
HeaderField::from_str(":method", "GET"),
HeaderField::from_str(":path", "/"),
];
encoder.encode(&mut buf, &headers);
assert!(buf.contains(&0x82));
assert!(buf.contains(&0x84));
}
#[test]
fn test_encode_never_indexed() {
let encoder = Encoder::new(4096);
let mut buf = Vec::new();
encoder.encode_never_indexed_new(&mut buf, b"authorization", b"secret");
assert_eq!(buf[0], 0x10);
}
#[test]
fn test_encode_never_indexed_with_index() {
let encoder = Encoder::new(4096);
let mut buf = Vec::new();
encoder.encode_never_indexed_with_name_index(&mut buf, 23, b"secret");
assert_eq!(buf[0] & 0xF0, 0x10);
}
#[test]
fn test_encode_sensitive_header() {
let mut encoder = Encoder::new(4096);
let mut buf = Vec::new();
let headers = vec![
HeaderField::from_str(":method", "GET"),
HeaderField::sensitive("authorization", "Bearer token"),
];
encoder.encode(&mut buf, &headers);
assert_eq!(buf[0], 0x82);
assert_eq!(buf[1] & 0xF0, 0x10);
}
}