use std::collections::VecDeque;
use std::fmt;
use std::sync::OnceLock;
use bytes::BytesMut;
use crate::helpers::fields::{self, Entry, HeaderField, Integer, Mark, StaticIndex, StringLiteral};
use crate::helpers::huffman;
use crate::helpers::text::Text;
pub struct StaticTable;
impl StaticTable {
pub fn entries() -> &'static [HeaderField; 99] {
static STATIC_TABLE: OnceLock<[HeaderField; 99]> = OnceLock::new();
STATIC_TABLE.get_or_init(|| {
[
(":authority", ""), (":path", "/"), ("age", "0"), ("content-disposition", ""), ("content-length", "0"), ("cookie", ""), ("date", ""), ("etag", ""), ("if-modified-since", ""), ("if-none-match", ""), ("last-modified", ""), ("link", ""), ("location", ""), ("referer", ""), ("set-cookie", ""), (":method", "CONNECT"), (":method", "DELETE"), (":method", "GET"), (":method", "HEAD"), (":method", "OPTIONS"), (":method", "POST"), (":method", "PUT"), (":scheme", "http"), (":scheme", "https"), (":status", "103"), (":status", "200"), (":status", "304"), (":status", "404"), (":status", "503"), ("accept", "*/*"), ("accept", "application/dns-message"), ("accept-encoding", "gzip, deflate, br"), ("accept-ranges", "bytes"), ("access-control-allow-headers", "cache-control"), ("access-control-allow-headers", "content-type"), ("access-control-allow-origin", "*"), ("cache-control", "max-age=0"), ("cache-control", "max-age=2592000"), ("cache-control", "max-age=604800"), ("cache-control", "no-cache"), ("cache-control", "no-store"), ("cache-control", "public, max-age=31536000"), ("content-encoding", "br"), ("content-encoding", "gzip"), ("content-type", "application/dns-message"), ("content-type", "application/javascript"), ("content-type", "application/json"), ("content-type", "application/x-www-form-urlencoded"), ("content-type", "image/gif"), ("content-type", "image/jpeg"), ("content-type", "image/png"), ("content-type", "text/css"), ("content-type", "text/html; charset=utf-8"), ("content-type", "text/plain"), ("content-type", "text/plain;charset=utf-8"), ("range", "bytes=0-"), ("strict-transport-security", "max-age=31536000"), ("strict-transport-security", "max-age=31536000; includesubdomains"), ("strict-transport-security", "max-age=31536000; includesubdomains; preload"), ("vary", "accept-encoding"), ("vary", "origin"), ("x-content-type-options", "nosniff"), ("x-xss-protection", "1; mode=block"), (":status", "100"), (":status", "204"), (":status", "206"), (":status", "302"), (":status", "400"), (":status", "403"), (":status", "421"), (":status", "425"), (":status", "500"), ("accept-language", ""), ("access-control-allow-credentials", "FALSE"), ("access-control-allow-credentials", "TRUE"), ("access-control-allow-headers", "*"), ("access-control-allow-methods", "get"), ("access-control-allow-methods", "get, post, options"), ("access-control-allow-methods", "options"), ("access-control-expose-headers", "content-length"), ("access-control-request-headers", "content-type"), ("access-control-request-method", "get"), ("access-control-request-method", "post"), ("alt-svc", "clear"), ("authorization", ""), ("content-security-policy", "script-src 'none'; object-src 'none'; base-uri 'none'"), ("early-data", "1"), ("expect-ct", ""), ("forwarded", ""), ("if-range", ""), ("origin", ""), ("purpose", "prefetch"), ("server", ""), ("timing-allow-origin", "*"), ("upgrade-insecure-requests", "1"), ("user-agent", ""), ("x-forwarded-for", ""), ("x-frame-options", "deny"), ("x-frame-options", "sameorigin"), ]
.map(|(name, value)| HeaderField::new(name, value))
})
}
pub fn index() -> &'static StaticIndex {
static INDEX: OnceLock<StaticIndex> = OnceLock::new();
INDEX.get_or_init(|| StaticIndex::new(StaticTable::entries(), 0))
}
pub fn find(field: &HeaderField) -> Option<(u64, bool)> {
let (named, exact) = StaticTable::index().lookup(&field.name, &field.value);
match (exact, named) {
(Some(index), _) => Some((index as u64, true)),
(None, Some(index)) => Some((index as u64, false)),
(None, None) => None,
}
}
}
pub struct DynamicTable {
entries: VecDeque<Entry>,
size: usize,
capacity: usize,
inserted_count: u64,
}
impl DynamicTable {
pub const DEFAULT_CAPACITY: usize = 0;
pub fn new(capacity: usize) -> Self {
Self { entries: VecDeque::new(), size: 0, capacity, inserted_count: 0 }
}
pub fn insert(&mut self, field: HeaderField) -> u64 {
let size = field.size();
while self.size + size > self.capacity {
match self.entries.pop_back() {
Some(evicted) => self.size -= evicted.size(),
None => break,
}
}
self.size += size;
self.entries.push_front(Entry::of(field));
self.inserted_count += 1;
self.inserted_count - 1
}
pub fn fits(&self, field: &HeaderField) -> bool {
field.size() <= self.capacity
}
pub fn oldest(&self) -> u64 {
self.inserted_count - self.entries.len() as u64
}
pub fn admits(&self, field: &HeaderField, floor: u64) -> bool {
if !self.fits(field) {
return false;
}
let size = field.size();
let mut held = self.size;
for (absolute, entry) in (self.oldest()..).zip(self.entries.iter().rev()) {
if held + size <= self.capacity {
break;
}
if absolute >= floor {
return false;
}
held -= entry.size();
}
held + size <= self.capacity
}
pub fn get(&self, absolute_index: u64) -> Option<&HeaderField> {
let offset = self.inserted_count.checked_sub(absolute_index + 1)?;
self.entries.get(offset as usize).map(|entry| &entry.field)
}
pub fn set_capacity(&mut self, capacity: usize) {
self.capacity = capacity;
while self.size > self.capacity {
match self.entries.pop_back() {
Some(evicted) => self.size -= evicted.size(),
None => break,
}
}
}
pub fn relative(&self, index: u64) -> Option<u64> {
self.inserted_count.checked_sub(index + 1)
}
pub fn indexed(&self, base: u64, index: u64) -> Option<u64> {
base.checked_sub(index + 1).filter(|absolute| *absolute < self.inserted_count)
}
pub fn post_base(&self, base: u64, index: u64) -> Option<u64> {
base.checked_add(index).filter(|absolute| *absolute < self.inserted_count)
}
pub fn probe(&self, field: &HeaderField, below: u64) -> (Option<(u64, bool)>, bool) {
let mark = Mark::of(&field.name);
let mut name_only = None;
let mut anywhere = false;
for (offset, entry) in self.entries.iter().enumerate() {
if !entry.named(mark, field) {
continue;
}
let Some(absolute) = self.inserted_count.checked_sub(offset as u64 + 1) else {
break;
};
if entry.valued(field) {
anywhere = true;
if absolute < below {
return (Some((absolute, true)), true);
}
} else if absolute < below {
name_only.get_or_insert(absolute);
}
}
(name_only.map(|absolute| (absolute, false)), anywhere)
}
pub fn find(&self, field: &HeaderField) -> Option<(u64, bool)> {
let mark = Mark::of(&field.name);
let mut name_only = None;
for (offset, entry) in self.entries.iter().enumerate() {
if !entry.named(mark, field) {
continue;
}
let Some(absolute) = self.inserted_count.checked_sub(offset as u64 + 1) else {
break;
};
if entry.valued(field) {
return Some((absolute, true));
}
name_only.get_or_insert(absolute);
}
name_only.map(|absolute| (absolute, false))
}
pub fn inserted_count(&self) -> u64 {
self.inserted_count
}
pub fn size(&self) -> usize {
self.size
}
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum Error {
IndexOutOfRange(u64),
IntegerOverflow,
InvalidCapacityUpdate,
InvalidInsertCount,
InvalidBase,
EntryTooLarge,
InstructionTooLarge,
TooManyBlockedStreams,
Incomplete,
Blocked,
Huffman(huffman::DecodeError),
DecodedSizeExceeded,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::IndexOutOfRange(index) => write!(f, "absolute index {index} is out of range"),
Self::IntegerOverflow => write!(f, "integer representation overflowed"),
Self::InvalidCapacityUpdate => write!(f, "dynamic table capacity update exceeds the negotiated limit"),
Self::InvalidInsertCount => write!(f, "required insert count could not have been produced by an encoder"),
Self::InvalidBase => write!(f, "delta base places the base below zero"),
Self::EntryTooLarge => write!(f, "entry is larger than the dynamic table capacity"),
Self::InstructionTooLarge => write!(f, "a single instruction exceeds the permitted size"),
Self::TooManyBlockedStreams => write!(f, "more streams are blocked than were advertised"),
Self::DecodedSizeExceeded => write!(f, "decoded header list exceeds the permitted size"),
Self::Incomplete => write!(f, "representation ends before the block does"),
Self::Blocked => write!(f, "decoding is blocked on a pending dynamic table insertion"),
Self::Huffman(err) => write!(f, "huffman error: {err}"),
}
}
}
impl std::error::Error for Error {}
impl From<huffman::DecodeError> for Error {
fn from(err: huffman::DecodeError) -> Self {
Self::Huffman(err)
}
}
impl From<fields::Error> for Error {
fn from(err: fields::Error) -> Self {
match err {
fields::Error::IntegerOverflow => Self::IntegerOverflow,
fields::Error::Incomplete => Self::Incomplete,
fields::Error::Huffman(err) => Self::Huffman(err),
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum EncoderInstruction {
SetDynamicTableCapacity {
capacity: usize,
},
InsertWithNameReference {
from_static: bool,
name_index: u64,
value: Vec<u8>,
},
InsertWithLiteralName {
name: Vec<u8>,
value: Vec<u8>,
},
Duplicate {
index: u64,
},
}
impl EncoderInstruction {
pub fn encode(&self) -> Vec<u8> {
let mut out = Vec::new();
self.encode_into(&mut out);
out
}
pub fn encode_into(&self, out: &mut Vec<u8>) {
match self {
Self::SetDynamicTableCapacity { capacity } => {
Integer::encode(out, *capacity as u64, 5, 0x20);
}
Self::InsertWithNameReference { from_static, name_index, value } => {
Integer::encode(out, *name_index, 6, 0x80 | u8::from(*from_static) << 6);
StringLiteral::encode_shorter(out, value, 7, 0x00);
}
Self::InsertWithLiteralName { name, value } => {
StringLiteral::encode_shorter(out, name, 5, 0x40);
StringLiteral::encode_shorter(out, value, 7, 0x00);
}
Self::Duplicate { index } => Integer::encode(out, *index, 5, 0x00),
}
}
pub fn decode(input: &[u8]) -> Result<(usize, Self), Error> {
let first = *input.first().ok_or(Error::Incomplete)?;
if first & 0x80 != 0 {
let (mut consumed, name_index) = Integer::decode(input, 6)?;
let (taken, value) = StringLiteral::decode(&input[consumed..], 7)?;
consumed += taken;
return Ok((consumed, Self::InsertWithNameReference {
from_static: first & 0x40 != 0,
name_index,
value,
}));
}
if first & 0x40 != 0 {
let (mut consumed, name) = StringLiteral::decode(input, 5)?;
let (taken, value) = StringLiteral::decode(&input[consumed..], 7)?;
consumed += taken;
return Ok((consumed, Self::InsertWithLiteralName { name, value }));
}
if first & 0x20 != 0 {
let (consumed, capacity) = Integer::decode(input, 5)?;
return Ok((consumed, Self::SetDynamicTableCapacity { capacity: capacity as usize }));
}
let (consumed, index) = Integer::decode(input, 5)?;
Ok((consumed, Self::Duplicate { index }))
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum DecoderInstruction {
SectionAcknowledgment {
stream_id: u64,
},
StreamCancellation {
stream_id: u64,
},
InsertCountIncrement {
increment: u64,
},
}
impl DecoderInstruction {
pub fn encode(&self) -> Vec<u8> {
let mut out = Vec::new();
self.encode_into(&mut out);
out
}
pub fn encode_into(&self, out: &mut Vec<u8>) {
match self {
Self::SectionAcknowledgment { stream_id } => Integer::encode(out, *stream_id, 7, 0x80),
Self::StreamCancellation { stream_id } => Integer::encode(out, *stream_id, 6, 0x40),
Self::InsertCountIncrement { increment } => Integer::encode(out, *increment, 6, 0x00),
}
}
pub fn decode(input: &[u8]) -> Result<(usize, Self), Error> {
let first = *input.first().ok_or(Error::Incomplete)?;
if first & 0x80 != 0 {
let (consumed, stream_id) = Integer::decode(input, 7)?;
return Ok((consumed, Self::SectionAcknowledgment { stream_id }));
}
if first & 0x40 != 0 {
let (consumed, stream_id) = Integer::decode(input, 6)?;
return Ok((consumed, Self::StreamCancellation { stream_id }));
}
let (consumed, increment) = Integer::decode(input, 6)?;
Ok((consumed, Self::InsertCountIncrement { increment }))
}
}
pub struct Prefix;
impl Prefix {
pub fn max_entries(max_capacity: usize) -> u64 {
(max_capacity / HeaderField::OVERHEAD) as u64
}
pub fn relative(base: u64, absolute: u64) -> u64 {
base.saturating_sub(absolute).saturating_sub(1)
}
pub fn encode_insert_count(required: u64, max_capacity: usize) -> u64 {
let full_range = 2 * Prefix::max_entries(max_capacity);
if required == 0 || full_range == 0 {
return 0;
}
required % full_range + 1
}
pub fn decode_insert_count(encoded: u64, inserted: u64, max_capacity: usize) -> Result<u64, Error> {
if encoded == 0 {
return Ok(0);
}
let full_range = 2 * Prefix::max_entries(max_capacity);
if full_range == 0 || encoded > full_range {
return Err(Error::InvalidInsertCount);
}
let max_value = inserted.saturating_add(Prefix::max_entries(max_capacity));
let max_wrapped = max_value / full_range * full_range;
let mut required = max_wrapped.saturating_add(encoded).saturating_sub(1);
if required > max_value {
if required <= full_range {
return Err(Error::InvalidInsertCount);
}
required -= full_range;
}
if required == 0 {
return Err(Error::InvalidInsertCount);
}
Ok(required)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Section {
pub stream_id: u64,
pub required: u64,
pub floor: u64,
}
pub struct Encoder {
dynamic_table: DynamicTable,
known_received_count: u64,
max_capacity: usize,
capacity_limit: usize,
max_outstanding_sections: usize,
max_instruction_size: usize,
sections: VecDeque<Section>,
section_floor: u64,
idle_capacity: usize,
stream_out: Vec<u8>,
stream_recv: BytesMut,
matches: Vec<Option<(bool, u64, bool)>>,
}
impl Encoder {
pub const DEFAULT_CAPACITY_LIMIT: usize = 4096;
pub const DEFAULT_MAX_OUTSTANDING_SECTIONS: usize = 512;
pub const DEFAULT_MAX_INSTRUCTION_SIZE: usize = 64 * 1024;
pub const DEFAULT_IDLE_CAPACITY: usize = 64 * 1024;
pub fn new() -> Self {
Self {
dynamic_table: DynamicTable::new(0),
known_received_count: 0,
max_capacity: DynamicTable::DEFAULT_CAPACITY,
capacity_limit: Self::DEFAULT_CAPACITY_LIMIT,
max_outstanding_sections: Self::DEFAULT_MAX_OUTSTANDING_SECTIONS,
idle_capacity: Self::DEFAULT_IDLE_CAPACITY,
max_instruction_size: Self::DEFAULT_MAX_INSTRUCTION_SIZE,
sections: VecDeque::new(),
section_floor: u64::MAX,
stream_out: Vec::new(),
stream_recv: BytesMut::new(),
matches: Vec::new(),
}
}
pub fn set_max_outstanding_sections(&mut self, max_sections: usize) {
self.max_outstanding_sections = max_sections;
}
pub fn set_max_instruction_size(&mut self, max_size: usize) {
self.max_instruction_size = max_size;
}
pub fn queue(&mut self, instructions: &[EncoderInstruction]) {
for instruction in instructions {
instruction.encode_into(&mut self.stream_out);
}
}
pub fn on_decoder_stream(&mut self, bytes: &[u8]) -> Result<(), Error> {
self.stream_recv.extend_from_slice(bytes);
if self.stream_recv.len() > self.max_instruction_size {
return Err(Error::InstructionTooLarge);
}
loop {
match DecoderInstruction::decode(&self.stream_recv) {
Ok((consumed, instruction)) => {
let _ = self.stream_recv.split_to(consumed);
self.on_decoder_instruction(instruction);
}
Err(Error::Incomplete) => break,
Err(err) => return Err(err),
}
}
Ok(())
}
pub fn set_idle_capacity(&mut self, idle_capacity: usize) {
self.idle_capacity = idle_capacity;
}
pub fn encoder_stream(&self) -> &[u8] {
&self.stream_out
}
pub fn take_encoder_stream(&mut self) -> Vec<u8> {
std::mem::take(&mut self.stream_out)
}
pub fn reclaim_encoder_stream(&mut self, mut buffer: Vec<u8>) {
buffer.clear();
if buffer.capacity() > self.idle_capacity {
buffer.shrink_to(self.idle_capacity / 2);
}
buffer.extend_from_slice(&self.stream_out);
self.stream_out = buffer;
}
pub fn encode(&mut self, stream_id: u64, headers: &[HeaderField]) -> Vec<u8> {
let mut out = Vec::with_capacity(headers.len() * 8 + 16);
self.encode_into(&mut out, stream_id, headers);
out
}
pub fn encode_into(&mut self, out: &mut Vec<u8>, stream_id: u64, headers: &[HeaderField]) {
let mut matches = std::mem::take(&mut self.matches);
matches.clear();
let mut required = 0;
let tracked = self.sections.len() < self.max_outstanding_sections;
self.section_floor = u64::MAX;
for field in headers {
let in_static = StaticTable::find(field);
let (matched, indexed) = match in_static {
Some((index, true)) => (Some((true, index, true)), true),
_ if !tracked => (in_static.map(|(index, _)| (true, index, false)), false),
_ => {
let (dynamic, anywhere) = self.dynamic_table.probe(field, self.known_received_count);
let matched = match dynamic {
Some((absolute, true)) => Some((false, absolute, true)),
_ => in_static
.map(|(index, _)| (true, index, false))
.or(dynamic.map(|(absolute, _)| (false, absolute, false))),
};
(matched, anywhere)
}
};
if let Some((false, absolute, _)) = matched {
required = required.max(absolute.saturating_add(1));
self.section_floor = self.section_floor.min(absolute);
}
if tracked && !indexed && !field.sensitive() {
self.insert(field, matched);
}
matches.push(matched);
}
out.reserve(headers.len() * 8 + 16);
Integer::encode(out, Prefix::encode_insert_count(required, self.max_capacity), 8, 0x00);
Integer::encode(out, 0, 7, 0x00);
for (field, matched) in headers.iter().zip(&matches) {
self.encode_field(out, field, *matched, required);
}
if required > 0 {
self.sections.push_back(Section { stream_id, required, floor: self.section_floor });
}
self.section_floor = u64::MAX;
self.matches = matches;
}
pub fn referenced(&self) -> u64 {
self.sections.iter().map(|section| section.floor).min().unwrap_or(u64::MAX).min(self.section_floor)
}
pub fn reference(&self, field: &HeaderField) -> Option<(bool, u64, bool)> {
let in_static = StaticTable::find(field);
if let Some((index, true)) = in_static {
return Some((true, index, true));
}
let in_dynamic = self
.dynamic_table
.find(field)
.filter(|(absolute, _)| *absolute < self.known_received_count);
if let Some((absolute, true)) = in_dynamic {
return Some((false, absolute, true));
}
in_static
.map(|(index, _)| (true, index, false))
.or(in_dynamic.map(|(absolute, _)| (false, absolute, false)))
}
pub fn insert(&mut self, field: &HeaderField, matched: Option<(bool, u64, bool)>) -> bool {
if !self.dynamic_table.admits(field, self.referenced()) {
return false;
}
let out = &mut self.stream_out;
match matched {
Some((from_static, index, _)) => {
let name_index = if from_static {
index
} else {
self.dynamic_table.inserted_count().saturating_sub(index).saturating_sub(1)
};
Integer::encode(out, name_index, 6, 0x80 | u8::from(from_static) << 6);
StringLiteral::encode_shorter(out, field.value.as_bytes(), 7, 0x00);
}
None => {
StringLiteral::encode_shorter(out, field.name.as_bytes(), 5, 0x40);
StringLiteral::encode_shorter(out, field.value.as_bytes(), 7, 0x00);
}
}
self.dynamic_table.insert(field.clone());
true
}
pub fn encode_field(&self, out: &mut Vec<u8>, field: &HeaderField, matched: Option<(bool, u64, bool)>, base: u64) {
let never = u8::from(field.sensitive());
match matched {
Some((true, index, true)) => Integer::encode(out, index, 6, 0xc0),
Some((false, absolute, true)) => {
Integer::encode(out, Prefix::relative(base, absolute), 6, 0x80);
}
Some((true, index, false)) => {
Integer::encode(out, index, 4, 0x50 | never << 5);
StringLiteral::encode_shorter(out, field.value.as_bytes(), 7, 0x00);
}
Some((false, absolute, false)) => {
Integer::encode(out, Prefix::relative(base, absolute), 4, 0x40 | never << 5);
StringLiteral::encode_shorter(out, field.value.as_bytes(), 7, 0x00);
}
None => {
StringLiteral::encode_shorter(out, field.name.as_bytes(), 3, 0x20 | never << 4);
StringLiteral::encode_shorter(out, field.value.as_bytes(), 7, 0x00);
}
}
}
pub fn on_decoder_instruction(&mut self, instruction: DecoderInstruction) {
match instruction {
DecoderInstruction::SectionAcknowledgment { stream_id } => {
if let Some(offset) = self.sections.iter().position(|section| section.stream_id == stream_id)
&& let Some(section) = self.sections.remove(offset)
{
self.known_received_count = self.known_received_count.max(section.required);
}
}
DecoderInstruction::InsertCountIncrement { increment } => {
self.known_received_count = self.known_received_count.saturating_add(increment);
}
DecoderInstruction::StreamCancellation { stream_id } => self.cancel(stream_id),
}
}
pub fn cancel(&mut self, stream_id: u64) {
self.sections.retain(|section| section.stream_id != stream_id);
}
pub fn outstanding(&self) -> usize {
self.sections.len()
}
pub fn set_max_capacity(&mut self, max_capacity: usize) -> Option<EncoderInstruction> {
self.max_capacity = max_capacity;
let capacity = max_capacity.min(self.capacity_limit);
if capacity == self.dynamic_table.capacity() {
return None;
}
self.dynamic_table.set_capacity(capacity);
Some(EncoderInstruction::SetDynamicTableCapacity { capacity })
}
pub fn set_capacity_limit(&mut self, capacity_limit: usize) -> Option<EncoderInstruction> {
self.capacity_limit = capacity_limit;
let capacity = self.max_capacity.min(capacity_limit);
if capacity >= self.dynamic_table.capacity() {
return None;
}
self.dynamic_table.set_capacity(capacity);
Some(EncoderInstruction::SetDynamicTableCapacity { capacity })
}
pub fn capacity_limit(&self) -> usize {
self.capacity_limit
}
pub fn max_capacity(&self) -> usize {
self.max_capacity
}
pub fn known_received_count(&self) -> u64 {
self.known_received_count
}
pub fn dynamic_table(&self) -> &DynamicTable {
&self.dynamic_table
}
}
impl Default for Encoder {
fn default() -> Self {
Self::new()
}
}
pub struct Decoder {
dynamic_table: DynamicTable,
max_capacity: usize,
max_decoded_size: usize,
max_instruction_size: usize,
max_blocked_streams: usize,
blocked: fields::FieldMap<u64, u64>,
scratch: Vec<u8>,
section: usize,
idle_capacity: usize,
stream_out: Vec<u8>,
stream_recv: BytesMut,
}
impl Decoder {
pub const DEFAULT_MAX_CAPACITY: usize = 4096;
pub const DEFAULT_MAX_DECODED_SIZE: usize = 64 * 1024;
pub const DEFAULT_MAX_INSTRUCTION_SIZE: usize = 64 * 1024;
pub const DEFAULT_MAX_BLOCKED_STREAMS: usize = 16;
pub const DEFAULT_IDLE_CAPACITY: usize = 64 * 1024;
pub fn new() -> Self {
Self {
dynamic_table: DynamicTable::new(Self::DEFAULT_MAX_CAPACITY),
max_capacity: Self::DEFAULT_MAX_CAPACITY,
max_decoded_size: Self::DEFAULT_MAX_DECODED_SIZE,
max_instruction_size: Self::DEFAULT_MAX_INSTRUCTION_SIZE,
max_blocked_streams: Self::DEFAULT_MAX_BLOCKED_STREAMS,
blocked: fields::FieldMap::default(),
scratch: Vec::new(),
section: HeaderField::SECTION_FLOOR,
idle_capacity: Self::DEFAULT_IDLE_CAPACITY,
stream_out: Vec::new(),
stream_recv: BytesMut::new(),
}
}
pub fn set_max_decoded_size(&mut self, max_size: usize) {
self.max_decoded_size = max_size;
}
pub fn set_max_instruction_size(&mut self, max_size: usize) {
self.max_instruction_size = max_size;
}
pub fn set_max_blocked_streams(&mut self, max_streams: usize) {
self.max_blocked_streams = max_streams;
}
pub fn queue(&mut self, instructions: &[DecoderInstruction]) {
for instruction in instructions {
instruction.encode_into(&mut self.stream_out);
}
}
pub fn on_encoder_stream(&mut self, bytes: &[u8]) -> Result<(), Error> {
self.stream_recv.extend_from_slice(bytes);
if self.stream_recv.len() > self.max_instruction_size {
return Err(Error::InstructionTooLarge);
}
loop {
match EncoderInstruction::decode(&self.stream_recv) {
Ok((consumed, instruction)) => {
let _ = self.stream_recv.split_to(consumed);
if let Some(answer) = self.on_encoder_instruction(instruction)? {
answer.encode_into(&mut self.stream_out);
}
}
Err(Error::Incomplete) => break,
Err(err) => return Err(err),
}
}
Ok(())
}
pub fn set_idle_capacity(&mut self, idle_capacity: usize) {
self.idle_capacity = idle_capacity;
}
pub fn decoder_stream(&self) -> &[u8] {
&self.stream_out
}
pub fn take_decoder_stream(&mut self) -> Vec<u8> {
std::mem::take(&mut self.stream_out)
}
pub fn reclaim_decoder_stream(&mut self, mut buffer: Vec<u8>) {
buffer.clear();
if buffer.capacity() > self.idle_capacity {
buffer.shrink_to(self.idle_capacity / 2);
}
buffer.extend_from_slice(&self.stream_out);
self.stream_out = buffer;
}
pub fn unblocked(&self) -> Vec<u64> {
let inserted = self.dynamic_table.inserted_count();
self.blocked.iter().filter(|(_, required)| **required <= inserted).map(|(stream_id, _)| *stream_id).collect()
}
pub fn cancel(&mut self, stream_id: u64) {
self.blocked.remove(&stream_id);
}
pub fn blocked(&self) -> usize {
self.blocked.len()
}
pub fn on_encoder_instruction(&mut self, instruction: EncoderInstruction) -> Result<Option<DecoderInstruction>, Error> {
let field = match instruction {
EncoderInstruction::SetDynamicTableCapacity { capacity } => {
if capacity > self.max_capacity {
return Err(Error::InvalidCapacityUpdate);
}
self.dynamic_table.set_capacity(capacity);
return Ok(None);
}
EncoderInstruction::InsertWithNameReference { from_static, name_index, value } => {
let name = if from_static {
StaticTable::entries()
.get(name_index as usize)
.ok_or(Error::IndexOutOfRange(name_index))?
.name
.clone()
} else {
let absolute = self.dynamic_table.relative(name_index).ok_or(Error::IndexOutOfRange(name_index))?;
self.dynamic_table.get(absolute).ok_or(Error::IndexOutOfRange(absolute))?.name.clone()
};
HeaderField::new(name, Text::from_utf8_lossy(&value))
}
EncoderInstruction::InsertWithLiteralName { name, value } => {
HeaderField::new(Text::from_utf8_lossy(&name), Text::from_utf8_lossy(&value))
}
EncoderInstruction::Duplicate { index } => {
let absolute = self.dynamic_table.relative(index).ok_or(Error::IndexOutOfRange(index))?;
self.dynamic_table.get(absolute).ok_or(Error::IndexOutOfRange(absolute))?.clone()
}
};
if !self.dynamic_table.fits(&field) {
return Err(Error::EntryTooLarge);
}
self.dynamic_table.insert(field);
Ok(Some(DecoderInstruction::InsertCountIncrement { increment: 1 }))
}
pub fn decode(&mut self, stream_id: u64, block: &[u8]) -> Result<(Vec<HeaderField>, Option<DecoderInstruction>), Error> {
let mut scratch = std::mem::take(&mut self.scratch);
let decoded = self.decode_into(stream_id, block, &mut scratch);
self.scratch = scratch;
decoded
}
pub fn decode_into(&mut self, stream_id: u64, block: &[u8], scratch: &mut Vec<u8>) -> Result<(Vec<HeaderField>, Option<DecoderInstruction>), Error> {
let (mut consumed, encoded) = Integer::decode(block, 8)?;
let required = Prefix::decode_insert_count(encoded, self.dynamic_table.inserted_count(), self.max_capacity)?;
if required > self.dynamic_table.inserted_count() {
if !self.blocked.contains_key(&stream_id) && self.blocked.len() >= self.max_blocked_streams {
return Err(Error::TooManyBlockedStreams);
}
self.blocked.insert(stream_id, required);
return Err(Error::Blocked);
}
self.blocked.remove(&stream_id);
let negative = block.get(consumed).ok_or(Error::Incomplete)? & 0x80 != 0;
let (taken, delta) = Integer::decode(&block[consumed..], 7)?;
consumed += taken;
let base = if negative {
required.checked_sub(delta.checked_add(1).ok_or(Error::InvalidBase)?).ok_or(Error::InvalidBase)?
} else {
required.checked_add(delta).ok_or(Error::IntegerOverflow)?
};
let mut headers = Vec::new();
let mut decoded_size = 0usize;
let mut rest = &block[consumed..];
while let Some(first) = rest.first() {
let (consumed, field) = match first {
_ if first & 0x80 != 0 => {
let (consumed, index) = Integer::decode(rest, 6)?;
(consumed, self.resolve(first & 0x40 != 0, base, index)?)
}
_ if first & 0x40 != 0 => {
let (mut consumed, index) = Integer::decode(rest, 4)?;
let name = self.resolve_name(first & 0x10 != 0, base, index)?;
let (taken, value) = StringLiteral::decode_text_into(&rest[consumed..], 7, scratch)?;
consumed += taken;
(consumed, HeaderField::new(name, value))
}
_ if first & 0x20 != 0 => {
let (mut consumed, name) = StringLiteral::decode_text_into(rest, 3, scratch)?;
let (taken, value) = StringLiteral::decode_text_into(&rest[consumed..], 7, scratch)?;
consumed += taken;
(consumed, HeaderField::new(name, value))
}
_ if first & 0x10 != 0 => {
let (consumed, index) = Integer::decode(rest, 4)?;
let absolute = self.dynamic_table.post_base(base, index).ok_or(Error::IndexOutOfRange(index))?;
(consumed, self.dynamic_table.get(absolute).ok_or(Error::IndexOutOfRange(absolute))?.clone())
}
_ => {
let (mut consumed, index) = Integer::decode(rest, 3)?;
let absolute = self.dynamic_table.post_base(base, index).ok_or(Error::IndexOutOfRange(index))?;
let name = self.dynamic_table.get(absolute).ok_or(Error::IndexOutOfRange(absolute))?.name.clone();
let (taken, value) = StringLiteral::decode_text_into(&rest[consumed..], 7, scratch)?;
consumed += taken;
(consumed, HeaderField::new(name, value))
}
};
decoded_size += field.size();
if decoded_size > self.max_decoded_size {
return Err(Error::DecodedSizeExceeded);
}
if headers.is_empty() {
headers.reserve(HeaderField::section_hint(self.section));
}
headers.push(field);
rest = &rest[consumed..];
}
let acknowledgment = (required > 0).then_some(DecoderInstruction::SectionAcknowledgment { stream_id });
self.section = headers.len();
Ok((headers, acknowledgment))
}
pub fn resolve(&self, from_static: bool, base: u64, index: u64) -> Result<HeaderField, Error> {
if from_static {
return StaticTable::entries().get(index as usize).cloned().ok_or(Error::IndexOutOfRange(index));
}
let absolute = self.dynamic_table.indexed(base, index).ok_or(Error::IndexOutOfRange(index))?;
self.dynamic_table.get(absolute).cloned().ok_or(Error::IndexOutOfRange(absolute))
}
pub fn resolve_name(&self, from_static: bool, base: u64, index: u64) -> Result<Text, Error> {
if from_static {
let field = StaticTable::entries().get(index as usize).ok_or(Error::IndexOutOfRange(index))?;
return Ok(field.name.clone());
}
let absolute = self.dynamic_table.indexed(base, index).ok_or(Error::IndexOutOfRange(index))?;
let field = self.dynamic_table.get(absolute).ok_or(Error::IndexOutOfRange(absolute))?;
Ok(field.name.clone())
}
pub fn set_max_capacity(&mut self, max_capacity: usize) {
self.max_capacity = max_capacity;
if self.dynamic_table.capacity() > max_capacity {
self.dynamic_table.set_capacity(max_capacity);
}
}
pub fn dynamic_table(&self) -> &DynamicTable {
&self.dynamic_table
}
}
impl Default for Decoder {
fn default() -> Self {
Self::new()
}
}