H3: encode headers from inner connection

This commit is contained in:
stammw
2019-05-11 15:05:14 +02:00
committed by Dirkjan Ochtman
parent bd8cc901e6
commit 0bb05fc93b
2 changed files with 111 additions and 2 deletions
+1
View File
@@ -32,6 +32,7 @@ bitlab = "0.8.1"
lazy_static = "1"
err-derive = "0.1.5"
slog = "2.1"
http = "0.1"
[dev-dependencies]
proptest = "0.9.1"
+110 -2
View File
@@ -1,11 +1,119 @@
use bytes::BytesMut;
use http::HeaderMap;
use quinn_proto::StreamId;
use crate::proto::frame::HeadersFrame;
use crate::qpack::{self, DynamicTable, EncoderError, HeaderField};
use crate::Settings;
pub struct Connection {
settings: Settings,
#[allow(dead_code)]
local_settings: Settings,
remote_settings: Option<Settings>,
decoder_table: DynamicTable,
encoder_table: DynamicTable,
pending_encoder: BytesMut,
}
impl Connection {
pub fn new(settings: Settings) -> Self {
Self { settings }
Self {
local_settings: settings,
remote_settings: None,
decoder_table: DynamicTable::new(),
encoder_table: DynamicTable::new(),
pending_encoder: BytesMut::with_capacity(2048),
}
}
pub fn encode_header(
&mut self,
stream_id: &StreamId,
headers: &HeaderMap,
) -> Result<HeadersFrame> {
if let Some(ref s) = self.remote_settings {
if headers.len() as u64 > s.max_header_list_size {
return Err(Error::HeaderListTooLarge);
}
}
let headers = headers.into_iter().map(HeaderField::from);
let mut block = BytesMut::with_capacity(512);
qpack::encode(
&mut self.encoder_table.encoder(stream_id.0),
&mut block,
&mut self.pending_encoder,
headers,
)?;
Ok(HeadersFrame {
encoded: block.into(),
})
}
}
#[derive(Debug, PartialEq)]
pub enum Error {
HeaderListTooLarge,
EncodeError { reason: EncoderError },
}
impl From<EncoderError> for Error {
fn from(err: EncoderError) -> Error {
Error::EncodeError { reason: err }
}
}
#[cfg(test)]
mod tests {
use super::*;
use http::header::{HeaderMap, HeaderValue};
#[test]
fn encode_no_dynamic() {
let mut header = HeaderMap::new();
header.append("hello", HeaderValue::from_static("text/html"));
let mut conn = Connection::new(Settings::default());
let mut conn = Connection::default();
assert_matches!(conn.encode_header(&StreamId(1), &header), Ok(_));
assert!(conn.pending_encoder.is_empty());
}
#[test]
fn encode_with_dynamic() {
let mut header = HeaderMap::new();
header.append("hello", HeaderValue::from_static("text/html"));
let mut conn = Connection::new(Settings::default());
conn.encoder_table
.inserter()
.set_max_mem_size(2048)
.expect("set table size");
conn.encoder_table
.set_max_blocked(12usize)
.expect("set max blocked");
assert_matches!(conn.encode_header(&StreamId(1), &header), Ok(_));
assert!(!conn.pending_encoder.is_empty());
}
#[test]
fn encode_too_many_fields() {
let mut header = HeaderMap::new();
for _ in 0..5 {
header.append("hello", HeaderValue::from_static("text/html"));
}
let mut conn = Connection::new(Settings::default());
conn.remote_settings = Some(Settings {
max_header_list_size: 4,
..Settings::default()
});
assert_eq!(
conn.encode_header(&StreamId(1), &header),
Err(Error::HeaderListTooLarge)
);
}
}