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