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