1 // Copyright (C) 2019, Cloudflare, Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright notice,
9 //       this list of conditions and the following disclaimer.
10 //
11 //     * Redistributions in binary form must reproduce the above copyright
12 //       notice, this list of conditions and the following disclaimer in the
13 //       documentation and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 use super::Result;
28 
29 use crate::h3::NameValue;
30 
31 use super::INDEXED;
32 use super::LITERAL;
33 use super::LITERAL_WITH_NAME_REF;
34 
35 /// A QPACK encoder.
36 #[derive(Default)]
37 pub struct Encoder {}
38 
39 impl Encoder {
40     /// Creates a new QPACK encoder.
new() -> Encoder41     pub fn new() -> Encoder {
42         Encoder::default()
43     }
44 
45     /// Encodes a list of headers into a QPACK header block.
encode<T: NameValue>( &mut self, headers: &[T], out: &mut [u8], ) -> Result<usize>46     pub fn encode<T: NameValue>(
47         &mut self, headers: &[T], out: &mut [u8],
48     ) -> Result<usize> {
49         let mut b = octets::OctetsMut::with_slice(out);
50 
51         // Required Insert Count.
52         encode_int(0, 0, 8, &mut b)?;
53 
54         // Base.
55         encode_int(0, 0, 7, &mut b)?;
56 
57         for h in headers {
58             match lookup_static(h) {
59                 Some((idx, true)) => {
60                     const STATIC: u8 = 0x40;
61 
62                     // Encode as statically indexed.
63                     encode_int(idx, INDEXED | STATIC, 6, &mut b)?;
64                 },
65 
66                 Some((idx, false)) => {
67                     const STATIC: u8 = 0x10;
68 
69                     // Encode value as literal with static name reference.
70                     encode_int(idx, LITERAL_WITH_NAME_REF | STATIC, 4, &mut b)?;
71                     encode_str(h.value(), 7, &mut b)?;
72                 },
73 
74                 None => {
75                     // Encode as fully literal.
76 
77                     // Huffman-encoding generally saves space but in some cases
78                     // it doesn't, for those just encode the literal string.
79                     match super::huffman::encode_output_length(h.name(), true) {
80                         Ok(len) => {
81                             encode_int(len as u64, LITERAL | 0x08, 3, &mut b)?;
82                             super::huffman::encode(h.name(), &mut b, true)?;
83                         },
84 
85                         Err(super::Error::InflatedHuffmanEncoding) => {
86                             encode_int(
87                                 h.name().len() as u64,
88                                 LITERAL,
89                                 3,
90                                 &mut b,
91                             )?;
92                             b.put_bytes(&h.name().to_ascii_lowercase())?;
93                         },
94 
95                         Err(e) => return Err(e),
96                     }
97 
98                     encode_str(h.value(), 7, &mut b)?;
99                 },
100             };
101         }
102 
103         Ok(b.off())
104     }
105 }
106 
lookup_static<T: NameValue>(h: &T) -> Option<(u64, bool)>107 fn lookup_static<T: NameValue>(h: &T) -> Option<(u64, bool)> {
108     let mut name_match = None;
109 
110     for (i, e) in super::static_table::STATIC_TABLE.iter().enumerate() {
111         // Match header name first.
112         if h.name().len() == e.0.len() && h.name().eq_ignore_ascii_case(e.0) {
113             // No header value to match, return early.
114             if e.1.is_empty() {
115                 return Some((i as u64, false));
116             }
117 
118             // Match header value.
119             if h.value().len() == e.1.len() && h.value() == e.1 {
120                 return Some((i as u64, true));
121             }
122 
123             // Remember name-only match for later, but keep searching.
124             name_match = Some((i as u64, false));
125         }
126     }
127 
128     name_match
129 }
130 
encode_int( mut v: u64, first: u8, prefix: usize, b: &mut octets::OctetsMut, ) -> Result<()>131 fn encode_int(
132     mut v: u64, first: u8, prefix: usize, b: &mut octets::OctetsMut,
133 ) -> Result<()> {
134     let mask = 2u64.pow(prefix as u32) - 1;
135 
136     // Encode I on N bits.
137     if v < mask {
138         b.put_u8(first | v as u8)?;
139         return Ok(());
140     }
141 
142     // Encode (2^N - 1) on N bits.
143     b.put_u8(first | mask as u8)?;
144 
145     v -= mask;
146 
147     while v >= 128 {
148         // Encode (I % 128 + 128) on 8 bits.
149         b.put_u8((v % 128 + 128) as u8)?;
150 
151         v >>= 7;
152     }
153 
154     // Encode I on 8 bits.
155     b.put_u8(v as u8)?;
156 
157     Ok(())
158 }
159 
encode_str(v: &[u8], prefix: usize, b: &mut octets::OctetsMut) -> Result<()>160 fn encode_str(v: &[u8], prefix: usize, b: &mut octets::OctetsMut) -> Result<()> {
161     // Huffman-encoding generally saves space but in some cases it doesn't, for
162     // those just encode the literal string.
163     match super::huffman::encode_output_length(v, false) {
164         Ok(len) => {
165             encode_int(len as u64, 0x80, prefix, b)?;
166             super::huffman::encode(v, b, false)?;
167         },
168 
169         Err(super::Error::InflatedHuffmanEncoding) => {
170             encode_int(v.len() as u64, 0, prefix, b)?;
171             b.put_bytes(v)?;
172         },
173 
174         Err(e) => return Err(e),
175     }
176 
177     Ok(())
178 }
179 
180 #[cfg(test)]
181 mod tests {
182     use super::*;
183 
184     #[test]
encode_int1()185     fn encode_int1() {
186         let expected = [0b01010];
187         let mut encoded = [0; 1];
188         let mut b = octets::OctetsMut::with_slice(&mut encoded);
189 
190         assert!(encode_int(10, 0, 5, &mut b).is_ok());
191 
192         assert_eq!(expected, encoded);
193     }
194 
195     #[test]
encode_int2()196     fn encode_int2() {
197         let expected = [0b11111, 0b10011010, 0b00001010];
198         let mut encoded = [0; 3];
199         let mut b = octets::OctetsMut::with_slice(&mut encoded);
200 
201         assert!(encode_int(1337, 0, 5, &mut b).is_ok());
202 
203         assert_eq!(expected, encoded);
204     }
205 
206     #[test]
encode_int3()207     fn encode_int3() {
208         let expected = [0b101010];
209         let mut encoded = [0; 1];
210         let mut b = octets::OctetsMut::with_slice(&mut encoded);
211 
212         assert!(encode_int(42, 0, 8, &mut b).is_ok());
213 
214         assert_eq!(expected, encoded);
215     }
216 }
217