1 mod table;
2
3 use self::table::{DECODE_TABLE, ENCODE_TABLE};
4 use crate::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.split())
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