• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //! [Integer Representation] implementation of [HPACK].
15 //!
16 //! [Integer Representation]: https://httpwg.org/specs/rfc7541.html#integer.representation
17 //! [HPACK]: https://httpwg.org/specs/rfc7541.html
18 //!
19 //! # Introduction
20 //! Integers are used to represent name indexes, header field indexes, or
21 //! string lengths. An integer representation can start anywhere within an
22 //! octet. To allow for optimized processing, an integer representation always
23 //! finishes at the end of an octet.
24 
25 use core::cmp::Ordering;
26 
27 use crate::h2::error::ErrorCode;
28 use crate::h2::H2Error;
29 
30 /// `IntegerDecoder` implementation according to `Pseudocode to decode an
31 /// integer I` in `RFC7541 section-5.1`.
32 ///
33 /// # Pseudocode
34 /// ```text
35 /// decode I from the next N bits
36 /// if I < 2^N - 1, return I
37 /// else
38 ///     M = 0
39 ///     repeat
40 ///         B = next octet
41 ///         I = I + (B & 127) * 2^M
42 ///         M = M + 7
43 ///     while B & 128 == 128
44 ///     return I
45 /// ```
46 pub(crate) struct IntegerDecoder {
47     index: usize,
48     shift: u32,
49 }
50 
51 impl IntegerDecoder {
52     /// Calculates an integer based on the incoming first byte and mask.
53     /// If no subsequent bytes exist, return the result directly, otherwise
54     /// return the decoder itself.
first_byte(byte: u8, mask: u8) -> Result<usize, Self>55     pub(crate) fn first_byte(byte: u8, mask: u8) -> Result<usize, Self> {
56         let index = byte & mask;
57         match index.cmp(&mask) {
58             Ordering::Less => Ok(index as usize),
59             _ => Err(Self {
60                 index: index as usize,
61                 shift: 1,
62             }),
63         }
64     }
65 
66     /// Continues computing the integer based on the next byte of the input.
67     /// Returns `Ok(Some(index))` if the result is obtained, otherwise returns
68     /// `Ok(None)`, and returns Err in case of overflow.
next_byte(&mut self, byte: u8) -> Result<Option<usize>, H2Error>69     pub(crate) fn next_byte(&mut self, byte: u8) -> Result<Option<usize>, H2Error> {
70         self.index = 1usize
71             .checked_shl(self.shift - 1)
72             .and_then(|res| res.checked_mul((byte & 0x7f) as usize))
73             .and_then(|res| res.checked_add(self.index))
74             .ok_or(H2Error::ConnectionError(ErrorCode::CompressionError))?;
75         self.shift += 7;
76         match (byte & 0x80) == 0x00 {
77             true => Ok(Some(self.index)),
78             false => Ok(None),
79         }
80     }
81 }
82 
83 /// `IntegerEncoder` implementation according to `Pseudocode to represent an
84 /// integer I` in `RFC7541 section-5.1`.
85 ///
86 /// # Pseudocode
87 /// ```text
88 /// if I < 2^N - 1, encode I on N bits
89 /// else
90 ///     encode (2^N - 1) on N bits
91 ///     I = I - (2^N - 1)
92 ///     while I >= 128
93 ///          encode (I % 128 + 128) on 8 bits
94 ///          I = I / 128
95 ///     encode I on 8 bits
96 /// ```
97 pub(crate) struct IntegerEncoder {
98     i: usize,
99     mask: u8,
100     pre: u8,
101     state: IntegerEncodeState,
102 }
103 
104 /// Enumeration of states that the `IntegerEncoder` needs to use.
105 enum IntegerEncodeState {
106     First,
107     Other,
108     Finish,
109 }
110 
111 impl IntegerEncoder {
112     /// Creates a new `IntegerEncoder`.
new(i: usize, mask: u8, pre: u8) -> Self113     pub(crate) fn new(i: usize, mask: u8, pre: u8) -> Self {
114         Self {
115             i,
116             mask,
117             pre,
118             state: IntegerEncodeState::First,
119         }
120     }
121 
122     /// Gets the next byte of the integer. If no remaining bytes are calculated,
123     /// return `None`.
next_byte(&mut self) -> Option<u8>124     pub(crate) fn next_byte(&mut self) -> Option<u8> {
125         match self.state {
126             IntegerEncodeState::First => {
127                 if self.i < self.mask as usize {
128                     self.state = IntegerEncodeState::Finish;
129                     return Some(self.pre | (self.i as u8));
130                 }
131                 self.i -= self.mask as usize;
132                 self.state = IntegerEncodeState::Other;
133                 Some(self.pre | self.mask)
134             }
135             IntegerEncodeState::Other => Some(if self.i >= 128 {
136                 let res = (self.i & 0x7f) as u8;
137                 self.i >>= 7;
138                 res | 0x80
139             } else {
140                 self.state = IntegerEncodeState::Finish;
141                 (self.i & 0x7f) as u8
142             }),
143             IntegerEncodeState::Finish => None,
144         }
145     }
146 
147     /// Checks if calculation is over.
is_finish(&self) -> bool148     pub(crate) fn is_finish(&self) -> bool {
149         matches!(self.state, IntegerEncodeState::Finish)
150     }
151 }
152 
153 #[cfg(test)]
154 mod ut_integer {
155     use crate::h2::hpack::integer::{IntegerDecoder, IntegerEncoder};
156 
157     /// UT test cases for `IntegerDecoder`.
158     ///
159     /// # Brief
160     /// 1. Creates an `IntegerDecoder`.
161     /// 2. Calls `IntegerDecoder::first_byte()` an
162     ///    `IntegerDecoder::next_byte()`,
163     /// passing in the specified parameters.
164     /// 3. Checks if the test results are correct.
165     #[test]
ut_integer_decode()166     fn ut_integer_decode() {
167         rfc7541_test_cases();
168 
169         macro_rules! integer_test_case {
170             ($fb: literal, $mask: literal => $fb_res: expr) => {
171                 match IntegerDecoder::first_byte($fb, $mask) {
172                     Ok(idx) => assert_eq!(idx, $fb_res),
173                     _ => panic!("IntegerDecoder::first_byte() failed!"),
174                 }
175             };
176             ($fb: literal, $mask: literal $(, $nb: literal => $nb_res: expr)* $(,)?) => {
177                 match IntegerDecoder::first_byte($fb, $mask) {
178                     Err(mut int) => {
179                         $(match int.next_byte($nb) {
180                             Ok(v) => assert_eq!(v, $nb_res),
181                             _ => panic!("IntegerDecoder::next_byte() failed!"),
182                         })*
183                     }
184                     _ => panic!("IntegerDecoder::first_byte() failed!"),
185                 }
186             };
187         }
188 
189         /// The following test cases are from RFC7541.
190         fn rfc7541_test_cases() {
191             // C.1.1. Example 1: Encoding 10 Using a 5-Bit Prefix
192             integer_test_case!(0x0a, 0x1f => 10);
193 
194             // C.1.2.  Example 2: Encoding 1337 Using a 5-Bit Prefix
195             integer_test_case!(
196                 0x1f, 0x1f,
197                 0x9a => None,
198                 0x0a => Some(1337),
199             );
200 
201             // C.1.3.  Example 3: Encoding 42 Starting at an Octet Boundary
202             integer_test_case!(0x2a, 0xff => 42);
203         }
204     }
205 
206     /// UT test cases for `IntegerEncoder`.
207     ///
208     /// # Brief
209     /// 1. Creates an `IntegerEncoder`.
210     /// 2. Calls `IntegerEncoder::first_byte()` and
211     ///    `IntegerEncoder::next_byte()`,
212     /// passing in the specified parameters.
213     /// 3. Checks if the test results are correct.
214     #[test]
ut_integer_encode()215     fn ut_integer_encode() {
216         rfc7541_test_cases();
217 
218         macro_rules! integer_test_case {
219             ($int: expr, $mask: expr, $pre: expr $(, $byte: expr)* $(,)? ) => {
220                 let mut integer = IntegerEncoder::new($int, $mask, $pre);
221                 $(
222                     assert_eq!(integer.next_byte(), Some($byte));
223                 )*
224                 assert_eq!(integer.next_byte(), None);
225             }
226         }
227 
228         /// The following test cases are from RFC7541.
229         fn rfc7541_test_cases() {
230             // C.1.1. Example 1: Encoding 10 Using a 5-Bit Prefix
231             integer_test_case!(10, 0x1f, 0x00, 0x0a);
232 
233             // C.1.2. Example 2: Encoding 1337 Using a 5-Bit Prefix
234             integer_test_case!(1337, 0x1f, 0x00, 0x1f, 0x9a, 0x0a);
235 
236             // C.1.3. Example 3: Encoding 42 Starting at an Octet Boundary
237             integer_test_case!(42, 0xff, 0x00, 0x2a);
238         }
239     }
240 }
241