httlib_huffman/parser/mod.rs
1//! Provides features for parsing [Huffman code] table provided by the [HPACK]
2//! documentation.
3//!
4//! [HPACK] provides a pre-created [Huffman code] table for encoding [ASCII]
5//! characters to the Huffman sequence. This Huffman code was generated from
6//! statistics obtained on a large sample of HTTP headers.
7//!
8//! The parser module is responsible for parsing the [Huffman code] table into
9//! the static Rust source code. This module was used to create the ENCODE_TABLE
10//! constant which can be found in the `encode::table` module.
11//!
12//! You will probably never use this module while developing applications.
13//!
14//! [ASCII]: https://en.wikipedia.org/wiki/ASCII
15//! [HPACK]: https://tools.ietf.org/html/rfc7541
16//! [Huffman code]: https://tools.ietf.org/html/rfc7541#appendix-B
17
18/// Parses the HPACK's static Huffman table. The function expects data to be in
19/// format as provided by the spec (7.2).
20///
21/// **Example:**
22///
23/// ```rust
24/// use std::fs;
25/// use std::path::Path;
26/// use httlib_huffman::parser::parse;
27///
28/// let path = Path::new("assets/hpack-huffman.txt");
29/// let data = fs::read_to_string(path).expect("Can't read file.");
30/// let codings = parse(&data);
31/// ```
32pub fn parse(data: &str) -> Vec<(u16, u32)> {
33 let lines = data.lines();
34 let mut codings = vec![];
35
36 for line in lines {
37 let coding = parse_line(line);
38 codings.push(coding);
39 }
40
41 codings
42}
43
44/// Parses a single line of the static Huffman table. The output returned
45/// contains a tuple of the number of bits for the code representing the symbol
46/// and Huffman LSB value.
47fn parse_line(line: &str) -> (u16, u32) {
48
49 let mut msb = vec![];
50 for &b in &line.as_bytes()[12..45] {
51 match b {
52 b'1' => msb.push(true),
53 b'0' => msb.push(false),
54 b'|' | b' ' => {}
55 _ => panic!("unexpected byte; {:?}", b),
56 }
57 }
58
59 let lsb = u32::from_str_radix(&line[50..59].trim().to_string(), 16).expect("Invalid hex");
60 let len = msb.len() as u16;
61
62 (len, lsb)
63}
64
65#[cfg(test)]
66mod tests {
67 use std::fs;
68 use std::path::Path;
69 use super::*;
70
71 /// Should read the text file `assets/hpack-huffman.txt` and parse the
72 /// content into 2-dimensional table that can be used in Rust code.
73 #[test]
74 fn parses_huffman_table() {
75 let path = Path::new("assets/hpack-huffman.txt");
76 let data = fs::read_to_string(path).expect("Can't read file.");
77 let table = parse(&data);
78
79 assert_eq!(table.len(), 257);
80
81 let item = table[10];
82 assert_eq!(item.0, 30);
83 assert_eq!(item.1, 0x3ffffffc);
84
85 let item = table[32];
86 assert_eq!(item.0, 6);
87 assert_eq!(item.1, 0x14);
88
89 let item = table.last().unwrap();
90 assert_eq!(item.0, 30);
91 assert_eq!(item.1, 0x3fffffff);
92 }
93}