Restructure hpack tests

This commit is contained in:
Carl Lerche
2017-06-29 23:11:35 -07:00
parent 63ffea61f5
commit a7b92d5ec2
8 changed files with 680 additions and 234 deletions

596
src/hpack/test/fixture.rs Normal file
View File

@@ -0,0 +1,596 @@
extern crate bytes;
extern crate hex;
extern crate serde_json;
use hpack::{Header, Decoder, Encoder};
use self::bytes::BytesMut;
use self::hex::FromHex;
use self::serde_json::Value;
use std::fs::File;
use std::io::prelude::*;
use std::io::Cursor;
use std::path::Path;
use std::str;
fn test_fixture(path: &Path) {
let mut file = File::open(path).unwrap();
let mut data = String::new();
file.read_to_string(&mut data).unwrap();
let story: Value = serde_json::from_str(&data).unwrap();
test_story(story);
}
fn test_story(story: Value) {
let story = story.as_object().unwrap();
if let Some(cases) = story.get("cases") {
let mut cases: Vec<_> = cases.as_array().unwrap().iter()
.map(|case| {
let case = case.as_object().unwrap();
let size = case.get("header_table_size")
.map(|v| v.as_u64().unwrap() as usize);
let wire = case.get("wire").unwrap().as_str().unwrap();
let wire: Vec<u8> = FromHex::from_hex(wire.as_bytes()).unwrap();
let expect: Vec<_> = case.get("headers").unwrap()
.as_array().unwrap().iter()
.map(|h| {
let h = h.as_object().unwrap();
let (name, val) = h.iter().next().unwrap();
(name.clone(), val.as_str().unwrap().to_string())
})
.collect();
Case {
seqno: case.get("seqno").unwrap().as_u64().unwrap(),
wire: wire,
expect: expect,
header_table_size: size,
}
})
.collect();
cases.sort_by_key(|c| c.seqno);
let mut decoder = Decoder::default();
// First, check decoding against the fixtures
for case in &cases {
let mut expect = case.expect.clone();
if let Some(size) = case.header_table_size {
decoder.queue_size_update(size);
}
decoder.decode(&mut Cursor::new(case.wire.clone().into()), |e| {
let (name, value) = expect.remove(0);
assert_eq!(name, key_str(&e));
assert_eq!(value, value_str(&e));
}).unwrap();
assert_eq!(0, expect.len());
}
let mut encoder = Encoder::default();
let mut decoder = Decoder::default();
// Now, encode the headers
for case in &cases {
let mut buf = BytesMut::with_capacity(64 * 1024);
if let Some(size) = case.header_table_size {
encoder.update_max_size(size);
decoder.queue_size_update(size);
}
let mut input: Vec<_> = case.expect.iter().map(|&(ref name, ref value)| {
Header::new(name.clone().into(), value.clone().into()).unwrap().into()
}).collect();
encoder.encode(None, &mut input.clone().into_iter(), &mut buf);
decoder.decode(&mut Cursor::new(buf.into()), |e| {
assert_eq!(e, input.remove(0).reify().unwrap());
}).unwrap();
assert_eq!(0, input.len());
}
}
}
struct Case {
seqno: u64,
wire: Vec<u8>,
expect: Vec<(String, String)>,
header_table_size: Option<usize>,
}
fn key_str(e: &Header) -> &str {
match *e {
Header::Field { ref name, .. } => name.as_str(),
Header::Authority(..) => ":authority",
Header::Method(..) => ":method",
Header::Scheme(..) => ":scheme",
Header::Path(..) => ":path",
Header::Status(..) => ":status",
}
}
fn value_str(e: &Header) -> &str {
match *e {
Header::Field { ref value, .. } => value.to_str().unwrap(),
Header::Authority(ref v) => &**v,
Header::Method(ref m) => m.as_str(),
Header::Scheme(ref v) => &**v,
Header::Path(ref v) => &**v,
Header::Status(ref v) => v.as_str(),
}
}
macro_rules! fixture_mod {
($module:ident => {
$(
($fn:ident, $path:expr);
)+
}) => {
mod $module {
$(
#[test]
fn $fn() {
let path = ::std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("fixtures/hpack")
.join($path);
super::test_fixture(path.as_ref());
}
)+
}
}
}
fixture_mod!(
haskell_http2_linear_huffman => {
(story_00, "haskell-http2-linear-huffman/story_00.json");
(story_01, "haskell-http2-linear-huffman/story_01.json");
(story_02, "haskell-http2-linear-huffman/story_02.json");
(story_03, "haskell-http2-linear-huffman/story_03.json");
(story_04, "haskell-http2-linear-huffman/story_04.json");
(story_05, "haskell-http2-linear-huffman/story_05.json");
(story_06, "haskell-http2-linear-huffman/story_06.json");
(story_07, "haskell-http2-linear-huffman/story_07.json");
(story_08, "haskell-http2-linear-huffman/story_08.json");
(story_09, "haskell-http2-linear-huffman/story_09.json");
(story_10, "haskell-http2-linear-huffman/story_10.json");
(story_11, "haskell-http2-linear-huffman/story_11.json");
(story_12, "haskell-http2-linear-huffman/story_12.json");
(story_13, "haskell-http2-linear-huffman/story_13.json");
(story_14, "haskell-http2-linear-huffman/story_14.json");
(story_15, "haskell-http2-linear-huffman/story_15.json");
(story_16, "haskell-http2-linear-huffman/story_16.json");
(story_17, "haskell-http2-linear-huffman/story_17.json");
(story_18, "haskell-http2-linear-huffman/story_18.json");
(story_19, "haskell-http2-linear-huffman/story_19.json");
(story_20, "haskell-http2-linear-huffman/story_20.json");
(story_21, "haskell-http2-linear-huffman/story_21.json");
(story_22, "haskell-http2-linear-huffman/story_22.json");
(story_23, "haskell-http2-linear-huffman/story_23.json");
(story_24, "haskell-http2-linear-huffman/story_24.json");
(story_25, "haskell-http2-linear-huffman/story_25.json");
(story_26, "haskell-http2-linear-huffman/story_26.json");
(story_27, "haskell-http2-linear-huffman/story_27.json");
(story_28, "haskell-http2-linear-huffman/story_28.json");
(story_29, "haskell-http2-linear-huffman/story_29.json");
(story_30, "haskell-http2-linear-huffman/story_30.json");
(story_31, "haskell-http2-linear-huffman/story_31.json");
}
);
fixture_mod!(
python_hpack => {
(story_00, "python-hpack/story_00.json");
(story_01, "python-hpack/story_01.json");
(story_02, "python-hpack/story_02.json");
(story_03, "python-hpack/story_03.json");
(story_04, "python-hpack/story_04.json");
(story_05, "python-hpack/story_05.json");
(story_06, "python-hpack/story_06.json");
(story_07, "python-hpack/story_07.json");
(story_08, "python-hpack/story_08.json");
(story_09, "python-hpack/story_09.json");
(story_10, "python-hpack/story_10.json");
(story_11, "python-hpack/story_11.json");
(story_12, "python-hpack/story_12.json");
(story_13, "python-hpack/story_13.json");
(story_14, "python-hpack/story_14.json");
(story_15, "python-hpack/story_15.json");
(story_16, "python-hpack/story_16.json");
(story_17, "python-hpack/story_17.json");
(story_18, "python-hpack/story_18.json");
(story_19, "python-hpack/story_19.json");
(story_20, "python-hpack/story_20.json");
(story_21, "python-hpack/story_21.json");
(story_22, "python-hpack/story_22.json");
(story_23, "python-hpack/story_23.json");
(story_24, "python-hpack/story_24.json");
(story_25, "python-hpack/story_25.json");
(story_26, "python-hpack/story_26.json");
(story_27, "python-hpack/story_27.json");
(story_28, "python-hpack/story_28.json");
(story_29, "python-hpack/story_29.json");
(story_30, "python-hpack/story_30.json");
(story_31, "python-hpack/story_31.json");
}
);
fixture_mod!(
nghttp2_16384_4096 => {
(story_00, "nghttp2-16384-4096/story_00.json");
(story_01, "nghttp2-16384-4096/story_01.json");
(story_02, "nghttp2-16384-4096/story_02.json");
(story_03, "nghttp2-16384-4096/story_03.json");
(story_04, "nghttp2-16384-4096/story_04.json");
(story_05, "nghttp2-16384-4096/story_05.json");
(story_06, "nghttp2-16384-4096/story_06.json");
(story_07, "nghttp2-16384-4096/story_07.json");
(story_08, "nghttp2-16384-4096/story_08.json");
(story_09, "nghttp2-16384-4096/story_09.json");
(story_10, "nghttp2-16384-4096/story_10.json");
(story_11, "nghttp2-16384-4096/story_11.json");
(story_12, "nghttp2-16384-4096/story_12.json");
(story_13, "nghttp2-16384-4096/story_13.json");
(story_14, "nghttp2-16384-4096/story_14.json");
(story_15, "nghttp2-16384-4096/story_15.json");
(story_16, "nghttp2-16384-4096/story_16.json");
(story_17, "nghttp2-16384-4096/story_17.json");
(story_18, "nghttp2-16384-4096/story_18.json");
(story_19, "nghttp2-16384-4096/story_19.json");
(story_20, "nghttp2-16384-4096/story_20.json");
(story_21, "nghttp2-16384-4096/story_21.json");
(story_22, "nghttp2-16384-4096/story_22.json");
(story_23, "nghttp2-16384-4096/story_23.json");
(story_24, "nghttp2-16384-4096/story_24.json");
(story_25, "nghttp2-16384-4096/story_25.json");
(story_26, "nghttp2-16384-4096/story_26.json");
(story_27, "nghttp2-16384-4096/story_27.json");
(story_28, "nghttp2-16384-4096/story_28.json");
(story_29, "nghttp2-16384-4096/story_29.json");
(story_30, "nghttp2-16384-4096/story_30.json");
}
);
fixture_mod!(
node_http2_hpack => {
(story_00, "node-http2-hpack/story_00.json");
(story_01, "node-http2-hpack/story_01.json");
(story_02, "node-http2-hpack/story_02.json");
(story_03, "node-http2-hpack/story_03.json");
(story_04, "node-http2-hpack/story_04.json");
(story_05, "node-http2-hpack/story_05.json");
(story_06, "node-http2-hpack/story_06.json");
(story_07, "node-http2-hpack/story_07.json");
(story_08, "node-http2-hpack/story_08.json");
(story_09, "node-http2-hpack/story_09.json");
(story_10, "node-http2-hpack/story_10.json");
(story_11, "node-http2-hpack/story_11.json");
(story_12, "node-http2-hpack/story_12.json");
(story_13, "node-http2-hpack/story_13.json");
(story_14, "node-http2-hpack/story_14.json");
(story_15, "node-http2-hpack/story_15.json");
(story_16, "node-http2-hpack/story_16.json");
(story_17, "node-http2-hpack/story_17.json");
(story_18, "node-http2-hpack/story_18.json");
(story_19, "node-http2-hpack/story_19.json");
(story_20, "node-http2-hpack/story_20.json");
(story_21, "node-http2-hpack/story_21.json");
(story_22, "node-http2-hpack/story_22.json");
(story_23, "node-http2-hpack/story_23.json");
(story_24, "node-http2-hpack/story_24.json");
(story_25, "node-http2-hpack/story_25.json");
(story_26, "node-http2-hpack/story_26.json");
(story_27, "node-http2-hpack/story_27.json");
(story_28, "node-http2-hpack/story_28.json");
(story_29, "node-http2-hpack/story_29.json");
(story_30, "node-http2-hpack/story_30.json");
(story_31, "node-http2-hpack/story_31.json");
}
);
fixture_mod!(
nghttp2_change_table_size => {
(story_00, "nghttp2-change-table-size/story_00.json");
(story_01, "nghttp2-change-table-size/story_01.json");
(story_02, "nghttp2-change-table-size/story_02.json");
(story_03, "nghttp2-change-table-size/story_03.json");
(story_04, "nghttp2-change-table-size/story_04.json");
(story_05, "nghttp2-change-table-size/story_05.json");
(story_06, "nghttp2-change-table-size/story_06.json");
(story_07, "nghttp2-change-table-size/story_07.json");
(story_08, "nghttp2-change-table-size/story_08.json");
(story_09, "nghttp2-change-table-size/story_09.json");
(story_10, "nghttp2-change-table-size/story_10.json");
(story_11, "nghttp2-change-table-size/story_11.json");
(story_12, "nghttp2-change-table-size/story_12.json");
(story_13, "nghttp2-change-table-size/story_13.json");
(story_14, "nghttp2-change-table-size/story_14.json");
(story_15, "nghttp2-change-table-size/story_15.json");
(story_16, "nghttp2-change-table-size/story_16.json");
(story_17, "nghttp2-change-table-size/story_17.json");
(story_18, "nghttp2-change-table-size/story_18.json");
(story_19, "nghttp2-change-table-size/story_19.json");
(story_20, "nghttp2-change-table-size/story_20.json");
(story_21, "nghttp2-change-table-size/story_21.json");
(story_22, "nghttp2-change-table-size/story_22.json");
(story_23, "nghttp2-change-table-size/story_23.json");
(story_24, "nghttp2-change-table-size/story_24.json");
(story_25, "nghttp2-change-table-size/story_25.json");
(story_26, "nghttp2-change-table-size/story_26.json");
(story_27, "nghttp2-change-table-size/story_27.json");
(story_28, "nghttp2-change-table-size/story_28.json");
(story_29, "nghttp2-change-table-size/story_29.json");
(story_30, "nghttp2-change-table-size/story_30.json");
}
);
fixture_mod!(
haskell_http2_static_huffman => {
(story_00, "haskell-http2-static-huffman/story_00.json");
(story_01, "haskell-http2-static-huffman/story_01.json");
(story_02, "haskell-http2-static-huffman/story_02.json");
(story_03, "haskell-http2-static-huffman/story_03.json");
(story_04, "haskell-http2-static-huffman/story_04.json");
(story_05, "haskell-http2-static-huffman/story_05.json");
(story_06, "haskell-http2-static-huffman/story_06.json");
(story_07, "haskell-http2-static-huffman/story_07.json");
(story_08, "haskell-http2-static-huffman/story_08.json");
(story_09, "haskell-http2-static-huffman/story_09.json");
(story_10, "haskell-http2-static-huffman/story_10.json");
(story_11, "haskell-http2-static-huffman/story_11.json");
(story_12, "haskell-http2-static-huffman/story_12.json");
(story_13, "haskell-http2-static-huffman/story_13.json");
(story_14, "haskell-http2-static-huffman/story_14.json");
(story_15, "haskell-http2-static-huffman/story_15.json");
(story_16, "haskell-http2-static-huffman/story_16.json");
(story_17, "haskell-http2-static-huffman/story_17.json");
(story_18, "haskell-http2-static-huffman/story_18.json");
(story_19, "haskell-http2-static-huffman/story_19.json");
(story_20, "haskell-http2-static-huffman/story_20.json");
(story_21, "haskell-http2-static-huffman/story_21.json");
(story_22, "haskell-http2-static-huffman/story_22.json");
(story_23, "haskell-http2-static-huffman/story_23.json");
(story_24, "haskell-http2-static-huffman/story_24.json");
(story_25, "haskell-http2-static-huffman/story_25.json");
(story_26, "haskell-http2-static-huffman/story_26.json");
(story_27, "haskell-http2-static-huffman/story_27.json");
(story_28, "haskell-http2-static-huffman/story_28.json");
(story_29, "haskell-http2-static-huffman/story_29.json");
(story_30, "haskell-http2-static-huffman/story_30.json");
(story_31, "haskell-http2-static-huffman/story_31.json");
}
);
fixture_mod!(
haskell_http2_naive_huffman => {
(story_00, "haskell-http2-naive-huffman/story_00.json");
(story_01, "haskell-http2-naive-huffman/story_01.json");
(story_02, "haskell-http2-naive-huffman/story_02.json");
(story_03, "haskell-http2-naive-huffman/story_03.json");
(story_04, "haskell-http2-naive-huffman/story_04.json");
(story_05, "haskell-http2-naive-huffman/story_05.json");
(story_06, "haskell-http2-naive-huffman/story_06.json");
(story_07, "haskell-http2-naive-huffman/story_07.json");
(story_08, "haskell-http2-naive-huffman/story_08.json");
(story_09, "haskell-http2-naive-huffman/story_09.json");
(story_10, "haskell-http2-naive-huffman/story_10.json");
(story_11, "haskell-http2-naive-huffman/story_11.json");
(story_12, "haskell-http2-naive-huffman/story_12.json");
(story_13, "haskell-http2-naive-huffman/story_13.json");
(story_14, "haskell-http2-naive-huffman/story_14.json");
(story_15, "haskell-http2-naive-huffman/story_15.json");
(story_16, "haskell-http2-naive-huffman/story_16.json");
(story_17, "haskell-http2-naive-huffman/story_17.json");
(story_18, "haskell-http2-naive-huffman/story_18.json");
(story_19, "haskell-http2-naive-huffman/story_19.json");
(story_20, "haskell-http2-naive-huffman/story_20.json");
(story_21, "haskell-http2-naive-huffman/story_21.json");
(story_22, "haskell-http2-naive-huffman/story_22.json");
(story_23, "haskell-http2-naive-huffman/story_23.json");
(story_24, "haskell-http2-naive-huffman/story_24.json");
(story_25, "haskell-http2-naive-huffman/story_25.json");
(story_26, "haskell-http2-naive-huffman/story_26.json");
(story_27, "haskell-http2-naive-huffman/story_27.json");
(story_28, "haskell-http2-naive-huffman/story_28.json");
(story_29, "haskell-http2-naive-huffman/story_29.json");
(story_30, "haskell-http2-naive-huffman/story_30.json");
(story_31, "haskell-http2-naive-huffman/story_31.json");
}
);
fixture_mod!(
haskell_http2_naive => {
(story_00, "haskell-http2-naive/story_00.json");
(story_01, "haskell-http2-naive/story_01.json");
(story_02, "haskell-http2-naive/story_02.json");
(story_03, "haskell-http2-naive/story_03.json");
(story_04, "haskell-http2-naive/story_04.json");
(story_05, "haskell-http2-naive/story_05.json");
(story_06, "haskell-http2-naive/story_06.json");
(story_07, "haskell-http2-naive/story_07.json");
(story_08, "haskell-http2-naive/story_08.json");
(story_09, "haskell-http2-naive/story_09.json");
(story_10, "haskell-http2-naive/story_10.json");
(story_11, "haskell-http2-naive/story_11.json");
(story_12, "haskell-http2-naive/story_12.json");
(story_13, "haskell-http2-naive/story_13.json");
(story_14, "haskell-http2-naive/story_14.json");
(story_15, "haskell-http2-naive/story_15.json");
(story_16, "haskell-http2-naive/story_16.json");
(story_17, "haskell-http2-naive/story_17.json");
(story_18, "haskell-http2-naive/story_18.json");
(story_19, "haskell-http2-naive/story_19.json");
(story_20, "haskell-http2-naive/story_20.json");
(story_21, "haskell-http2-naive/story_21.json");
(story_22, "haskell-http2-naive/story_22.json");
(story_23, "haskell-http2-naive/story_23.json");
(story_24, "haskell-http2-naive/story_24.json");
(story_25, "haskell-http2-naive/story_25.json");
(story_26, "haskell-http2-naive/story_26.json");
(story_27, "haskell-http2-naive/story_27.json");
(story_28, "haskell-http2-naive/story_28.json");
(story_29, "haskell-http2-naive/story_29.json");
(story_30, "haskell-http2-naive/story_30.json");
(story_31, "haskell-http2-naive/story_31.json");
}
);
fixture_mod!(
haskell_http2_static => {
(story_00, "haskell-http2-static/story_00.json");
(story_01, "haskell-http2-static/story_01.json");
(story_02, "haskell-http2-static/story_02.json");
(story_03, "haskell-http2-static/story_03.json");
(story_04, "haskell-http2-static/story_04.json");
(story_05, "haskell-http2-static/story_05.json");
(story_06, "haskell-http2-static/story_06.json");
(story_07, "haskell-http2-static/story_07.json");
(story_08, "haskell-http2-static/story_08.json");
(story_09, "haskell-http2-static/story_09.json");
(story_10, "haskell-http2-static/story_10.json");
(story_11, "haskell-http2-static/story_11.json");
(story_12, "haskell-http2-static/story_12.json");
(story_13, "haskell-http2-static/story_13.json");
(story_14, "haskell-http2-static/story_14.json");
(story_15, "haskell-http2-static/story_15.json");
(story_16, "haskell-http2-static/story_16.json");
(story_17, "haskell-http2-static/story_17.json");
(story_18, "haskell-http2-static/story_18.json");
(story_19, "haskell-http2-static/story_19.json");
(story_20, "haskell-http2-static/story_20.json");
(story_21, "haskell-http2-static/story_21.json");
(story_22, "haskell-http2-static/story_22.json");
(story_23, "haskell-http2-static/story_23.json");
(story_24, "haskell-http2-static/story_24.json");
(story_25, "haskell-http2-static/story_25.json");
(story_26, "haskell-http2-static/story_26.json");
(story_27, "haskell-http2-static/story_27.json");
(story_28, "haskell-http2-static/story_28.json");
(story_29, "haskell-http2-static/story_29.json");
(story_30, "haskell-http2-static/story_30.json");
(story_31, "haskell-http2-static/story_31.json");
}
);
fixture_mod!(
nghttp2 => {
(story_00, "nghttp2/story_00.json");
(story_01, "nghttp2/story_01.json");
(story_02, "nghttp2/story_02.json");
(story_03, "nghttp2/story_03.json");
(story_04, "nghttp2/story_04.json");
(story_05, "nghttp2/story_05.json");
(story_06, "nghttp2/story_06.json");
(story_07, "nghttp2/story_07.json");
(story_08, "nghttp2/story_08.json");
(story_09, "nghttp2/story_09.json");
(story_10, "nghttp2/story_10.json");
(story_11, "nghttp2/story_11.json");
(story_12, "nghttp2/story_12.json");
(story_13, "nghttp2/story_13.json");
(story_14, "nghttp2/story_14.json");
(story_15, "nghttp2/story_15.json");
(story_16, "nghttp2/story_16.json");
(story_17, "nghttp2/story_17.json");
(story_18, "nghttp2/story_18.json");
(story_19, "nghttp2/story_19.json");
(story_20, "nghttp2/story_20.json");
(story_21, "nghttp2/story_21.json");
(story_22, "nghttp2/story_22.json");
(story_23, "nghttp2/story_23.json");
(story_24, "nghttp2/story_24.json");
(story_25, "nghttp2/story_25.json");
(story_26, "nghttp2/story_26.json");
(story_27, "nghttp2/story_27.json");
(story_28, "nghttp2/story_28.json");
(story_29, "nghttp2/story_29.json");
(story_30, "nghttp2/story_30.json");
(story_31, "nghttp2/story_31.json");
}
);
fixture_mod!(
haskell_http2_linear => {
(story_00, "haskell-http2-linear/story_00.json");
(story_01, "haskell-http2-linear/story_01.json");
(story_02, "haskell-http2-linear/story_02.json");
(story_03, "haskell-http2-linear/story_03.json");
(story_04, "haskell-http2-linear/story_04.json");
(story_05, "haskell-http2-linear/story_05.json");
(story_06, "haskell-http2-linear/story_06.json");
(story_07, "haskell-http2-linear/story_07.json");
(story_08, "haskell-http2-linear/story_08.json");
(story_09, "haskell-http2-linear/story_09.json");
(story_10, "haskell-http2-linear/story_10.json");
(story_11, "haskell-http2-linear/story_11.json");
(story_12, "haskell-http2-linear/story_12.json");
(story_13, "haskell-http2-linear/story_13.json");
(story_14, "haskell-http2-linear/story_14.json");
(story_15, "haskell-http2-linear/story_15.json");
(story_16, "haskell-http2-linear/story_16.json");
(story_17, "haskell-http2-linear/story_17.json");
(story_18, "haskell-http2-linear/story_18.json");
(story_19, "haskell-http2-linear/story_19.json");
(story_20, "haskell-http2-linear/story_20.json");
(story_21, "haskell-http2-linear/story_21.json");
(story_22, "haskell-http2-linear/story_22.json");
(story_23, "haskell-http2-linear/story_23.json");
(story_24, "haskell-http2-linear/story_24.json");
(story_25, "haskell-http2-linear/story_25.json");
(story_26, "haskell-http2-linear/story_26.json");
(story_27, "haskell-http2-linear/story_27.json");
(story_28, "haskell-http2-linear/story_28.json");
(story_29, "haskell-http2-linear/story_29.json");
(story_30, "haskell-http2-linear/story_30.json");
(story_31, "haskell-http2-linear/story_31.json");
}
);
fixture_mod!(
go_hpack => {
(story_00, "go-hpack/story_00.json");
(story_01, "go-hpack/story_01.json");
(story_02, "go-hpack/story_02.json");
(story_03, "go-hpack/story_03.json");
(story_04, "go-hpack/story_04.json");
(story_05, "go-hpack/story_05.json");
(story_06, "go-hpack/story_06.json");
(story_07, "go-hpack/story_07.json");
(story_08, "go-hpack/story_08.json");
(story_09, "go-hpack/story_09.json");
(story_10, "go-hpack/story_10.json");
(story_11, "go-hpack/story_11.json");
(story_12, "go-hpack/story_12.json");
(story_13, "go-hpack/story_13.json");
(story_14, "go-hpack/story_14.json");
(story_15, "go-hpack/story_15.json");
(story_16, "go-hpack/story_16.json");
(story_17, "go-hpack/story_17.json");
(story_18, "go-hpack/story_18.json");
(story_19, "go-hpack/story_19.json");
(story_20, "go-hpack/story_20.json");
(story_21, "go-hpack/story_21.json");
(story_22, "go-hpack/story_22.json");
(story_23, "go-hpack/story_23.json");
(story_24, "go-hpack/story_24.json");
(story_25, "go-hpack/story_25.json");
(story_26, "go-hpack/story_26.json");
(story_27, "go-hpack/story_27.json");
(story_28, "go-hpack/story_28.json");
(story_29, "go-hpack/story_29.json");
(story_30, "go-hpack/story_30.json");
(story_31, "go-hpack/story_31.json");
}
);

348
src/hpack/test/fuzz.rs Normal file
View File

@@ -0,0 +1,348 @@
extern crate bytes;
extern crate quickcheck;
extern crate rand;
use hpack::{Header, Decoder, Encoder, Encode};
use http::header::{HeaderName, HeaderValue};
use self::bytes::BytesMut;
use self::quickcheck::{QuickCheck, Arbitrary, Gen, TestResult};
use self::rand::{StdRng, Rng, SeedableRng};
use std::io::Cursor;
const MAX_CHUNK: usize = 2 * 1024;
#[test]
fn hpack_fuzz() {
fn prop(fuzz: FuzzHpack) -> TestResult {
fuzz.run();
TestResult::from_bool(true)
}
QuickCheck::new()
.tests(100)
.quickcheck(prop as fn(FuzzHpack) -> TestResult)
}
#[derive(Debug, Clone)]
struct FuzzHpack {
// The magic seed that makes the test case reproducible
seed: [usize; 4],
// The set of headers to encode / decode
frames: Vec<HeaderFrame>,
// The list of chunk sizes to do it in
chunks: Vec<usize>,
// Number of times reduced
reduced: usize,
}
#[derive(Debug, Clone)]
struct HeaderFrame {
resizes: Vec<usize>,
headers: Vec<Header<Option<HeaderName>>>,
}
impl FuzzHpack {
fn new(seed: [usize; 4]) -> FuzzHpack {
// Seed the RNG
let mut rng = StdRng::from_seed(&seed);
// Generates a bunch of source headers
let mut source: Vec<Header<Option<HeaderName>>> = vec![];
for _ in 0..2000 {
source.push(gen_header(&mut rng));
}
// Actual test run headers
let num: usize = rng.gen_range(40, 500);
let mut frames: Vec<HeaderFrame> = vec![];
let mut added = 0;
let skew: i32 = rng.gen_range(1, 5);
// Rough number of headers to add
while added < num {
let mut frame = HeaderFrame {
resizes: vec![],
headers: vec![],
};
match rng.gen_range(0, 20) {
0 => {
// Two resizes
let high = rng.gen_range(128, MAX_CHUNK * 2);
let low = rng.gen_range(0, high);
frame.resizes.extend(&[low, high]);
}
1...3 => {
frame.resizes.push(rng.gen_range(128, MAX_CHUNK * 2));
}
_ => {}
}
for _ in 0..rng.gen_range(1, (num - added) + 1) {
added += 1;
let x: f64 = rng.gen_range(0.0, 1.0);
let x = x.powi(skew);
let i = (x * source.len() as f64) as usize;
frame.headers.push(source[i].clone());
}
frames.push(frame);
}
// Now, generate the buffer sizes used to encode
let mut chunks = vec![];
for _ in 0..rng.gen_range(0, 100) {
chunks.push(rng.gen_range(0, MAX_CHUNK));
}
FuzzHpack {
seed: seed,
frames: frames,
chunks: chunks,
reduced: 0,
}
}
fn run(self) {
let mut chunks = self.chunks;
let frames = self.frames;
let mut expect = vec![];
let mut encoder = Encoder::default();
let mut decoder = Decoder::default();
for frame in frames {
expect.extend(frame.headers.clone());
let mut index = None;
let mut input = frame.headers.into_iter();
let mut buf = BytesMut::with_capacity(
chunks.pop().unwrap_or(MAX_CHUNK));
if let Some(max) = frame.resizes.iter().max() {
decoder.queue_size_update(*max);
}
// Apply resizes
for resize in &frame.resizes {
encoder.update_max_size(*resize);
}
loop {
match encoder.encode(index.take(), &mut input, &mut buf) {
Encode::Full => break,
Encode::Partial(i) => {
index = Some(i);
// Decode the chunk!
decoder.decode(&mut Cursor::new(buf.into()), |e| {
assert_eq!(e, expect.remove(0).reify().unwrap());
}).unwrap();
buf = BytesMut::with_capacity(
chunks.pop().unwrap_or(MAX_CHUNK));
}
}
}
// Decode the chunk!
decoder.decode(&mut Cursor::new(buf.into()), |e| {
assert_eq!(e, expect.remove(0).reify().unwrap());
}).unwrap();
}
assert_eq!(0, expect.len());
}
}
impl Arbitrary for FuzzHpack {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
FuzzHpack::new(quickcheck::Rng::gen(g))
}
}
fn gen_header(g: &mut StdRng) -> Header<Option<HeaderName>> {
use http::StatusCode;
use http::method::{self, Method};
if g.gen_weighted_bool(10) {
match g.next_u32() % 5 {
0 => {
let value = gen_string(g, 4, 20);
Header::Authority(value.into())
}
1 => {
let method = match g.next_u32() % 6 {
0 => method::GET,
1 => method::POST,
2 => method::PUT,
3 => method::PATCH,
4 => method::DELETE,
5 => {
let n: usize = g.gen_range(3, 7);
let bytes: Vec<u8> = (0..n).map(|_| {
g.choose(b"ABCDEFGHIJKLMNOPQRSTUVWXYZ").unwrap().clone()
}).collect();
Method::from_bytes(&bytes).unwrap()
}
_ => unreachable!(),
};
Header::Method(method)
}
2 => {
let value = match g.next_u32() % 2 {
0 => "http",
1 => "https",
_ => unreachable!(),
};
Header::Scheme(value.into())
}
3 => {
let value = match g.next_u32() % 100 {
0 => "/".to_string(),
1 => "/index.html".to_string(),
_ => gen_string(g, 2, 20),
};
Header::Path(value.into())
}
4 => {
let status = (g.gen::<u16>() % 500) + 100;
Header::Status(StatusCode::from_u16(status).unwrap())
}
_ => unreachable!(),
}
} else {
let name = gen_header_name(g);
let mut value = gen_header_value(g);
if g.gen_weighted_bool(30) {
value.set_sensitive(true);
}
Header::Field { name: Some(name), value: value }
}
}
fn gen_header_name(g: &mut StdRng) -> HeaderName {
use http::header;
if g.gen_weighted_bool(2) {
g.choose(&[
header::ACCEPT,
header::ACCEPT_CHARSET,
header::ACCEPT_ENCODING,
header::ACCEPT_LANGUAGE,
header::ACCEPT_PATCH,
header::ACCEPT_RANGES,
header::ACCESS_CONTROL_ALLOW_CREDENTIALS,
header::ACCESS_CONTROL_ALLOW_HEADERS,
header::ACCESS_CONTROL_ALLOW_METHODS,
header::ACCESS_CONTROL_ALLOW_ORIGIN,
header::ACCESS_CONTROL_EXPOSE_HEADERS,
header::ACCESS_CONTROL_MAX_AGE,
header::ACCESS_CONTROL_REQUEST_HEADERS,
header::ACCESS_CONTROL_REQUEST_METHOD,
header::AGE,
header::ALLOW,
header::ALT_SVC,
header::AUTHORIZATION,
header::CACHE_CONTROL,
header::CONNECTION,
header::CONTENT_DISPOSITION,
header::CONTENT_ENCODING,
header::CONTENT_LANGUAGE,
header::CONTENT_LENGTH,
header::CONTENT_LOCATION,
header::CONTENT_MD5,
header::CONTENT_RANGE,
header::CONTENT_SECURITY_POLICY,
header::CONTENT_SECURITY_POLICY_REPORT_ONLY,
header::CONTENT_TYPE,
header::COOKIE,
header::DNT,
header::DATE,
header::ETAG,
header::EXPECT,
header::EXPIRES,
header::FORWARDED,
header::FROM,
header::HOST,
header::IF_MATCH,
header::IF_MODIFIED_SINCE,
header::IF_NONE_MATCH,
header::IF_RANGE,
header::IF_UNMODIFIED_SINCE,
header::LAST_MODIFIED,
header::KEEP_ALIVE,
header::LINK,
header::LOCATION,
header::MAX_FORWARDS,
header::ORIGIN,
header::PRAGMA,
header::PROXY_AUTHENTICATE,
header::PROXY_AUTHORIZATION,
header::PUBLIC_KEY_PINS,
header::PUBLIC_KEY_PINS_REPORT_ONLY,
header::RANGE,
header::REFERER,
header::REFERRER_POLICY,
header::REFRESH,
header::RETRY_AFTER,
header::SERVER,
header::SET_COOKIE,
header::STRICT_TRANSPORT_SECURITY,
header::TE,
header::TK,
header::TRAILER,
header::TRANSFER_ENCODING,
header::TSV,
header::USER_AGENT,
header::UPGRADE,
header::UPGRADE_INSECURE_REQUESTS,
header::VARY,
header::VIA,
header::WARNING,
header::WWW_AUTHENTICATE,
header::X_CONTENT_TYPE_OPTIONS,
header::X_DNS_PREFETCH_CONTROL,
header::X_FRAME_OPTIONS,
header::X_XSS_PROTECTION,
]).unwrap().clone()
} else {
let value = gen_string(g, 1, 25);
HeaderName::from_bytes(value.as_bytes()).unwrap()
}
}
fn gen_header_value(g: &mut StdRng) -> HeaderValue {
let value = gen_string(g, 0, 70);
HeaderValue::try_from_bytes(value.as_bytes()).unwrap()
}
fn gen_string(g: &mut StdRng, min: usize, max: usize) -> String {
let bytes: Vec<_> = (min..max).map(|_| {
// Chars to pick from
g.choose(b"ABCDEFGHIJKLMNOPQRSTUVabcdefghilpqrstuvwxyz----").unwrap().clone()
}).collect();
String::from_utf8(bytes).unwrap()
}

2
src/hpack/test/mod.rs Normal file
View File

@@ -0,0 +1,2 @@
mod fixture;
mod fuzz;