1 mod table;
2 
3 use self::table::{DECODE_TABLE, ENCODE_TABLE};
4 use hpack::{DecoderError, EncoderError};
5 
6 use bytes::{BufMut, BytesMut};
7 
8 // Constructed in the generated `table.rs` file
9 struct Decoder {
10     state: usize,
11     maybe_eos: bool,
12 }
13 
14 // These flags must match the ones in genhuff.rs
15 
16 const MAYBE_EOS: u8 = 1;
17 const DECODED: u8 = 2;
18 const ERROR: u8 = 4;
19 
decode(src: &[u8], buf: &mut BytesMut) -> Result<BytesMut, DecoderError>20 pub fn decode(src: &[u8], buf: &mut BytesMut) -> Result<BytesMut, DecoderError> {
21     let mut decoder = Decoder::new();
22 
23     // Max compression ratio is >= 0.5
24     buf.reserve(src.len() << 1);
25 
26     for b in src {
27         if let Some(b) = decoder.decode4(b >> 4)? {
28             buf.put_u8(b);
29         }
30 
31         if let Some(b) = decoder.decode4(b & 0xf)? {
32             buf.put_u8(b);
33         }
34     }
35 
36     if !decoder.is_final() {
37         return Err(DecoderError::InvalidHuffmanCode);
38     }
39 
40     Ok(buf.take())
41 }
42 
43 // TODO: return error when there is not enough room to encode the value
encode<B: BufMut>(src: &[u8], dst: &mut B) -> Result<(), EncoderError>44 pub fn encode<B: BufMut>(src: &[u8], dst: &mut B) -> Result<(), EncoderError> {
45     let mut bits: u64 = 0;
46     let mut bits_left = 40;
47     let mut rem = dst.remaining_mut();
48 
49     for &b in src {
50         let (nbits, code) = ENCODE_TABLE[b as usize];
51 
52         bits |= code << (bits_left - nbits);
53         bits_left -= nbits;
54 
55         while bits_left <= 32 {
56             if rem == 0 {
57                 return Err(EncoderError::BufferOverflow);
58             }
59 
60             dst.put_u8((bits >> 32) as u8);
61 
62             bits <<= 8;
63             bits_left += 8;
64             rem -= 1;
65         }
66     }
67 
68     if bits_left != 40 {
69         if rem == 0 {
70             return Err(EncoderError::BufferOverflow);
71         }
72 
73         // This writes the EOS token
74         bits |= (1 << bits_left) - 1;
75         dst.put_u8((bits >> 32) as u8);
76     }
77 
78     Ok(())
79 }
80 
81 impl Decoder {
new() -> Decoder82     fn new() -> Decoder {
83         Decoder {
84             state: 0,
85             maybe_eos: false,
86         }
87     }
88 
89     // Decodes 4 bits
decode4(&mut self, input: u8) -> Result<Option<u8>, DecoderError>90     fn decode4(&mut self, input: u8) -> Result<Option<u8>, DecoderError> {
91         // (next-state, byte, flags)
92         let (next, byte, flags) = DECODE_TABLE[self.state][input as usize];
93 
94         if flags & ERROR == ERROR {
95             // Data followed the EOS marker
96             return Err(DecoderError::InvalidHuffmanCode);
97         }
98 
99         let mut ret = None;
100 
101         if flags & DECODED == DECODED {
102             ret = Some(byte);
103         }
104 
105         self.state = next;
106         self.maybe_eos = flags & MAYBE_EOS == MAYBE_EOS;
107 
108         Ok(ret)
109     }
110 
is_final(&self) -> bool111     fn is_final(&self) -> bool {
112         self.state == 0 || self.maybe_eos
113     }
114 }
115 
116 #[cfg(test)]
117 mod test {
118     use super::*;
119 
decode(src: &[u8]) -> Result<BytesMut, DecoderError>120     fn decode(src: &[u8]) -> Result<BytesMut, DecoderError> {
121         let mut buf = BytesMut::new();
122         super::decode(src, &mut buf)
123     }
124 
125     #[test]
decode_single_byte()126     fn decode_single_byte() {
127         assert_eq!("o", decode(&[0b00111111]).unwrap());
128         assert_eq!("0", decode(&[0x0 + 7]).unwrap());
129         assert_eq!("A", decode(&[(0x21 << 2) + 3]).unwrap());
130     }
131 
132     #[test]
single_char_multi_byte()133     fn single_char_multi_byte() {
134         assert_eq!("#", decode(&[255, 160 + 15]).unwrap());
135         assert_eq!("$", decode(&[255, 200 + 7]).unwrap());
136         assert_eq!("\x0a", decode(&[255, 255, 255, 240 + 3]).unwrap());
137     }
138 
139     #[test]
multi_char()140     fn multi_char() {
141         assert_eq!("!0", decode(&[254, 1]).unwrap());
142         assert_eq!(" !", decode(&[0b01010011, 0b11111000]).unwrap());
143     }
144 
145     #[test]
encode_single_byte()146     fn encode_single_byte() {
147         let mut dst = Vec::with_capacity(1);
148 
149         encode(b"o", &mut dst).unwrap();
150         assert_eq!(&dst[..], &[0b00111111]);
151 
152         dst.clear();
153         encode(b"0", &mut dst).unwrap();
154         assert_eq!(&dst[..], &[0x0 + 7]);
155 
156         dst.clear();
157         encode(b"A", &mut dst).unwrap();
158         assert_eq!(&dst[..], &[(0x21 << 2) + 3]);
159     }
160 
161     #[test]
encode_decode_str()162     fn encode_decode_str() {
163         const DATA: &'static [&'static str] = &[
164             "hello world",
165             ":method",
166             ":scheme",
167             ":authority",
168             "yahoo.co.jp",
169             "GET",
170             "http",
171             ":path",
172             "/images/top/sp2/cmn/logo-ns-130528.png",
173             "example.com",
174             "hpack-test",
175             "xxxxxxx1",
176             "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0",
177             "accept",
178             "Accept",
179             "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
180             "cookie",
181             "B=76j09a189a6h4&b=3&s=0b",
182             "TE",
183             "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi non bibendum libero. \
184              Etiam ultrices lorem ut.",
185         ];
186 
187         for s in DATA {
188             let mut dst = Vec::with_capacity(s.len());
189 
190             encode(s.as_bytes(), &mut dst).unwrap();
191 
192             let decoded = decode(&dst).unwrap();
193 
194             assert_eq!(&decoded[..], s.as_bytes());
195         }
196     }
197 
198     #[test]
encode_decode_u8()199     fn encode_decode_u8() {
200         const DATA: &'static [&'static [u8]] =
201             &[b"\0", b"\0\0\0", b"\0\x01\x02\x03\x04\x05", b"\xFF\xF8"];
202 
203         for s in DATA {
204             let mut dst = Vec::with_capacity(s.len());
205 
206             encode(s, &mut dst).unwrap();
207 
208             let decoded = decode(&dst).unwrap();
209 
210             assert_eq!(&decoded[..], &s[..]);
211         }
212     }
213 }
214