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 use crate::h2::hpack::representation::{ReprEncStateHolder, ReprEncodeState, ReprEncoder}; 15 use crate::h2::hpack::table::{DynamicTable, Header}; 16 use crate::h2::{Parts, PseudoHeaders}; 17 18 /// Decoder implementation of [`HPACK`]. 19 /// 20 /// [`HPACK`]: https://httpwg.org/specs/rfc7541.html 21 // TODO: 增加 SizeUpdate 字段以支持用户动态变化 DynamicTable 大小。 22 pub(crate) struct HpackEncoder { 23 table: DynamicTable, 24 holder: ReprEncStateHolder, 25 use_huffman: bool, 26 } 27 28 impl HpackEncoder { 29 /// Create a `HpackEncoder` with the given max dynamic table size and 30 /// huffman usage. new(max_size: usize, use_huffman: bool) -> Self31 pub(crate) fn new(max_size: usize, use_huffman: bool) -> Self { 32 Self { 33 table: DynamicTable::with_max_size(max_size), 34 holder: ReprEncStateHolder::new(), 35 use_huffman, 36 } 37 } 38 39 // TODO enable update header_table_size update_max_dynamic_table_size(&self, _max_size: usize)40 pub(crate) fn update_max_dynamic_table_size(&self, _max_size: usize) {} 41 42 /// Set the `Parts` to be encoded. set_parts(&mut self, parts: Parts)43 pub(crate) fn set_parts(&mut self, parts: Parts) { 44 self.holder.set_parts(parts) 45 } 46 47 /// Users can call `encode` multiple times to encode the previously set 48 /// `Parts` in segments. encode(&mut self, dst: &mut [u8]) -> usize49 pub(crate) fn encode(&mut self, dst: &mut [u8]) -> usize { 50 let mut encoder = ReprEncoder::new(&mut self.table); 51 encoder.load(&mut self.holder); 52 let size = encoder.encode(dst, self.use_huffman); 53 if size == dst.len() { 54 encoder.save(&mut self.holder); 55 } 56 size 57 } 58 59 /// Check the previously set `Parts` if encoding is complete. is_finished(&self) -> bool60 pub(crate) fn is_finished(&self) -> bool { 61 self.holder.is_empty() 62 } 63 } 64 65 #[cfg(test)] 66 mod ut_hpack_encoder { 67 use crate::h2::hpack::table::Header; 68 use crate::h2::hpack::HpackEncoder; 69 use crate::h2::Parts; 70 use crate::util::test_util::decode; 71 72 #[test] ut_hpack_encoder()73 fn ut_hpack_encoder() { 74 rfc7541_test_cases(); 75 76 // In order to ensure that Header and Value are added in the order of 77 // `RFC`, each time a Parts is generated separately and passed in 78 macro_rules! hpack_test_cases { 79 ($enc: expr, $len: expr, $res: literal, $size: expr , { $($h: expr, $v: expr $(,)?)*} $(,)?) => { 80 let mut _encoder = $enc; 81 let mut vec = [0u8; $len]; 82 let mut cur = 0; 83 $( 84 let mut parts = Parts::new(); 85 parts.update($h, $v); 86 _encoder.set_parts(parts); 87 cur += _encoder.encode(&mut vec[cur..]); 88 )* 89 assert_eq!(cur, $len); 90 let result = decode($res).unwrap(); 91 assert_eq!(vec.as_slice(), result.as_slice()); 92 assert_eq!(_encoder.table.curr_size(), $size); 93 } 94 } 95 96 /// The following test cases are from RFC7541. 97 fn rfc7541_test_cases() { 98 // C.2.1. Literal Header Field with Indexing 99 hpack_test_cases!( 100 HpackEncoder::new(4096, false), 101 26, "400a637573746f6d2d6b65790d637573746f6d2d686561646572", 55, 102 { 103 Header::Other(String::from("custom-key")), 104 String::from("custom-header"), 105 }, 106 ); 107 108 // TODO: C.2.2. Literal Header Field without Indexing 109 // TODO: C.2.3. Literal Header Field Never Indexed 110 111 // C.2.4. Indexed Header Field 112 hpack_test_cases!( 113 HpackEncoder::new(4096, false), 114 1, "82", 0, 115 { 116 Header::Method, 117 String::from("GET"), 118 }, 119 ); 120 121 // C.3. Request Examples without Huffman Coding 122 { 123 let mut encoder = HpackEncoder::new(4096, false); 124 // C.3.1. First Request 125 hpack_test_cases!( 126 &mut encoder, 127 20, "828684410f7777772e6578616d706c652e636f6d", 57, 128 { 129 Header::Method, 130 String::from("GET"), 131 Header::Scheme, 132 String::from("http"), 133 Header::Path, 134 String::from("/"), 135 Header::Authority, 136 String::from("www.example.com"), 137 }, 138 ); 139 140 // C.3.2. Second Request 141 hpack_test_cases!( 142 &mut encoder, 143 14, "828684be58086e6f2d6361636865", 110, 144 { 145 Header::Method, 146 String::from("GET"), 147 Header::Scheme, 148 String::from("http"), 149 Header::Path, 150 String::from("/"), 151 Header::Authority, 152 String::from("www.example.com"), 153 Header::Other(String::from("cache-control")), 154 String::from("no-cache"), 155 }, 156 ); 157 158 // C.3.3. Third Request 159 hpack_test_cases!( 160 &mut encoder, 161 29, "828785bf400a637573746f6d2d6b65790c637573746f6d2d76616c7565", 164, 162 { 163 Header::Method, 164 String::from("GET"), 165 Header::Scheme, 166 String::from("https"), 167 Header::Path, 168 String::from("/index.html"), 169 Header::Authority, 170 String::from("www.example.com"), 171 Header::Other(String::from("custom-key")), 172 String::from("custom-value"), 173 }, 174 ); 175 } 176 177 // TODO: C.4. Request Examples with Huffman Coding 178 179 // C.5. Response Examples without Huffman Coding 180 { 181 let mut encoder = HpackEncoder::new(256, false); 182 // C.5.1. First Response 183 hpack_test_cases!( 184 &mut encoder, 185 70, 186 "4803333032580770726976617465611d\ 187 4d6f6e2c203231204f63742032303133\ 188 2032303a31333a323120474d546e1768\ 189 747470733a2f2f7777772e6578616d70\ 190 6c652e636f6d", 191 222, 192 { 193 Header::Status, 194 String::from("302"), 195 Header::Other(String::from("cache-control")), 196 String::from("private"), 197 Header::Other(String::from("date")), 198 String::from("Mon, 21 Oct 2013 20:13:21 GMT"), 199 Header::Other(String::from("location")), 200 String::from("https://www.example.com"), 201 }, 202 ); 203 204 // C.5.2. Second Response 205 hpack_test_cases!( 206 &mut encoder, 207 8, "4803333037c1c0bf", 222, 208 { 209 Header::Status, 210 String::from("307"), 211 Header::Other(String::from("cache-control")), 212 String::from("private"), 213 Header::Other(String::from("date")), 214 String::from("Mon, 21 Oct 2013 20:13:21 GMT"), 215 Header::Other(String::from("location")), 216 String::from("https://www.example.com"), 217 }, 218 ); 219 220 // C.5.3. Third Response 221 hpack_test_cases!( 222 &mut encoder, 223 98, 224 "88c1611d4d6f6e2c203231204f637420\ 225 323031332032303a31333a323220474d\ 226 54c05a04677a69707738666f6f3d4153\ 227 444a4b48514b425a584f5157454f5049\ 228 5541585157454f49553b206d61782d61\ 229 67653d333630303b2076657273696f6e\ 230 3d31", 231 215, 232 { 233 Header::Status, 234 String::from("200"), 235 Header::Other(String::from("cache-control")), 236 String::from("private"), 237 Header::Other(String::from("date")), 238 String::from("Mon, 21 Oct 2013 20:13:22 GMT"), 239 Header::Other(String::from("location")), 240 String::from("https://www.example.com"), 241 Header::Other(String::from("content-encoding")), 242 String::from("gzip"), 243 Header::Other(String::from("set-cookie")), 244 String::from("foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"), 245 }, 246 ); 247 } 248 249 // TODO: C.6. Response Examples with Huffman Coding 250 } 251 } 252 } 253