use std::borrow::Cow;
use std::num::Wrapping;
use std::sync::{Arc, RwLock};
use crate::{HeaderName, HeaderValue, Http2Error, WebResult};
use algorithm::buf::Bt;
use super::huffman::{HuffmanDecoder, HuffmanDecoderError};
use super::HeaderIndex;
enum FieldRepresentation {
Indexed,
LiteralWithIncrementalIndexing,
SizeUpdate,
LiteralNeverIndexed,
LiteralWithoutIndexing,
}
impl FieldRepresentation {
fn new(octet: u8) -> FieldRepresentation {
if octet & 128 == 128 {
FieldRepresentation::Indexed
} else if octet & 64 == 64 {
FieldRepresentation::LiteralWithIncrementalIndexing
} else if octet & 32 == 32 {
FieldRepresentation::SizeUpdate
} else if octet & 16 == 16 {
FieldRepresentation::LiteralNeverIndexed
} else {
FieldRepresentation::LiteralWithoutIndexing
}
}
}
#[derive(PartialEq, Copy, Clone, Debug)]
pub enum IntegerDecodingError {
TooManyOctets,
ValueTooLarge,
NotEnoughOctets,
InvalidPrefix,
}
#[derive(PartialEq, Copy, Clone, Debug)]
pub enum StringDecodingError {
NotEnoughOctets,
HuffmanDecoderError(HuffmanDecoderError),
}
#[derive(PartialEq, Copy, Clone, Debug)]
pub enum DecoderError {
HeaderIndexOutOfBounds,
IntegerDecodingError(IntegerDecodingError),
StringDecodingError(StringDecodingError),
InvalidMaxDynamicSize,
}
#[derive(Debug)]
pub struct Decoder {
pub index: Arc<RwLock<HeaderIndex>>,
}
impl Decoder {
pub fn new() -> Decoder {
Decoder {
index: Arc::new(RwLock::new(HeaderIndex::new())),
}
}
pub fn new_index(index: Arc<RwLock<HeaderIndex>>) -> Decoder {
Decoder { index }
}
pub fn decode<B: Bt>(&mut self, buf: &mut B) -> WebResult<Vec<(HeaderName, HeaderValue)>> {
let mut header_list = Vec::new();
self.decode_with_cb(buf, |n, v| {
header_list.push((n.into_owned(), v.into_owned()))
})?;
Ok(header_list)
}
pub fn decode_with_cb<F, B: Bt>(&mut self, buf: &mut B, mut cb: F) -> WebResult<()>
where
F: FnMut(Cow<HeaderName>, Cow<HeaderValue>),
{
while buf.has_remaining() {
let initial_octet = buf.peek().unwrap();
let buffer_leftover = buf.chunk();
let consumed = match FieldRepresentation::new(initial_octet) {
FieldRepresentation::Indexed => {
let consumed = (self.decode_indexed(initial_octet, |name, value| {
cb(Cow::Borrowed(name), Cow::Borrowed(value));
}))?;
consumed
}
FieldRepresentation::LiteralWithIncrementalIndexing => {
let ((name, value), consumed) = {
let ((name, value), consumed) =
self.decode_literal(buffer_leftover, true)?;
cb(Cow::Borrowed(&name), Cow::Borrowed(&value));
let name = name.clone();
let value = value.clone();
((name, value), consumed)
};
self.index.write().unwrap().add_header(name, value);
consumed
}
FieldRepresentation::LiteralWithoutIndexing => {
let ((name, value), consumed) = (self.decode_literal(buffer_leftover, false))?;
cb(Cow::Owned(name), Cow::Owned(value));
consumed
}
FieldRepresentation::LiteralNeverIndexed => {
let ((name, value), consumed) = (self.decode_literal(buffer_leftover, false))?;
cb(Cow::Owned(name), Cow::Owned(value));
consumed
}
FieldRepresentation::SizeUpdate => {
0
}
};
buf.advance(consumed);
}
Ok(())
}
fn decode_integer(buf: &[u8], prefix_size: u8) -> WebResult<(usize, usize)> {
if prefix_size < 1 || prefix_size > 8 {
return Err(Http2Error::into(DecoderError::IntegerDecodingError(
IntegerDecodingError::InvalidPrefix,
)));
}
if buf.len() < 1 {
return Err(Http2Error::into(DecoderError::IntegerDecodingError(
IntegerDecodingError::NotEnoughOctets,
)));
}
let Wrapping(mask) = if prefix_size == 8 {
Wrapping(0xFF)
} else {
Wrapping(1u8 << prefix_size) - Wrapping(1)
};
let mut value = (buf[0] & mask) as usize;
if value < (mask as usize) {
return Ok((value, 1));
}
let mut total = 1;
let mut m = 0;
let octet_limit = 5;
for &b in buf[1..].iter() {
total += 1;
value += ((b & 127) as usize) * (1 << m);
m += 7;
if b & 128 != 128 {
return Ok((value, total));
}
if total == octet_limit {
return Err(Http2Error::into(DecoderError::IntegerDecodingError(
IntegerDecodingError::TooManyOctets,
)));
}
}
Err(Http2Error::into(DecoderError::IntegerDecodingError(
IntegerDecodingError::NotEnoughOctets,
)))
}
fn decode_string<'a>(buf: &'a [u8]) -> WebResult<(Cow<'a, [u8]>, usize)> {
let (len, consumed) = Self::decode_integer(buf, 7)?;
if consumed + len > buf.len() {
return Err(Http2Error::into(DecoderError::StringDecodingError(
StringDecodingError::NotEnoughOctets,
)));
}
let raw_string = &buf[consumed..consumed + len];
if buf[0] & 128 == 128 {
let mut decoder = HuffmanDecoder::new();
let decoded = match decoder.decode(raw_string) {
Err(e) => {
return Err(e);
}
Ok(res) => res,
};
Ok((Cow::Owned(decoded), consumed + len))
} else {
Ok((Cow::Borrowed(raw_string), consumed + len))
}
}
fn decode_literal(
&self,
buf: &[u8],
index: bool,
) -> WebResult<((HeaderName, HeaderValue), usize)> {
let prefix = if index { 6 } else { 4 };
let (table_index, mut consumed) = Self::decode_integer(buf, prefix)?;
let name = if table_index == 0 {
let (name, name_len) = Self::decode_string(&buf[consumed..])?;
consumed += name_len;
HeaderName::from_bytes(&name).unwrap()
} else {
let mut name = HeaderName::Stand("");
self.get_from_table(table_index, |n, _| {
name = n.clone();
})?;
name
};
let (value, value_len) = Self::decode_string(&buf[consumed..])?;
consumed += value_len;
Ok(((name, HeaderValue::from_bytes(&value)), consumed))
}
fn decode_indexed<F>(&self, index: u8, call: F) -> WebResult<usize>
where
F: FnOnce(&HeaderName, &HeaderValue),
{
let index = index & 0x7f;
let header = self.index.read().unwrap();
let (name, value) = header
.get_from_index(index as usize)
.ok_or(Http2Error::into(DecoderError::HeaderIndexOutOfBounds))?;
call(name, value);
Ok(1)
}
fn get_from_table<F>(&self, index: usize, call: F) -> WebResult<()>
where
F: FnOnce(&HeaderName, &HeaderValue),
{
let header = self.index.read().unwrap();
let (name, value) = header
.get_from_index(index as usize)
.ok_or(Http2Error::into(DecoderError::HeaderIndexOutOfBounds))?;
call(name, value);
Ok(())
}
}