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