• 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 #![rustfmt::skip]
15 
16 use crate::h3::parts::Parts;
17 use crate::h3::qpack::error::ErrorCode::DecoderStreamError;
18 use crate::h3::qpack::error::H3errorQpack;
19 use crate::h3::qpack::format::encoder::{
20     DecInstDecoder, InstDecodeState, PartsIter, ReprEncodeState, SetCap,
21 };
22 use crate::h3::qpack::format::ReprEncoder;
23 use crate::h3::qpack::integer::{Integer, IntegerEncoder};
24 use crate::h3::qpack::table::{DynamicTable, Field};
25 use crate::h3::qpack::{DecoderInstruction, PrefixMask};
26 use std::collections::{HashMap, VecDeque};
27 
28 /// An encoder is used to compress field in a compression format for efficiently representing
29 /// HTTP fields that is to be used in HTTP/3. This is a variation of HPACK compression that seeks
30 /// to reduce head-of-line blocking.
31 ///
32 /// # Examples
33 // ```no_run
34 // use crate::ylong_http::h3::qpack::encoder::QpackEncoder;
35 // use crate::ylong_http::h3::parts::Parts;
36 // use crate::ylong_http::h3::qpack::table::{DynamicTable, Field};
37 // use crate::ylong_http::test_util::decode;
38 //
39 //
40 //
41 // // the (field, value) is: ("custom-key", "custom-value2")
42 // // Required content:
43 // let mut encoder_buf = [0u8; 1024]; // QPACK stream providing control commands.
44 // let mut stream_buf = [0u8; 1024]; // Field section encoded in QPACK format.
45 // let mut encoder_cur = 0; // index of encoder_buf.
46 // let mut stream_cur = 0; // index of stream_buf.
47 // let mut table = DynamicTable::with_empty();
48 //
49 // // create a new encoder.
50 // let mut encoder = QpackEncoder::new(&mut table, 0, true, 1);
51 //
52 // // set dynamic table capacity.
53 // encoder_cur += encoder.set_capacity(220, &mut encoder_buf[encoder_buf..]);
54 //
55 // // set field section.
56 // let mut field = Parts::new();
57 // field.update(Field::Other(String::from("custom-key")), String::from("custom-value"));
58 // encoder.set_parts(field);
59 //
60 // // encode field section.
61 // let (cur1, cur2, _) = encoder.encode(&mut encoder_buf[encoder_cur..], &mut stream_buf[stream_cur..]);
62 // encoder_cur += cur1;
63 // stream_cur += cur2;
64 //
65 // assert_eq!(stream_buf[..encoder_cur].to_vec().as_slice(), decode("028010").unwrap().as_slice());
66 // assert_eq!(stream_buf[..stream_cur].to_vec().as_slice(), decode("4a637573746f6d2d6b65790c637573746f6d2d76616c7565").unwrap().as_slice());
67 //
68 //
69 // ```
70 
71 pub struct QpackEncoder<'a> {
72     table: &'a mut DynamicTable,
73     // Headers to be encode.
74     field_iter: Option<PartsIter>,
75     // save the state of encoding field.
76     field_state: Option<ReprEncodeState>,
77     // save the state of decoding instructions.
78     inst_state: Option<InstDecodeState>,
79     // list of fields to be inserted.
80     insert_list: VecDeque<(Field, String)>,
81     insert_length: usize,
82     // `RFC`: the number of insertions that the decoder needs to receive before it can decode the field section.
83     required_insert_count: usize,
84 
85     stream_id: usize,
86     // allow reference to the inserting field default is false.
87     allow_post: bool,
88     // RFC9204-2.1.1.1. if index<draining_index, then execute Duplicate.
89     draining_index: usize,
90 }
91 
92 impl<'a> QpackEncoder<'a> {
93 
94     /// create a new encoder.
95     /// #Examples
96 //     ```no_run
97 //     use ylong_http::h3::qpack::encoder::QpackEncoder;
98 //     use ylong_http::h3::qpack::table::DynamicTable;
99 //     let mut encoder_buf = [0u8; 1024]; // QPACK stream providing control commands.
100 //     let mut stream_buf = [0u8; 1024]; // Field section encoded in QPACK format.
101 //     let mut encoder_cur = 0; // index of encoder_buf.
102 //     let mut stream_cur = 0; // index of stream_buf.
103 //     let mut table = DynamicTable::with_empty();
104 //
105 //     // create a new encoder.
106 //     let mut encoder = QpackEncoder::new(&mut table, 0, true, 1);
107 //     ```
new( table: &'a mut DynamicTable, stream_id: usize, allow_post: bool, draining_index: usize, ) -> QpackEncoder108     pub fn new(
109         table: &'a mut DynamicTable,
110         stream_id: usize,
111         allow_post: bool,
112         draining_index: usize,
113     ) -> QpackEncoder {
114         Self {
115             table,
116             field_iter: None,
117             field_state: None,
118             inst_state: None,
119             insert_list: VecDeque::new(),
120             insert_length: 0,
121             required_insert_count: 0,
122             stream_id,
123             allow_post,
124             draining_index,
125         }
126     }
127 
128     /// Set the maximum dynamic table size.
129     /// # Examples
130     /// ```no_run
131     /// use ylong_http::h3::qpack::encoder::QpackEncoder;
132     /// use ylong_http::h3::qpack::table::DynamicTable;
133     /// let mut encoder_buf = [0u8; 1024]; // QPACK stream providing control commands.
134     /// let mut stream_buf = [0u8; 1024]; // Field section encoded in QPACK format.
135     /// let mut encoder_cur = 0; // index of encoder_buf.
136     /// let mut stream_cur = 0; // index of stream_buf.
137     /// let mut table = DynamicTable::with_empty();
138     /// let mut encoder = QpackEncoder::new(&mut table, 0, true, 1);
139     /// let mut encoder_cur = encoder.set_capacity(220, &mut encoder_buf[..]);
140     /// ```
set_capacity(&mut self, max_size: usize, encoder_buf: &mut [u8]) -> usize141     pub fn set_capacity(&mut self, max_size: usize, encoder_buf: &mut [u8]) -> usize {
142         self.table.update_size(max_size);
143         if let Ok(cur) = SetCap::new(max_size).encode(&mut encoder_buf[..]) {
144             return cur;
145         }
146         0
147     }
148 
149 
150     /// Set the field section to be encoded.
151     /// # Examples
152 //     ```no_run
153 //     use ylong_http::h3::qpack::encoder::QpackEncoder;
154 //     use ylong_http::h3::parts::Parts;
155 //     use ylong_http::h3::qpack::table::{DynamicTable, Field};
156 //     let mut table = DynamicTable::with_empty();
157 //     let mut encoder = QpackEncoder::new(&mut table, 0, true, 1);
158 //     let mut parts = Parts::new();
159 //     parts.update(Field::Other(String::from("custom-key")), String::from("custom-value"));
160 //     encoder.set_parts(parts);
161 //     ```
set_parts(&mut self, parts: Parts)162     pub fn set_parts(&mut self, parts: Parts) {
163         self.field_iter = Some(PartsIter::new(parts));
164     }
165 
ack(&mut self, stream_id: usize) -> Result<Option<DecoderInst>, H3errorQpack>166     fn ack(&mut self, stream_id: usize) -> Result<Option<DecoderInst>, H3errorQpack> {
167         assert_eq!(stream_id, self.stream_id);
168 
169         if self.table.known_received_count < self.required_insert_count {
170             self.table.known_received_count = self.required_insert_count;
171         } else {
172             return Err(H3errorQpack::ConnectionError(DecoderStreamError));
173         }
174 
175         Ok(Some(DecoderInst::Ack))
176     }
177 
178     /// Users can call `decode_ins` multiple times to decode decoder instructions.
179     /// # Return
180     /// `Ok(None)` means that the decoder instruction is not complete.
181     /// # Examples
182 //     ```no_run
183 //     use ylong_http::h3::qpack::encoder::QpackEncoder;
184 //     use ylong_http::h3::parts::Parts;
185 //     use ylong_http::h3::qpack::table::{DynamicTable, Field};
186 //     use ylong_http::test_util::decode;
187 //     let mut table = DynamicTable::with_empty();
188 //     let mut encoder = QpackEncoder::new(&mut table, 0, true, 1);
189 //     let _ = encoder.decode_ins(&mut decode("80").unwrap().as_slice());
190 //     ```
decode_ins(&mut self, buf: &[u8]) -> Result<Option<DecoderInst>, H3errorQpack>191     pub fn decode_ins(&mut self, buf: &[u8]) -> Result<Option<DecoderInst>, H3errorQpack> {
192         let mut decoder = DecInstDecoder::new(buf);
193 
194         match decoder.decode(&mut self.inst_state)? {
195             Some(DecoderInstruction::Ack { stream_id }) => self.ack(stream_id),
196             //todo: stream cancel
197             Some(DecoderInstruction::StreamCancel { stream_id }) => {
198                 assert_eq!(stream_id, self.stream_id);
199                 Ok(Some(DecoderInst::StreamCancel))
200             }
201             //todo: insert count increment
202             Some(DecoderInstruction::InsertCountIncrement { increment }) => {
203                 self.table.known_received_count += increment;
204                 Ok(Some(DecoderInst::InsertCountIncrement))
205             }
206             None => Ok(None),
207         }
208     }
209 
get_prefix(&self, prefix_buf: &mut [u8]) -> usize210     fn get_prefix(&self, prefix_buf: &mut [u8]) -> usize {
211         let mut cur_prefix = 0;
212         let mut wire_ric = 0;
213         if self.required_insert_count != 0 {
214             wire_ric = self.required_insert_count % (2 * self.table.max_entries()) + 1;
215         }
216 
217         cur_prefix += Integer::index(0x00, wire_ric, 0xff)
218             .encode(&mut prefix_buf[..])
219             .unwrap_or(0);
220         let base = self.table.insert_count;
221         println!("base: {}", base);
222         println!("required_insert_count: {}", self.required_insert_count);
223         if base >= self.required_insert_count {
224             cur_prefix += Integer::index(0x00, base - self.required_insert_count, 0x7f)
225                 .encode(&mut prefix_buf[cur_prefix..])
226                 .unwrap_or(0);
227         } else {
228             cur_prefix += Integer::index(0x80, self.required_insert_count - base - 1, 0x7f)
229                 .encode(&mut prefix_buf[cur_prefix..])
230                 .unwrap_or(0);
231         }
232         cur_prefix
233     }
234     /// Users can call `encode` multiple times to encode multiple complete field sections.
235     /// # Examples
236 //     ```no_run
237 //     use ylong_http::h3::qpack::encoder::QpackEncoder;
238 //     use ylong_http::h3::parts::Parts;
239 //     use ylong_http::h3::qpack::table::{DynamicTable, Field};
240 //     use ylong_http::test_util::decode;
241 //     let mut encoder_buf = [0u8; 1024]; // QPACK stream providing control commands.
242 //     let mut stream_buf = [0u8; 1024]; // Field section encoded in QPACK format.
243 //     let mut encoder_cur = 0; // index of encoder_buf.
244 //     let mut stream_cur = 0; // index of stream_buf.
245 //     let mut table = DynamicTable::with_empty();
246 //     let mut encoder = QpackEncoder::new(&mut table, 0, true, 1);
247 //     let mut parts = Parts::new();
248 //     parts.update(Field::Other(String::from("custom-key")), String::from("custom-value"));
249 //     encoder.set_parts(parts);
250 //     let (cur1, cur2, _) = encoder.encode(&mut encoder_buf[encoder_cur..], &mut stream_buf[stream_cur..]);
251 //     encoder_cur += cur1;
252 //     stream_cur += cur2;
253 //     ```
encode( &mut self, encoder_buf: &mut [u8], stream_buf: &mut [u8], ) -> (usize, usize, Option<([u8; 1024], usize)>)254     pub fn encode(
255         &mut self,
256         encoder_buf: &mut [u8], //instructions encoded results
257         stream_buf: &mut [u8],  //headers encoded results
258     ) -> (usize, usize, Option<([u8; 1024], usize)>) {
259         let (mut cur_encoder, mut cur_stream) = (0, 0);
260         if self.is_finished() {
261             // denote an end of field section
262             // self.stream_reference.push_back(None);
263             //todo: size of prefix_buf
264             let mut prefix_buf = [0u8; 1024];
265             let cur_prefix = self.get_prefix(&mut prefix_buf[0..]);
266             for (field, value) in self.insert_list.iter() {
267                 self.table.update(field.clone(), value.clone());
268             }
269             (cur_encoder, cur_stream, Some((prefix_buf, cur_prefix)))
270         } else {
271             let mut encoder = ReprEncoder::new(
272                 self.table,
273                 self.draining_index,
274                 self.allow_post,
275                 &mut self.insert_length,
276             );
277             (cur_encoder, cur_stream) = encoder.encode(
278                 &mut self.field_iter,
279                 &mut self.field_state,
280                 &mut encoder_buf[0..],
281                 &mut stream_buf[0..],
282                 &mut self.insert_list,
283                 &mut self.required_insert_count,
284             );
285             (cur_encoder, cur_stream, None)
286         }
287     }
288 
289     /// Check the previously set `Parts` if encoding is complete.
is_finished(&self) -> bool290     pub(crate) fn is_finished(&self) -> bool {
291         self.field_iter.is_none() && self.field_state.is_none()
292     }
293 }
294 
295 pub enum DecoderInst {
296     Ack,
297     StreamCancel,
298     InsertCountIncrement,
299 }
300 
301 #[cfg(test)]
302 mod ut_qpack_encoder {
303     use crate::h3::parts::Parts;
304     use crate::h3::qpack::encoder;
305     use crate::h3::qpack::encoder::QpackEncoder;
306     use crate::h3::qpack::table::{DynamicTable, Field};
307     use crate::util::test_util::decode;
308     macro_rules! qpack_test_cases {
309             ($enc: expr,$encoder_buf:expr,$encoder_cur:expr, $len: expr, $res: literal,$encoder_res: literal, $size: expr, { $($h: expr, $v: expr $(,)?)*} $(,)?) => {
310                 let mut _encoder = $enc;
311                 let mut stream_buf = [0u8; $len];
312                 let mut stream_cur = 0;
313                 $(
314                     let mut parts = Parts::new();
315                     parts.update($h, $v);
316                     _encoder.set_parts(parts);
317                     let (cur1,cur2,_) = _encoder.encode(&mut $encoder_buf[$encoder_cur..],&mut stream_buf[stream_cur..]);
318                     $encoder_cur += cur1;
319                     stream_cur += cur2;
320                 )*
321                 let (cur1, cur2, prefix) = _encoder.encode(&mut $encoder_buf[$encoder_cur..],&mut stream_buf[stream_cur..]);
322                 $encoder_cur += cur1;
323                 stream_cur += cur2;
324                 if let Some((prefix_buf,cur_prefix)) = prefix{
325                     stream_buf.copy_within(0..stream_cur,cur_prefix);
326                     stream_buf[..cur_prefix].copy_from_slice(&prefix_buf[..cur_prefix]);
327                     stream_cur += cur_prefix;
328                 }
329                 println!("stream_buf: {:#?}",stream_buf);
330                 let result = decode($res).unwrap();
331                 if let Some(res) = decode($encoder_res){
332                     assert_eq!($encoder_buf[..$encoder_cur].to_vec().as_slice(), res.as_slice());
333                 }
334                 assert_eq!(stream_cur, $len);
335                 assert_eq!(stream_buf.as_slice(), result.as_slice());
336                 assert_eq!(_encoder.table.size(), $size);
337             }
338         }
339     #[test]
340     /// The encoder sends an encoded field section containing a literal representation of a field
341     /// with a static name reference.
literal_field_line_with_name_reference()342     fn literal_field_line_with_name_reference() {
343         println!("literal_field_line_with_name_reference");
344         let mut encoder_buf = [0u8; 1024];
345         let mut table = DynamicTable::with_empty();
346         let mut encoder = QpackEncoder::new(&mut table, 0, false, 0);
347         let mut encoder_cur = encoder.set_capacity(0, &mut encoder_buf[..]);
348         qpack_test_cases!(
349             encoder,
350             encoder_buf,
351             encoder_cur,
352             15, "0000510b2f696e6465782e68746d6c",
353             "20",
354             0,
355             {
356                 Field::Path,
357                 String::from("/index.html"),
358             },
359         );
360     }
361 
362     #[test]
363     ///The encoder sets the dynamic table capacity, inserts a header with a dynamic name
364     /// reference, then sends a potentially blocking, encoded field section referencing
365     /// this new entry. The decoder acknowledges processing the encoded field section,
366     /// which implicitly acknowledges all dynamic table insertions up to the Required
367     /// Insert Count.
dynamic_table()368     fn dynamic_table() {
369         let mut encoder_buf = [0u8; 1024];
370         let mut table = DynamicTable::with_empty();
371         let mut encoder = QpackEncoder::new(&mut table, 0, true, 0);
372         let mut encoder_cur = encoder.set_capacity(220, &mut encoder_buf[..]);
373         qpack_test_cases!(
374             encoder,
375             encoder_buf,
376             encoder_cur,
377             4, "03811011",
378             "3fbd01c00f7777772e6578616d706c652e636f6dc10c2f73616d706c652f70617468",
379             106,
380             {
381                 Field::Authority,
382                 String::from("www.example.com"),
383                 Field::Path,
384                 String::from("/sample/path"),
385             },
386         );
387     }
388 
389     #[test]
390     ///The encoder inserts a header into the dynamic table with a literal name.
391     /// The decoder acknowledges receipt of the entry. The encoder does not send any
392     /// encoded field sections.
speculative_insert()393     fn speculative_insert() {
394         let mut encoder_buf = [0u8; 1024];
395         let mut table = DynamicTable::with_empty();
396         let mut encoder = QpackEncoder::new(&mut table, 0, true, 0);
397         let _ = encoder.set_capacity(220, &mut encoder_buf[..]);
398         let mut encoder_cur = 0;
399         qpack_test_cases!(
400             encoder,
401             encoder_buf,
402             encoder_cur,
403             3, "028010",
404             "4a637573746f6d2d6b65790c637573746f6d2d76616c7565",
405             54,
406             {
407                 Field::Other(String::from("custom-key")),
408                 String::from("custom-value"),
409             },
410         );
411     }
412 
413     #[test]
duplicate_instruction_stream_cancellation()414     fn duplicate_instruction_stream_cancellation() {
415         let mut encoder_buf = [0u8; 1024];
416         let mut table = DynamicTable::with_empty();
417         let mut encoder = QpackEncoder::new(&mut table, 0, true, 1);
418         let _ = encoder.set_capacity(4096, &mut encoder_buf[..]);
419         encoder
420             .table
421             .update(Field::Authority, String::from("www.example.com"));
422         encoder
423             .table
424             .update(Field::Path, String::from("/sample/path"));
425         encoder.table.update(
426             Field::Other(String::from("custom-key")),
427             String::from("custom-value"),
428         );
429         encoder.required_insert_count = 3;
430         let mut encoder_cur = 0;
431         qpack_test_cases!(
432             encoder,
433             encoder_buf,
434             encoder_cur,
435             5, "050080c181",
436             "02",
437             274,
438             {
439                 Field::Authority,
440                 String::from("www.example.com"),
441                 Field::Path,
442                 String::from("/"),
443                 Field::Other(String::from("custom-key")),
444                 String::from("custom-value")
445             },
446         );
447     }
448 
449     #[test]
dynamic_table_insert_eviction()450     fn dynamic_table_insert_eviction() {
451         let mut encoder_buf = [0u8; 1024];
452         let mut table = DynamicTable::with_empty();
453         let mut encoder = QpackEncoder::new(&mut table, 0, true, 1);
454         let _ = encoder.set_capacity(4096, &mut encoder_buf[..]);
455         encoder
456             .table
457             .update(Field::Authority, String::from("www.example.com"));
458         encoder
459             .table
460             .update(Field::Path, String::from("/sample/path"));
461         encoder.table.update(
462             Field::Other(String::from("custom-key")),
463             String::from("custom-value"),
464         );
465         encoder
466             .table
467             .update(Field::Authority, String::from("www.example.com"));
468         encoder.required_insert_count = 3; //acked
469         let mut encoder_cur = 0;
470         qpack_test_cases!(
471             encoder,
472             encoder_buf,
473             encoder_cur,
474             3, "040183",
475             "810d637573746f6d2d76616c756532",
476             272,
477             {
478                 Field::Other(String::from("custom-key")),
479                 String::from("custom-value2")
480             },
481         );
482     }
483 
484     #[test]
test_ack()485     fn test_ack() {
486         let mut encoder_buf = [0u8; 1024];
487         let mut table = DynamicTable::with_empty();
488         let mut encoder = QpackEncoder::new(&mut table, 0, true, 1);
489         let mut encoder_cur = encoder.set_capacity(4096, &mut encoder_buf[..]);
490 
491         let field_list: [(Field, String); 3] = [
492             (Field::Authority, String::from("www.example.com")),
493             (Field::Path, String::from("/sample/path")),
494             (
495                 Field::Other(String::from("custom-key")),
496                 String::from("custom-value"),
497             ),
498         ];
499         let mut stream_cur = 0;
500         for (field, value) in field_list.iter() {
501             let mut parts = Parts::new();
502             parts.update(field.clone(), value.clone());
503             encoder.set_parts(parts);
504             let mut stream_buf = [0u8; 1024];
505             let (cur1, cur2, _) = encoder.encode(
506                 &mut encoder_buf[encoder_cur..],
507                 &mut stream_buf[stream_cur..],
508             );
509             encoder_cur += cur1;
510             stream_cur += cur2;
511         }
512         let _ = encoder.decode_ins(decode("80").unwrap().as_slice());
513         assert_eq!(encoder.table.known_received_count, 3);
514     }
515 
516     #[test]
encode_post_name()517     fn encode_post_name() {
518         let mut encoder_buf = [0u8; 1024];
519         let mut table = DynamicTable::with_empty();
520         let mut encoder = QpackEncoder::new(&mut table, 0, true, 1);
521         let _ = encoder.set_capacity(60, &mut encoder_buf[..]);
522         let mut encoder_cur = 0;
523         let mut stream_buf = [0u8; 100];
524         let mut stream_cur = 0;
525         let mut parts = Parts::new();
526         parts.update(
527             Field::Other(String::from("custom-key")),
528             String::from("custom-value1"),
529         );
530         encoder.set_parts(parts);
531         let (cur1, cur2, _) = encoder.encode(
532             &mut encoder_buf[encoder_cur..],
533             &mut stream_buf[stream_cur..],
534         );
535         encoder_cur += cur1;
536         stream_cur += cur2;
537         let mut parts = Parts::new();
538         parts.update(
539             Field::Other(String::from("custom-key")),
540             String::from("custom-value2"),
541         );
542         encoder.set_parts(parts);
543         let (cur1, cur2, _) = encoder.encode(
544             &mut encoder_buf[encoder_cur..],
545             &mut stream_buf[stream_cur..],
546         );
547         encoder_cur += cur1;
548         stream_cur += cur2;
549         assert_eq!(
550             [16, 0, 13, 99, 117, 115, 116, 111, 109, 45, 118, 97, 108, 117, 101, 50],
551             stream_buf[..stream_cur]
552         );
553         assert_eq!(
554             [
555                 74, 99, 117, 115, 116, 111, 109, 45, 107, 101, 121, 13, 99, 117, 115, 116, 111,
556                 109, 45, 118, 97, 108, 117, 101, 49
557             ],
558             encoder_buf[..encoder_cur]
559         )
560     }
561     #[test]
test_indexing_with_litreal()562     fn test_indexing_with_litreal() {
563         let mut encoder_buf = [0u8; 1024];
564         let mut table = DynamicTable::with_empty();
565         let mut encoder = QpackEncoder::new(&mut table, 0, false, 1);
566         let _ = encoder.set_capacity(60, &mut encoder_buf[..]);
567         let encoder_cur = 0;
568         let mut stream_buf = [0u8; 100];
569         let mut stream_cur = 0;
570         let mut parts = Parts::new();
571         parts.update(
572             Field::Other(String::from("custom-key")),
573             String::from("custom-value1"),
574         );
575         encoder.set_parts(parts);
576         let (_, cur2, _) = encoder.encode(
577             &mut encoder_buf[encoder_cur..],
578             &mut stream_buf[stream_cur..],
579         );
580         stream_cur += cur2;
581 
582         assert_eq!(
583             [
584                 39, 3, 99, 117, 115, 116, 111, 109, 45, 107, 101, 121, 13, 99, 117, 115, 116, 111,
585                 109, 45, 118, 97, 108, 117, 101, 49
586             ],
587             stream_buf[..stream_cur]
588         );
589     }
590 }
591