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 core::mem::take;
15 
16 use crate::h2::error::ErrorCode;
17 use crate::h2::hpack::representation::{
18     Name, ReprDecStateHolder, ReprDecodeState, ReprDecoder, Representation,
19 };
20 use crate::h2::hpack::table::{DynamicTable, Header, TableSearcher};
21 use crate::h2::{H2Error, Parts};
22 
23 // A structure used to store header lines and octets lengths of header lines.
24 struct HeaderLines {
25     parts: Parts,
26     header_size: usize,
27 }
28 
29 /// Decoder implementation of [`HPACK`].
30 ///
31 /// [`HPACK`]: https://httpwg.org/specs/rfc7541.html
32 pub(crate) struct HpackDecoder {
33     header_list_size: usize,
34     table: DynamicTable,
35     lines: HeaderLines,
36     holder: ReprDecStateHolder,
37 }
38 
39 impl HpackDecoder {
40     /// Creates a `HpackDecoder` with the given max size.
with_max_size(header_table_size: usize, max_header_list_size: usize) -> Self41     pub(crate) fn with_max_size(header_table_size: usize, max_header_list_size: usize) -> Self {
42         Self {
43             header_list_size: max_header_list_size,
44             table: DynamicTable::with_max_size(header_table_size),
45             lines: HeaderLines {
46                 parts: Parts::new(),
47                 header_size: 0,
48             },
49             holder: ReprDecStateHolder::new(),
50         }
51     }
52 
53     /// Users can call `decode` multiple times to decode the byte stream in
54     /// segments.
decode(&mut self, buf: &[u8]) -> Result<(), H2Error>55     pub(crate) fn decode(&mut self, buf: &[u8]) -> Result<(), H2Error> {
56         // Initialize ReprDecoder.
57         let mut decoder = ReprDecoder::new(buf);
58         decoder.load(&mut self.holder);
59 
60         let mut updater = Updater::new(&mut self.table, &mut self.lines, self.header_list_size);
61         loop {
62             match decoder.decode()? {
63                 // If a `Repr` is decoded, the `Updater` updates it immediately.
64                 Some(repr) => updater.update(repr)?,
65                 // If no `Repr` is decoded at this time, the intermediate result
66                 // needs to be saved.
67                 None => {
68                     decoder.save(&mut self.holder);
69                     return Ok(());
70                 }
71             }
72         }
73     }
74 
75     /// Users call `finish` to stop decoding and get the result.
finish(&mut self) -> Result<Parts, H2Error>76     pub(crate) fn finish(&mut self) -> Result<Parts, H2Error> {
77         if !self.holder.is_empty() {
78             return Err(H2Error::ConnectionError(ErrorCode::CompressionError));
79         }
80         self.lines.header_size = 0;
81         Ok(take(&mut self.lines.parts))
82     }
83 
84     /// Update the SETTING_HEADER_LIST_SIZE
update_header_list_size(&mut self, size: usize)85     pub(crate) fn update_header_list_size(&mut self, size: usize) {
86         self.header_list_size = size
87     }
88 }
89 
90 /// `Updater` is used to update `DynamicTable` `PseudoHeaders` and
91 /// `HttpHeaderMap`.
92 struct Updater<'a> {
93     header_list_size: usize,
94     table: &'a mut DynamicTable,
95     lines: &'a mut HeaderLines,
96 }
97 
98 impl<'a> Updater<'a> {
99     /// Creates a new `Updater`.
new( table: &'a mut DynamicTable, lines: &'a mut HeaderLines, header_list_size: usize, ) -> Self100     fn new(
101         table: &'a mut DynamicTable,
102         lines: &'a mut HeaderLines,
103         header_list_size: usize,
104     ) -> Self {
105         Self {
106             table,
107             lines,
108             header_list_size,
109         }
110     }
111 
112     /// Updates the `DynamicTable` and `Parts`.
update(&mut self, repr: Representation) -> Result<(), H2Error>113     fn update(&mut self, repr: Representation) -> Result<(), H2Error> {
114         match repr {
115             Representation::Indexed { index } => self.update_indexed(index),
116             Representation::LiteralWithIndexing { name: n, value: v } => {
117                 self.update_literal_with_indexing(n, v)
118             }
119             Representation::LiteralWithoutIndexing { name: n, value: v } => {
120                 self.update_literal_without_indexing(n, v)
121             }
122             Representation::LiteralNeverIndexed { name: n, value: v } => {
123                 self.update_literal_never_indexing(n, v)
124             }
125             Representation::SizeUpdate { max_size } => {
126                 self.table.update_size(max_size);
127                 Ok(())
128             }
129         }
130     }
131 
update_indexed(&mut self, index: usize) -> Result<(), H2Error>132     fn update_indexed(&mut self, index: usize) -> Result<(), H2Error> {
133         let searcher = TableSearcher::new(self.table);
134         let (h, v) = searcher
135             .search_header(index)
136             .ok_or(H2Error::ConnectionError(ErrorCode::CompressionError))?;
137         self.check_header_list_size(&h, &v)?;
138         self.lines.parts.update(h, v);
139         Ok(())
140     }
141 
update_literal_with_indexing(&mut self, name: Name, value: Vec<u8>) -> Result<(), H2Error>142     fn update_literal_with_indexing(&mut self, name: Name, value: Vec<u8>) -> Result<(), H2Error> {
143         let (h, v) = self.get_header_by_name_and_value(name, value)?;
144         self.check_header_list_size(&h, &v)?;
145         self.table.update(h.clone(), v.clone());
146         self.lines.parts.update(h, v);
147         Ok(())
148     }
149 
update_literal_without_indexing( &mut self, name: Name, value: Vec<u8>, ) -> Result<(), H2Error>150     fn update_literal_without_indexing(
151         &mut self,
152         name: Name,
153         value: Vec<u8>,
154     ) -> Result<(), H2Error> {
155         let (h, v) = self.get_header_by_name_and_value(name, value)?;
156         self.check_header_list_size(&h, &v)?;
157         self.lines.parts.update(h, v);
158         Ok(())
159     }
160 
161     // TODO: 支持 `LiteralNeverIndexed`.
update_literal_never_indexing(&mut self, name: Name, value: Vec<u8>) -> Result<(), H2Error>162     fn update_literal_never_indexing(&mut self, name: Name, value: Vec<u8>) -> Result<(), H2Error> {
163         self.update_literal_without_indexing(name, value)
164     }
165 
check_header_list_size(&mut self, key: &Header, value: &str) -> Result<(), H2Error>166     fn check_header_list_size(&mut self, key: &Header, value: &str) -> Result<(), H2Error> {
167         let line_size = header_line_length(key.len(), value.len());
168         self.update_size(line_size);
169         if self.lines.header_size > self.header_list_size {
170             Err(H2Error::ConnectionError(ErrorCode::ConnectError))
171         } else {
172             Ok(())
173         }
174     }
175 
update_size(&mut self, addition: usize)176     pub(crate) fn update_size(&mut self, addition: usize) {
177         self.lines.header_size += addition;
178     }
179 
get_header_by_name_and_value( &self, name: Name, value: Vec<u8>, ) -> Result<(Header, String), H2Error>180     fn get_header_by_name_and_value(
181         &self,
182         name: Name,
183         value: Vec<u8>,
184     ) -> Result<(Header, String), H2Error> {
185         let h = match name {
186             Name::Index(index) => {
187                 let searcher = TableSearcher::new(self.table);
188                 searcher
189                     .search_header_name(index)
190                     .ok_or(H2Error::ConnectionError(ErrorCode::CompressionError))?
191             }
192             Name::Literal(octets) => Header::Other(unsafe { String::from_utf8_unchecked(octets) }),
193         };
194         let v = unsafe { String::from_utf8_unchecked(value) };
195         Ok((h, v))
196     }
197 }
198 
header_line_length(key_size: usize, value_size: usize) -> usize199 fn header_line_length(key_size: usize, value_size: usize) -> usize {
200     key_size + value_size + 32
201 }
202 
203 #[cfg(test)]
204 mod ut_hpack_decoder {
205     use crate::h2::hpack::table::Header;
206     use crate::h2::hpack::HpackDecoder;
207     use crate::util::test_util::decode;
208 
209     const MAX_HEADER_LIST_SIZE: usize = 16 << 20;
210 
211     /// UT test cases for `HpackDecoder`.
212     ///
213     /// # Brief
214     /// 1. Creates a `HpackDecoder`.
215     /// 2. Calls `HpackDecoder::decode()` function, passing in the specified
216     /// parameters.
217     /// 3. Checks if the test results are correct.
218     #[test]
ut_hpack_decoder()219     fn ut_hpack_decoder() {
220         rfc7541_test_cases();
221         slices_test_cases();
222 
223         macro_rules! check_pseudo {
224             (
225                 $pseudo: expr,
226                 { $a: expr, $m: expr, $p: expr, $sc: expr, $st: expr } $(,)?
227             ) => {
228                 assert_eq!($pseudo.authority(), $a);
229                 assert_eq!($pseudo.method(), $m);
230                 assert_eq!($pseudo.path(), $p);
231                 assert_eq!($pseudo.scheme(), $sc);
232                 assert_eq!($pseudo.status(), $st);
233             };
234         }
235 
236         macro_rules! check_map {
237             ($map: expr, { $($(,)? $k: literal => $v: literal)* } $(,)?) => {
238                 $(
239                     assert_eq!($map.get($k).unwrap().to_string().unwrap(), $v);
240                 )*
241             }
242         }
243 
244         macro_rules! check_table {
245             (
246                 $hpack: expr, $size: expr,
247                 { $($(,)? $($k: literal)? $($k2: ident)? => $v: literal)* } $(,)?
248             ) => {
249                 assert_eq!($hpack.table.curr_size(), $size);
250                 let mut _cnt = 0;
251                 $(
252 
253                     $(
254                         match $hpack.table.header(_cnt) {
255                             Some((Header::Other(k), v)) if k == $k && v == $v => {},
256                             _ => panic!("DynamicTable::header() failed! (branch 1)"),
257                         }
258                     )?
259                     $(
260                         match $hpack.table.header(_cnt) {
261                             Some((Header::$k2, v)) if v == $v => {},
262                             _ => panic!("DynamicTable::header() failed! (branch 2)"),
263                         }
264                     )?
265                     _cnt += 1;
266                 )*
267             }
268         }
269 
270         macro_rules! get_parts {
271             ($hpack: expr $(, $input: literal)*) => {{
272                 $(
273                     let text = decode($input).unwrap();
274                     assert!($hpack.decode(text.as_slice()).is_ok());
275                 )*
276                 match $hpack.finish() {
277                     Ok(parts) => parts,
278                     Err(_) => panic!("HpackDecoder::finish() failed!"),
279                 }
280             }};
281         }
282 
283         macro_rules! hpack_test_case {
284             (
285                 $hpack: expr $(, $input: literal)*,
286                 { $a: expr, $m: expr, $p: expr, $sc: expr, $st: expr },
287                 { $size: expr $(, $($k2: literal)? $($k3: ident)? => $v2: literal)* } $(,)?
288             ) => {
289                 let mut _hpack = $hpack;
290                 let (pseudo, _) = get_parts!(_hpack $(, $input)*).into_parts();
291                 check_pseudo!(pseudo, { $a, $m, $p, $sc, $st });
292                 check_table!(_hpack, $size, { $($($k2)? $($k3)? => $v2)* });
293             };
294 
295             (
296                 $hpack: expr $(, $input: literal)*,
297                 { $($(,)? $k1: literal => $v1: literal)* },
298                 { $size: expr $(, $($k2: literal)? $($k3: ident)? => $v2: literal)* } $(,)?
299             ) => {
300                 let mut _hpack = $hpack;
301                 let (_, map) = get_parts!(_hpack $(, $input)*).into_parts();
302                 check_map!(map, { $($k1 => $v1)* });
303                 check_table!(_hpack, $size, { $($($k2)? $($k3)? => $v2)* });
304             };
305 
306             (
307                 $hpack: expr $(, $input: literal)*,
308                 { $a: expr, $m: expr, $p: expr, $sc: expr, $st: expr },
309                 { $($(,)? $k1: literal => $v1: literal)* },
310                 { $size: expr $(, $($k2: literal)? $($k3: ident)? => $v2: literal)* } $(,)?
311             ) => {
312                 let mut _hpack = $hpack;
313                 let (pseudo, map) = get_parts!(_hpack $(, $input)*).into_parts();
314                 check_pseudo!(pseudo, { $a, $m, $p, $sc, $st });
315                 check_map!(map, { $($k1 => $v1)* });
316                 check_table!(_hpack, $size, { $($($k2)? $($k3)? => $v2)* });
317             };
318         }
319 
320         /// The following test cases are from RFC7541.
321         fn rfc7541_test_cases() {
322             // C.2.1. Literal Header Field with Indexing
323             hpack_test_case!(
324                 HpackDecoder::with_max_size(4096, MAX_HEADER_LIST_SIZE),
325                 "400a637573746f6d2d6b65790d637573746f6d2d686561646572",
326                 { "custom-key" => "custom-header" },
327                 { 55, "custom-key" => "custom-header" },
328             );
329 
330             // C.2.2. Literal Header Field without Indexing
331             hpack_test_case!(
332                 HpackDecoder::with_max_size(4096, MAX_HEADER_LIST_SIZE),
333                 "040c2f73616d706c652f70617468",
334                 { None, None, Some("/sample/path"), None, None },
335                 { 0 }
336             );
337 
338             // C.2.3. Literal Header Field Never Indexed
339             hpack_test_case!(
340                 HpackDecoder::with_max_size(4096, MAX_HEADER_LIST_SIZE),
341                 "100870617373776f726406736563726574",
342                 { "password" => "secret" },
343                 { 0 },
344             );
345 
346             // C.2.4. Indexed Header Field
347             hpack_test_case!(
348                 HpackDecoder::with_max_size(4096, MAX_HEADER_LIST_SIZE),
349                 "82",
350                 { None, Some("GET"), None, None, None },
351                 { 0 }
352             );
353 
354             // Request Examples without Huffman Coding.
355             {
356                 let mut hpack_decoder = HpackDecoder::with_max_size(4096, MAX_HEADER_LIST_SIZE);
357                 // C.3.1. First Request
358                 hpack_test_case!(
359                     &mut hpack_decoder,
360                     "828684410f7777772e6578616d706c652e636f6d",
361                     { Some("www.example.com"), Some("GET"), Some("/"), Some("http"), None },
362                     { 57, Authority => "www.example.com" }
363                 );
364 
365                 // C.3.2. Second Request
366                 hpack_test_case!(
367                     &mut hpack_decoder,
368                     "828684be58086e6f2d6361636865",
369                     { Some("www.example.com"), Some("GET"), Some("/"), Some("http"), None },
370                     { "cache-control" => "no-cache" },
371                     { 110, "cache-control" => "no-cache", Authority => "www.example.com" }
372                 );
373 
374                 // C.3.3. Third Request
375                 hpack_test_case!(
376                     &mut hpack_decoder,
377                     "828785bf400a637573746f6d2d6b65790c637573746f6d2d76616c7565",
378                     { Some("www.example.com"), Some("GET"), Some("/index.html"), Some("https"), None },
379                     { "custom-key" => "custom-value" },
380                     { 164, "custom-key" => "custom-value", "cache-control" => "no-cache", Authority => "www.example.com" }
381                 );
382             }
383 
384             // C.4. Request Examples with Huffman Coding
385             {
386                 let mut hpack_decoder = HpackDecoder::with_max_size(4096, MAX_HEADER_LIST_SIZE);
387                 // C.4.1. First Request
388                 hpack_test_case!(
389                     &mut hpack_decoder,
390                     "828684418cf1e3c2e5f23a6ba0ab90f4ff",
391                     { Some("www.example.com"), Some("GET"), Some("/"), Some("http"), None },
392                     { 57, Authority => "www.example.com" }
393                 );
394 
395                 // C.4.2. Second Request
396                 hpack_test_case!(
397                     &mut hpack_decoder,
398                     "828684be5886a8eb10649cbf",
399                     { Some("www.example.com"), Some("GET"), Some("/"), Some("http"), None },
400                     { "cache-control" => "no-cache" },
401                     { 110, "cache-control" => "no-cache", Authority => "www.example.com" }
402                 );
403 
404                 // C.4.3. Third Request
405                 hpack_test_case!(
406                     &mut hpack_decoder,
407                     "828785bf408825a849e95ba97d7f8925a849e95bb8e8b4bf",
408                     { Some("www.example.com"), Some("GET"), Some("/index.html"), Some("https"), None },
409                     { "custom-key" => "custom-value" },
410                     { 164, "custom-key" => "custom-value", "cache-control" => "no-cache", Authority => "www.example.com" }
411                 );
412             }
413 
414             // C.5. Response Examples without Huffman Coding
415             {
416                 let mut hpack_decoder = HpackDecoder::with_max_size(256, MAX_HEADER_LIST_SIZE);
417                 // C.5.1. First Response
418                 hpack_test_case!(
419                     &mut hpack_decoder,
420                     "4803333032580770726976617465611d\
421                     4d6f6e2c203231204f63742032303133\
422                     2032303a31333a323120474d546e1768\
423                     747470733a2f2f7777772e6578616d70\
424                     6c652e636f6d",
425                     { None, None, None, None, Some("302") },
426                     {
427                         "location" => "https://www.example.com",
428                         "date" => "Mon, 21 Oct 2013 20:13:21 GMT",
429                         "cache-control" => "private"
430                     },
431                     {
432                         222,
433                         "location" => "https://www.example.com",
434                         "date" => "Mon, 21 Oct 2013 20:13:21 GMT",
435                         "cache-control" => "private",
436                         Status => "302"
437                     }
438                 );
439 
440                 // C.5.2. Second Response
441                 hpack_test_case!(
442                     &mut hpack_decoder,
443                     "4803333037c1c0bf",
444                     { None, None, None, None, Some("307") },
445                     {
446                         "cache-control" => "private",
447                         "date" => "Mon, 21 Oct 2013 20:13:21 GMT",
448                         "location" => "https://www.example.com"
449                     },
450                     {
451                         222,
452                         Status => "307",
453                         "location" => "https://www.example.com",
454                         "date" => "Mon, 21 Oct 2013 20:13:21 GMT",
455                         "cache-control" => "private"
456                     }
457                 );
458 
459                 // C.5.3. Third Response
460                 hpack_test_case!(
461                     &mut hpack_decoder,
462                     "88c1611d4d6f6e2c203231204f637420\
463                     323031332032303a31333a323220474d\
464                     54c05a04677a69707738666f6f3d4153\
465                     444a4b48514b425a584f5157454f5049\
466                     5541585157454f49553b206d61782d61\
467                     67653d333630303b2076657273696f6e\
468                     3d31",
469                     { None, None, None, None, Some("200") },
470                     {
471                         "cache-control" => "private",
472                         "date" => "Mon, 21 Oct 2013 20:13:22 GMT",
473                         "location" => "https://www.example.com",
474                         "content-encoding" => "gzip",
475                         "set-cookie" => "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"
476                     },
477                     {
478                         215,
479                         "set-cookie" => "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1",
480                         "content-encoding" => "gzip",
481                         "date" => "Mon, 21 Oct 2013 20:13:22 GMT"
482                     }
483                 );
484             }
485 
486             // C.6. Response Examples with Huffman Coding
487             {
488                 let mut hpack_decoder = HpackDecoder::with_max_size(256, MAX_HEADER_LIST_SIZE);
489                 // C.6.1. First Response
490                 hpack_test_case!(
491                     &mut hpack_decoder,
492                     "488264025885aec3771a4b6196d07abe\
493                     941054d444a8200595040b8166e082a6\
494                     2d1bff6e919d29ad171863c78f0b97c8\
495                     e9ae82ae43d3",
496                     { None, None, None, None, Some("302") },
497                     {
498                         "location" => "https://www.example.com",
499                         "date" => "Mon, 21 Oct 2013 20:13:21 GMT",
500                         "cache-control" => "private"
501                     },
502                     {
503                         222,
504                         "location" => "https://www.example.com",
505                         "date" => "Mon, 21 Oct 2013 20:13:21 GMT",
506                         "cache-control" => "private",
507                         Status => "302"
508                     }
509                 );
510 
511                 // C.6.2. Second Response
512                 hpack_test_case!(
513                     &mut hpack_decoder,
514                     "4883640effc1c0bf",
515                     { None, None, None, None, Some("307") },
516                     {
517                         "cache-control" => "private",
518                         "date" => "Mon, 21 Oct 2013 20:13:21 GMT",
519                         "location" => "https://www.example.com"
520                     },
521                     {
522                         222,
523                         Status => "307",
524                         "location" => "https://www.example.com",
525                         "date" => "Mon, 21 Oct 2013 20:13:21 GMT",
526                         "cache-control" => "private"
527                     }
528                 );
529 
530                 // C.6.3. Third Response
531                 hpack_test_case!(
532                     &mut hpack_decoder,
533                     "88c16196d07abe941054d444a8200595\
534                     040b8166e084a62d1bffc05a839bd9ab\
535                     77ad94e7821dd7f2e6c7b335dfdfcd5b\
536                     3960d5af27087f3672c1ab270fb5291f\
537                     9587316065c003ed4ee5b1063d5007",
538                     { None, None, None, None, Some("200") },
539                     {
540                         "cache-control" => "private",
541                         "date" => "Mon, 21 Oct 2013 20:13:22 GMT",
542                         "location" => "https://www.example.com",
543                         "content-encoding" => "gzip",
544                         "set-cookie" => "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"
545                     },
546                     {
547                         215,
548                         "set-cookie" => "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1",
549                         "content-encoding" => "gzip",
550                         "date" => "Mon, 21 Oct 2013 20:13:22 GMT"
551                     }
552                 );
553             }
554         }
555 
556         fn slices_test_cases() {
557             // C.2.1. Literal Header Field with Indexing
558             hpack_test_case!(
559                 HpackDecoder::with_max_size(4096, MAX_HEADER_LIST_SIZE),
560                 "04", "0c", "2f", "73", "61", "6d", "70", "6c", "65", "2f", "70", "61", "74", "68",
561                 { None, None, Some("/sample/path"), None, None },
562                 { 0 }
563             );
564 
565             // C.6.1. First Response
566             hpack_test_case!(
567                 HpackDecoder::with_max_size(256, MAX_HEADER_LIST_SIZE),
568                 "488264025885aec3771a4b6196d07abe",
569                 "941054d444a8200595040b8166e082a6",
570                 "2d1bff6e919d29ad171863c78f0b97c8",
571                 "e9ae82ae43d3",
572                 { None, None, None, None, Some("302") },
573                 {
574                     "location" => "https://www.example.com",
575                     "date" => "Mon, 21 Oct 2013 20:13:21 GMT",
576                     "cache-control" => "private"
577                 },
578                 {
579                     222,
580                     "location" => "https://www.example.com",
581                     "date" => "Mon, 21 Oct 2013 20:13:21 GMT",
582                     "cache-control" => "private",
583                     Status => "302"
584                 }
585             );
586         }
587     }
588 
589     /// UT test cases for `HpackDecoder`.
590     ///
591     /// # Brief
592     /// 1. Creates a header buf with non-utf8 bytes `0xE5, 0xBB, 0x6F`.
593     /// 2. Calls `HpackDecoder::decode()` function, passing in the specified
594     /// parameters.
595     /// 3. Checks if the test results are correct.
596     #[test]
ut_decode_literal_non_utf8_header_value()597     fn ut_decode_literal_non_utf8_header_value() {
598         let mut decoder = HpackDecoder::with_max_size(1000, 2000);
599         let buf: [u8; 73] = [
600             0x0, 0x8D, 0x21, 0xEA, 0x49, 0x6A, 0x4A, 0xD2, 0x19, 0x15, 0x9D, 0x6, 0x49, 0x8F, 0x57,
601             0x39, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x66, 0x69,
602             0x6C, 0x65, 0x4E, 0x61, 0x6D, 0x65, 0x3D, 0x54, 0x65, 0x73, 0x74, 0x5F, 0xE6, 0x96,
603             0xB0, 0xE5, 0xBB, 0x6F, 0x20, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74,
604             0x20, 0x57, 0x6F, 0x72, 0x64, 0x20, 0xE6, 0x96, 0x87, 0xE6, 0xA1, 0xA3, 0x2E, 0x64,
605             0x6F, 0x63,
606         ];
607         let res = decoder.decode(&buf);
608         assert!(res.is_ok());
609     }
610 }
611