1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 //! [Header Field Representation] implementation of [HPACK].
15 //!
16 //! [Header Field Representation]: https://www.rfc-editor.org/rfc/rfc7541.html#section-2.4
17 //! [HPACK]: https://httpwg.org/specs/rfc7541.html
18 //!
19 //! # Description from RFC7541
20 //! An encoded header field can be represented either as an index or as a
21 //! literal.
22 //!
23 //! An [indexed representation] defines a header field as a reference to an
24 //! entry in either the static table or the dynamic table.
25 //!
26 //! A [literal representation] defines a header field by specifying its
27 //! name and value. The header field name can be represented literally or as a
28 //! reference to an entry in either the static table or the dynamic table.
29 //! The header field value is represented literally.
30 //!
31 //! Three different literal representations are defined:
32 //!
33 //! - A literal representation that adds the header field as a new entry at the
34 //! beginning of the dynamic table (see
35 //! [Literal Header Field with Incremental Indexing]).
36 //!
37 //! - A literal representation that does not add the header field to the dynamic
38 //! table (see [Literal Header Field without Indexing]).
39 //!
40 //! - A literal representation that does not add the header field to the dynamic
41 //! table, with the additional stipulation that this header field always use a
42 //! literal representation, in particular when re-encoded by an intermediary
43 //! (see [Literal Header Field Never Indexed]. This representation is intended
44 //! for protecting header field values that are not to be put at risk by
45 //! compressing them (see [Never-Indexed Literals] for more details).
46 //!
47 //! The selection of one of these literal representations can be guided by
48 //! security considerations, in order to protect sensitive header field values
49 //! (see [Probing Dynamic Table State]).
50 //!
51 //! The literal representation of a header field name or of a header field value
52 //! can encode the sequence of octets either directly or using a static
53 //! Huffman code (see [String Literal Representation]).
54 //!
55 //! [Literal Header Field Never Indexed]: https://www.rfc-editor.org/rfc/rfc7541.html#section-6.2.3
56 //! [Literal Header Field with Incremental Indexing]: https://www.rfc-editor.org/rfc/rfc7541.html#section-6.2.1
57 //! [Literal Header Field without Indexing]: https://www.rfc-editor.org/rfc/rfc7541.html#section-6.2.2
58 //! [Never-Indexed Literals]: https://www.rfc-editor.org/rfc/rfc7541.html#section-7.1.3
59 //! [Probing Dynamic Table State]: https://www.rfc-editor.org/rfc/rfc7541.html#section-7.1
60 //! [String Literal Representation]: https://www.rfc-editor.org/rfc/rfc7541.html#section-5.2
61 //! [indexed representation]: https://www.rfc-editor.org/rfc/rfc7541.html#section-6.1
62 //! [literal representation]: https://www.rfc-editor.org/rfc/rfc7541.html#section-6.2
63 
64 mod decoder;
65 mod encoder;
66 
67 pub(crate) use decoder::{ReprDecStateHolder, ReprDecodeState, ReprDecoder};
68 pub(crate) use encoder::{ReprEncStateHolder, ReprEncodeState, ReprEncoder};
69 
70 /// Definition and [binary format] of each of the different
71 /// [header field representations] and the [dynamic table size update]
72 /// instruction.
73 ///
74 /// [binary format]: https://www.rfc-editor.org/rfc/rfc7541.html#section-6
75 /// [header field representations]: https://www.rfc-editor.org/rfc/rfc7541.html#section-3.2
76 /// [dynamic table size update]: https://www.rfc-editor.org/rfc/rfc7541.html#section-6.3
77 pub(crate) enum Representation {
78     /// An [indexed header field representation] identifies an entry in either
79     /// the static table or the dynamic table. It causes a header field to be
80     /// added to the decoded header list.
81     ///
82     /// An indexed header field starts with the '1' 1-bit pattern, followed by
83     /// the index of the matching header field, represented as an integer with
84     /// a 7-bit prefix.
85     ///
86     /// [indexed header field representation]: https://www.rfc-editor.org/rfc/rfc7541.html#section-6.1
87     ///
88     /// # Binary Format
89     /// `Indexed Header Field`:
90     /// ```text
91     ///   0   1   2   3   4   5   6   7
92     /// +---+---+---+---+---+---+---+---+
93     /// | 1 |        Index (7+)         |
94     /// +---+---------------------------+
95     /// ```
96     Indexed { index: usize },
97 
98     /// A [literal header field with incremental indexing representation]
99     /// results in appending a header field to the decoded header list and
100     /// inserting it as a new entry into the dynamic table.
101     ///
102     /// A literal header field with incremental indexing representation starts
103     /// with the '01' 2-bit pattern.
104     ///
105     /// [literal header field with incremental indexing representation]: https://www.rfc-editor.org/rfc/rfc7541.html#section-6.2.1
106     ///
107     /// # Binary Format
108     /// `Literal Header Field with Incremental Indexing -- Indexed Name`:
109     /// ```text
110     ///   0   1   2   3   4   5   6   7
111     /// +---+---+---+---+---+---+---+---+
112     /// | 0 | 1 |      Index (6+)       |
113     /// +---+---+-----------------------+
114     /// | H |     Value Length (7+)     |
115     /// +---+---------------------------+
116     /// | Value String (Length octets)  |
117     /// +-------------------------------+
118     /// ```
119     ///
120     /// `Literal Header Field with Incremental Indexing -- New Name`:
121     /// ```text
122     ///   0   1   2   3   4   5   6   7
123     /// +---+---+---+---+---+---+---+---+
124     /// | 0 | 1 |           0           |
125     /// +---+---+-----------------------+
126     /// | H |     Name Length (7+)      |
127     /// +---+---------------------------+
128     /// |  Name String (Length octets)  |
129     /// +---+---------------------------+
130     /// | H |     Value Length (7+)     |
131     /// +---+---------------------------+
132     /// | Value String (Length octets)  |
133     /// +-------------------------------+
134     /// ```
135     LiteralWithIndexing { name: Name, value: Vec<u8> },
136 
137     /// A [literal header field without indexing representation] results in
138     /// appending a header field to the decoded header list without altering
139     /// the dynamic table.
140     ///
141     /// A literal header field without indexing representation starts with the
142     /// '0000' 4-bit pattern.
143     ///
144     /// [literal header field without indexing representation]: https://www.rfc-editor.org/rfc/rfc7541.html#section-6.2.2
145     ///
146     /// # Binary Format
147     /// `Literal Header Field without Indexing -- Indexed Name`:
148     /// ```text
149     ///   0   1   2   3   4   5   6   7
150     /// +---+---+---+---+---+---+---+---+
151     /// | 0 | 0 | 0 | 0 |  Index (4+)   |
152     /// +---+---+---+---+---------------+
153     /// | H |     Value Length (7+)     |
154     /// +---+---------------------------+
155     /// | Value String (Length octets)  |
156     /// +-------------------------------+
157     /// ```
158     /// `Literal Header Field without Indexing -- New Name`:
159     /// ```text
160     ///   0   1   2   3   4   5   6   7
161     /// +---+---+---+---+---+---+---+---+
162     /// | 0 | 0 | 0 | 0 |       0       |
163     /// +---+---+---+---+---------------+
164     /// | H |     Name Length (7+)      |
165     /// +---+---------------------------+
166     /// |  Name String (Length octets)  |
167     /// +---+---------------------------+
168     /// | H |     Value Length (7+)     |
169     /// +---+---------------------------+
170     /// | Value String (Length octets)  |
171     /// +-------------------------------+
172     /// ```
173     LiteralWithoutIndexing { name: Name, value: Vec<u8> },
174 
175     /// A [literal header field never-indexed representation] results in
176     /// appending a header field to the decoded header list without altering
177     /// the dynamic table. Intermediaries **MUST** use the same
178     /// representation for encoding this header field.
179     ///
180     /// A literal header field never-indexed representation starts with the
181     /// '0001' 4-bit pattern.
182     ///
183     /// [literal header field never-indexed representation]: https://www.rfc-editor.org/rfc/rfc7541.html#section-6.2.3
184     ///
185     /// # Binary Format
186     /// `Literal Header Field Never Indexed -- Indexed Name`:
187     /// ```text
188     ///   0   1   2   3   4   5   6   7
189     /// +---+---+---+---+---+---+---+---+
190     /// | 0 | 0 | 0 | 1 |  Index (4+)   |
191     /// +---+---+---+---+---------------+
192     /// | H |     Value Length (7+)     |
193     /// +---+---------------------------+
194     /// | Value String (Length octets)  |
195     /// +-------------------------------+
196     /// ```
197     ///
198     /// `Literal Header Field Never Indexed -- New Name`:
199     /// ```text
200     ///   0   1   2   3   4   5   6   7
201     /// +---+---+---+---+---+---+---+---+
202     /// | 0 | 0 | 0 | 1 |       0       |
203     /// +---+---+---+---+---------------+
204     /// | H |     Name Length (7+)      |
205     /// +---+---------------------------+
206     /// |  Name String (Length octets)  |
207     /// +---+---------------------------+
208     /// | H |     Value Length (7+)     |
209     /// +---+---------------------------+
210     /// | Value String (Length octets)  |
211     /// +-------------------------------+
212     /// ```
213     LiteralNeverIndexed { name: Name, value: Vec<u8> },
214 
215     /// A [dynamic table size update] signals a change to the size of the
216     /// dynamic table.
217     ///
218     /// [dynamic table size update]: https://www.rfc-editor.org/rfc/rfc7541.html#section-6.3
219     ///
220     /// # Binary Format
221     /// `Maximum Dynamic Table Size Change`:
222     /// ```text
223     ///   0   1   2   3   4   5   6   7
224     /// +---+---+---+---+---+---+---+---+
225     /// | 0 | 0 | 1 |   Max size (5+)   |
226     /// +---+---+---+-------------------+
227     /// ```
228     SizeUpdate { max_size: usize },
229 }
230 
231 impl Representation {
232     /// Gets the prefix bit of the `Representation`.
prefix_bit(&self) -> PrefixBit233     pub(crate) const fn prefix_bit(&self) -> PrefixBit {
234         match self {
235             Self::Indexed { .. } => PrefixBit::INDEXED,
236             Self::LiteralWithIndexing { .. } => PrefixBit::LITERAL_WITH_INDEXING,
237             Self::SizeUpdate { .. } => PrefixBit::SIZE_UPDATE,
238             Self::LiteralNeverIndexed { .. } => PrefixBit::LITERAL_NEVER_INDEXED,
239             Self::LiteralWithoutIndexing { .. } => PrefixBit::LITERAL_WITHOUT_INDEXING,
240         }
241     }
242 
243     /// Gets the index mask of the `Representation`.
prefix_index_mask(&self) -> PrefixIndexMask244     pub(crate) const fn prefix_index_mask(&self) -> PrefixIndexMask {
245         match self {
246             Self::Indexed { .. } => PrefixIndexMask::INDEXED,
247             Self::LiteralWithIndexing { .. } => PrefixIndexMask::LITERAL_WITH_INDEXING,
248             Self::SizeUpdate { .. } => PrefixIndexMask::SIZE_UPDATE,
249             Self::LiteralNeverIndexed { .. } => PrefixIndexMask::LITERAL_NEVER_INDEXED,
250             Self::LiteralWithoutIndexing { .. } => PrefixIndexMask::LITERAL_WITHOUT_INDEXING,
251         }
252     }
253 }
254 
255 /// Prefix bit of `Representation`. An integer is represented in two
256 /// parts: a prefix that fills the current octet and an optional list of octets
257 /// that are used if the integer value does not fit within the prefix.
258 ///
259 /// # Binary Format
260 /// ```text
261 ///   0   1   2   3   4   5   6   7
262 /// +---+---+---+---+---+---+---+---+
263 /// | PrefixBit |       Value       |
264 /// +---+---+---+-------------------+
265 /// ```
266 #[derive(Copy, Clone, PartialEq, Eq)]
267 pub(crate) struct PrefixBit(u8);
268 
269 impl PrefixBit {
270     pub(crate) const INDEXED: Self = Self(0x80);
271     pub(crate) const LITERAL_WITH_INDEXING: Self = Self(0x40);
272     pub(crate) const SIZE_UPDATE: Self = Self(0x20);
273     pub(crate) const LITERAL_NEVER_INDEXED: Self = Self(0x10);
274     pub(crate) const LITERAL_WITHOUT_INDEXING: Self = Self(0x00);
275 
276     /// Creates a `PrefixBit` from a byte. The interface will convert the
277     /// incoming byte to the most suitable prefix bit.
from_u8(byte: u8) -> Self278     pub(crate) fn from_u8(byte: u8) -> Self {
279         match byte {
280             x if x >= 0x80 => Self::INDEXED,
281             x if x >= 0x40 => Self::LITERAL_WITH_INDEXING,
282             x if x >= 0x20 => Self::SIZE_UPDATE,
283             x if x >= 0x10 => Self::LITERAL_NEVER_INDEXED,
284             _ => Self::LITERAL_WITHOUT_INDEXING,
285         }
286     }
287 
288     /// Returns the corresponding `PrefixIndexMask` according to the current
289     /// prefix bit.
prefix_index_mask(&self) -> PrefixIndexMask290     pub(crate) fn prefix_index_mask(&self) -> PrefixIndexMask {
291         match self.0 {
292             0x80 => PrefixIndexMask::INDEXED,
293             0x40 => PrefixIndexMask::LITERAL_WITH_INDEXING,
294             0x20 => PrefixIndexMask::SIZE_UPDATE,
295             0x10 => PrefixIndexMask::LITERAL_NEVER_INDEXED,
296             _ => PrefixIndexMask::LITERAL_WITHOUT_INDEXING,
297         }
298     }
299 }
300 
301 /// Prefix index mask of `Representation`.
302 ///
303 /// # Binary Format
304 /// ```text
305 ///   0   1   2   3   4   5   6   7
306 /// +---+---+---+---+---+---+---+---+
307 /// | PrefixBit |       Value       |
308 /// +---+---+---+-------------------+
309 ///
310 /// +---+---+---+---+---+---+---+---+
311 /// | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 |
312 /// +---+---+---+---+---+---+---+---+
313 /// |<-      PrefixIndexMask      ->|
314 /// ```
315 pub(crate) struct PrefixIndexMask(u8);
316 
317 impl PrefixIndexMask {
318     pub(crate) const INDEXED: Self = Self(0x7f);
319     pub(crate) const LITERAL_WITH_INDEXING: Self = Self(0x3f);
320     pub(crate) const SIZE_UPDATE: Self = Self(0x1f);
321     pub(crate) const LITERAL_NEVER_INDEXED: Self = Self(0x0f);
322     pub(crate) const LITERAL_WITHOUT_INDEXING: Self = Self(0x0f);
323 }
324 
325 /// Name of `Representation`. It can be represented as string literals or an
326 /// index.
327 pub(crate) enum Name {
328     Index(usize),
329     Literal(Vec<u8>),
330 }
331