QPACK: rewrite prefixed string using codec traits

This commit is contained in:
stammw
2018-12-31 08:22:11 +01:00
committed by Dirkjan Ochtman
parent 76cd18b7c8
commit ed37636805
4 changed files with 140 additions and 9 deletions
+2 -1
View File
@@ -26,4 +26,5 @@ lazy_static = "1"
quinn-proto = { path = "../quinn-proto", version = "0.1.0" }
[dev-dependencies]
proptest = "0.6.0"
proptest = "0.6.0"
assert_matches = "1.1"
+4
View File
@@ -5,5 +5,9 @@ extern crate lazy_static;
#[macro_use]
extern crate proptest;
#[cfg(test)]
#[macro_use]
extern crate assert_matches;
extern crate quinn_proto;
mod qpack;
+3 -3
View File
@@ -2,7 +2,7 @@ use bytes::{Buf, BufMut};
use quinn_proto::coding::{self, BufExt, BufMutExt};
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub enum Error {
Overflow,
UnexpectedEnd,
@@ -130,9 +130,9 @@ mod test {
#[test]
#[should_panic]
fn size_too_big_of_size() {
let mut buf = vec![];
let buf = vec![];
let mut read = Cursor::new(&buf);
super::decode(9, &mut read);
super::decode(9, &mut read).unwrap();
}
#[cfg(target_pointer_width = "64")]
+131 -5
View File
@@ -1,12 +1,138 @@
// This is only here because qpack is new and quinn no uses it yet.
// TODO remove allow dead code
#![allow(unused_imports)]
#![allow(unused_imports, dead_code)]
pub mod bitwin;
mod bitwin;
mod decode;
mod encode;
use std::borrow::Cow;
pub use self::bitwin::BitWindow;
pub mod decode;
pub use self::decode::{DecodeIter, Error as HuffmanDecodingError, HpackStringDecode};
pub mod encode;
pub use self::encode::{Error as HuffmanEncodingError, HpackStringEncode};
use crate::qpack::prefix_int::{self, Error as IntegerError};
use bytes::{Buf, BufMut};
use quinn_proto::coding::{self, BufExt, BufMutExt};
#[derive(Debug, PartialEq)]
pub enum Error {
UnexpectedEnd,
Integer(IntegerError),
HuffmanDecoding(HuffmanDecodingError),
HuffmanEncoding(HuffmanEncodingError),
}
pub fn decode<B: Buf>(size: u8, buf: &mut B) -> Result<Vec<u8>, Error> {
let (flags, len) = prefix_int::decode(size - 1, buf)?;
if buf.remaining() < len {
return Err(Error::UnexpectedEnd);
}
let payload = buf.take(len);
let value = if flags & 1 == 0 {
payload.collect()
} else {
let mut decoded = Vec::new();
for byte in payload.collect::<Vec<u8>>().hpack_decode() {
decoded.push(byte?);
}
decoded
};
Ok(value)
}
pub fn encode<B: BufMut>(size: u8, flags: u8, value: &[u8], buf: &mut B) -> Result<(), Error> {
let encoded = Vec::from(value).hpack_encode()?;
prefix_int::encode(size - 1, flags << 1 | 1, encoded.len(), buf);
for byte in encoded {
buf.write(byte);
}
Ok(())
}
impl From<HuffmanEncodingError> for Error {
fn from(error: HuffmanEncodingError) -> Self {
Error::HuffmanEncoding(error)
}
}
impl From<IntegerError> for Error {
fn from(error: IntegerError) -> Self {
Error::Integer(error)
}
}
impl From<HuffmanDecodingError> for Error {
fn from(error: HuffmanDecodingError) -> Self {
Error::HuffmanDecoding(error)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn codec_6() {
let mut buf = Vec::new();
encode(6, 0b01, b"name without ref", &mut buf).unwrap();
let mut read = Cursor::new(&buf);
assert_eq!(
&buf,
&[
0b0110_1100,
168,
116,
149,
79,
6,
76,
231,
181,
42,
88,
89,
127
]
);
assert_eq!(decode(6, &mut read).unwrap(), b"name without ref");
}
#[test]
fn codec_8() {
let mut buf = Vec::new();
encode(8, 0b01, b"name with ref", &mut buf).unwrap();
let mut read = Cursor::new(&buf);
assert_eq!(
&buf,
&[0b100_01010, 168, 116, 149, 79, 6, 76, 234, 88, 89, 127]
);
assert_eq!(decode(8, &mut read).unwrap(), b"name with ref");
}
#[test]
fn codec_8_empty() {
let mut buf = Vec::new();
encode(8, 0b01, b"", &mut buf).unwrap();
let mut read = Cursor::new(&buf);
assert_eq!(&buf, &[0b100_00000]);
assert_eq!(decode(8, &mut read).unwrap(), b"");
}
#[test]
fn decode_non_huffman() {
let buf = vec![0b0100_0011, b'b', b'a', b'r'];
let mut read = Cursor::new(&buf);
assert_eq!(decode(6, &mut read).unwrap(), b"bar");
}
#[test]
fn decode_too_short() {
let buf = vec![0b0100_0011, b'b', b'a'];
let mut read = Cursor::new(&buf);
assert_matches!(decode(6, &mut read), Err(Error::UnexpectedEnd));
}
}