use crate::{
h3::{H3Error, H3ErrorCode},
headers::{
entry_name::EntryName,
qpack::{
decoder_dynamic_table::DecoderDynamicTable,
instruction::encoder::{EncoderInstruction, parse},
static_table::static_entry,
},
},
};
use futures_lite::io::AsyncRead;
use std::borrow::Cow;
impl DecoderDynamicTable {
pub(crate) async fn run_reader<T: AsyncRead + Unpin + Send>(
&self,
stream: &mut T,
) -> Result<(), H3Error> {
let result = self.run_reader_inner(stream).await;
match &result {
Err(H3Error::Protocol(code)) => {
log::debug!("QPACK encoder stream: protocol error: {code}");
self.fail(*code);
}
Err(H3Error::Io(e)) => {
log::debug!("QPACK encoder stream: I/O error: {e}");
self.fail(H3ErrorCode::QpackEncoderStreamError);
}
Ok(()) => {
log::trace!("QPACK encoder stream: closed cleanly");
}
}
result
}
async fn run_reader_inner<T>(&self, stream: &mut T) -> Result<(), H3Error>
where
T: AsyncRead + Unpin + Send,
{
let max_entry_size = self.max_capacity();
while let Some(instruction) = parse(max_entry_size, stream).await? {
self.apply(instruction)?;
}
log::trace!("QPACK encoder stream: EOF");
Ok(())
}
fn apply(&self, instruction: EncoderInstruction) -> Result<(), H3Error> {
match instruction {
EncoderInstruction::SetCapacity(capacity) => {
log::trace!("QPACK encoder: Set Dynamic Table Capacity {capacity}");
self.set_capacity(capacity).inspect_err(|e| {
log::error!("QPACK encoder: set_capacity({capacity}) failed: {e:?}");
})
}
EncoderInstruction::InsertWithStaticNameRef { name_index, value } => {
let (static_name, _) = static_entry(name_index).map_err(|e| {
log::error!("QPACK encoder: static_entry({name_index}) failed: {e:?}");
H3ErrorCode::QpackEncoderStreamError
})?;
let name = EntryName::from(*static_name);
log::trace!(
"QPACK encoder: Insert With Name Reference (static) [{name}: {}]",
String::from_utf8_lossy(&value)
);
self.insert(name, Cow::Owned(value))
}
EncoderInstruction::InsertWithDynamicNameRef {
relative_index,
value,
} => {
let name = self.name_at_relative(relative_index).ok_or_else(|| {
log::error!("QPACK encoder: name_at_relative({relative_index}) returned None");
H3ErrorCode::QpackEncoderStreamError
})?;
log::trace!(
"QPACK encoder: Insert With Name Reference (dynamic) [{name}: {}]",
String::from_utf8_lossy(&value)
);
self.insert(name, Cow::Owned(value))
}
EncoderInstruction::InsertWithLiteralName { name, value } => {
log::trace!(
"QPACK encoder: Insert With Literal Name [{name}: {}]",
String::from_utf8_lossy(&value)
);
self.insert(name, Cow::Owned(value))
}
EncoderInstruction::Duplicate { relative_index } => {
log::trace!("QPACK encoder: Duplicate index {relative_index}");
self.duplicate(relative_index).inspect_err(|e| {
log::error!("QPACK encoder: duplicate({relative_index}) failed: {e:?}");
})
}
}
}
}