1 // Copyright (C) 2019, Cloudflare, Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright notice,
9 //       this list of conditions and the following disclaimer.
10 //
11 //     * Redistributions in binary form must reproduce the above copyright
12 //       notice, this list of conditions and the following disclaimer in the
13 //       documentation and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 use super::Result;
28 
29 use crate::octets;
30 
31 pub const DATA_FRAME_TYPE_ID: u64 = 0x0;
32 pub const HEADERS_FRAME_TYPE_ID: u64 = 0x1;
33 pub const CANCEL_PUSH_FRAME_TYPE_ID: u64 = 0x3;
34 pub const SETTINGS_FRAME_TYPE_ID: u64 = 0x4;
35 pub const PUSH_PROMISE_FRAME_TYPE_ID: u64 = 0x5;
36 pub const GOAWAY_FRAME_TYPE_ID: u64 = 0x6;
37 pub const MAX_PUSH_FRAME_TYPE_ID: u64 = 0xD;
38 
39 const SETTINGS_QPACK_MAX_TABLE_CAPACITY: u64 = 0x1;
40 const SETTINGS_MAX_HEADER_LIST_SIZE: u64 = 0x6;
41 const SETTINGS_QPACK_BLOCKED_STREAMS: u64 = 0x7;
42 const SETTINGS_H3_DATAGRAM: u64 = 0x276;
43 
44 // Permit between 16 maximally-encoded and 128 minimally-encoded SETTINGS.
45 const MAX_SETTINGS_PAYLOAD_SIZE: usize = 256;
46 
47 #[derive(Clone, PartialEq)]
48 pub enum Frame {
49     Data {
50         payload: Vec<u8>,
51     },
52 
53     Headers {
54         header_block: Vec<u8>,
55     },
56 
57     CancelPush {
58         push_id: u64,
59     },
60 
61     Settings {
62         max_header_list_size: Option<u64>,
63         qpack_max_table_capacity: Option<u64>,
64         qpack_blocked_streams: Option<u64>,
65         h3_datagram: Option<u64>,
66         grease: Option<(u64, u64)>,
67     },
68 
69     PushPromise {
70         push_id: u64,
71         header_block: Vec<u8>,
72     },
73 
74     GoAway {
75         id: u64,
76     },
77 
78     MaxPushId {
79         push_id: u64,
80     },
81 
82     Unknown,
83 }
84 
85 impl Frame {
from_bytes( frame_type: u64, payload_length: u64, bytes: &[u8], ) -> Result<Frame>86     pub fn from_bytes(
87         frame_type: u64, payload_length: u64, bytes: &[u8],
88     ) -> Result<Frame> {
89         let mut b = octets::Octets::with_slice(bytes);
90 
91         // TODO: handling of 0-length frames
92         let frame = match frame_type {
93             DATA_FRAME_TYPE_ID => Frame::Data {
94                 payload: b.get_bytes(payload_length as usize)?.to_vec(),
95             },
96 
97             HEADERS_FRAME_TYPE_ID => Frame::Headers {
98                 header_block: b.get_bytes(payload_length as usize)?.to_vec(),
99             },
100 
101             CANCEL_PUSH_FRAME_TYPE_ID => Frame::CancelPush {
102                 push_id: b.get_varint()?,
103             },
104 
105             SETTINGS_FRAME_TYPE_ID =>
106                 parse_settings_frame(&mut b, payload_length as usize)?,
107 
108             PUSH_PROMISE_FRAME_TYPE_ID =>
109                 parse_push_promise(payload_length, &mut b)?,
110 
111             GOAWAY_FRAME_TYPE_ID => Frame::GoAway {
112                 id: b.get_varint()?,
113             },
114 
115             MAX_PUSH_FRAME_TYPE_ID => Frame::MaxPushId {
116                 push_id: b.get_varint()?,
117             },
118 
119             _ => Frame::Unknown,
120         };
121 
122         Ok(frame)
123     }
124 
to_bytes(&self, b: &mut octets::OctetsMut) -> Result<usize>125     pub fn to_bytes(&self, b: &mut octets::OctetsMut) -> Result<usize> {
126         let before = b.cap();
127 
128         match self {
129             Frame::Data { payload } => {
130                 b.put_varint(DATA_FRAME_TYPE_ID)?;
131                 b.put_varint(payload.len() as u64)?;
132 
133                 b.put_bytes(payload.as_ref())?;
134             },
135 
136             Frame::Headers { header_block } => {
137                 b.put_varint(HEADERS_FRAME_TYPE_ID)?;
138                 b.put_varint(header_block.len() as u64)?;
139 
140                 b.put_bytes(header_block.as_ref())?;
141             },
142 
143             Frame::CancelPush { push_id } => {
144                 b.put_varint(CANCEL_PUSH_FRAME_TYPE_ID)?;
145                 b.put_varint(octets::varint_len(*push_id) as u64)?;
146 
147                 b.put_varint(*push_id)?;
148             },
149 
150             Frame::Settings {
151                 max_header_list_size,
152                 qpack_max_table_capacity,
153                 qpack_blocked_streams,
154                 h3_datagram,
155                 grease,
156             } => {
157                 let mut len = 0;
158 
159                 if let Some(val) = max_header_list_size {
160                     len += octets::varint_len(SETTINGS_MAX_HEADER_LIST_SIZE);
161                     len += octets::varint_len(*val);
162                 }
163 
164                 if let Some(val) = qpack_max_table_capacity {
165                     len += octets::varint_len(SETTINGS_QPACK_MAX_TABLE_CAPACITY);
166                     len += octets::varint_len(*val);
167                 }
168 
169                 if let Some(val) = qpack_blocked_streams {
170                     len += octets::varint_len(SETTINGS_QPACK_BLOCKED_STREAMS);
171                     len += octets::varint_len(*val);
172                 }
173 
174                 if let Some(val) = h3_datagram {
175                     len += octets::varint_len(SETTINGS_H3_DATAGRAM);
176                     len += octets::varint_len(*val);
177                 }
178 
179                 if let Some(val) = grease {
180                     len += octets::varint_len(val.0);
181                     len += octets::varint_len(val.1);
182                 }
183 
184                 b.put_varint(SETTINGS_FRAME_TYPE_ID)?;
185                 b.put_varint(len as u64)?;
186 
187                 if let Some(val) = max_header_list_size {
188                     b.put_varint(SETTINGS_MAX_HEADER_LIST_SIZE)?;
189                     b.put_varint(*val as u64)?;
190                 }
191 
192                 if let Some(val) = qpack_max_table_capacity {
193                     b.put_varint(SETTINGS_QPACK_MAX_TABLE_CAPACITY)?;
194                     b.put_varint(*val as u64)?;
195                 }
196 
197                 if let Some(val) = qpack_blocked_streams {
198                     b.put_varint(SETTINGS_QPACK_BLOCKED_STREAMS)?;
199                     b.put_varint(*val as u64)?;
200                 }
201 
202                 if let Some(val) = h3_datagram {
203                     b.put_varint(SETTINGS_H3_DATAGRAM)?;
204                     b.put_varint(*val as u64)?;
205                 }
206 
207                 if let Some(val) = grease {
208                     b.put_varint(val.0)?;
209                     b.put_varint(val.1)?;
210                 }
211             },
212 
213             Frame::PushPromise {
214                 push_id,
215                 header_block,
216             } => {
217                 let len = octets::varint_len(*push_id) + header_block.len();
218                 b.put_varint(PUSH_PROMISE_FRAME_TYPE_ID)?;
219                 b.put_varint(len as u64)?;
220 
221                 b.put_varint(*push_id)?;
222                 b.put_bytes(header_block.as_ref())?;
223             },
224 
225             Frame::GoAway { id } => {
226                 b.put_varint(GOAWAY_FRAME_TYPE_ID)?;
227                 b.put_varint(octets::varint_len(*id) as u64)?;
228 
229                 b.put_varint(*id)?;
230             },
231 
232             Frame::MaxPushId { push_id } => {
233                 b.put_varint(MAX_PUSH_FRAME_TYPE_ID)?;
234                 b.put_varint(octets::varint_len(*push_id) as u64)?;
235 
236                 b.put_varint(*push_id)?;
237             },
238 
239             Frame::Unknown => unreachable!(),
240         }
241 
242         Ok(before - b.cap())
243     }
244 }
245 
246 impl std::fmt::Debug for Frame {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result247     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
248         match self {
249             Frame::Data { payload } => {
250                 write!(f, "DATA len={}", payload.len())?;
251             },
252 
253             Frame::Headers { header_block } => {
254                 write!(f, "HEADERS len={}", header_block.len())?;
255             },
256 
257             Frame::CancelPush { push_id } => {
258                 write!(f, "CANCEL_PUSH push_id={}", push_id)?;
259             },
260 
261             Frame::Settings {
262                 max_header_list_size,
263                 qpack_max_table_capacity,
264                 qpack_blocked_streams,
265                 ..
266             } => {
267                 write!(f, "SETTINGS max_headers={:?}, qpack_max_table={:?}, qpack_blocked={:?} ", max_header_list_size, qpack_max_table_capacity, qpack_blocked_streams)?;
268             },
269 
270             Frame::PushPromise {
271                 push_id,
272                 header_block,
273             } => {
274                 write!(
275                     f,
276                     "PUSH_PROMISE push_id={} len={}",
277                     push_id,
278                     header_block.len()
279                 )?;
280             },
281 
282             Frame::GoAway { id } => {
283                 write!(f, "GOAWAY id={}", id)?;
284             },
285 
286             Frame::MaxPushId { push_id } => {
287                 write!(f, "MAX_PUSH_ID push_id={}", push_id)?;
288             },
289 
290             Frame::Unknown => {
291                 write!(f, "UNKNOWN")?;
292             },
293         }
294 
295         Ok(())
296     }
297 }
298 
parse_settings_frame( b: &mut octets::Octets, settings_length: usize, ) -> Result<Frame>299 fn parse_settings_frame(
300     b: &mut octets::Octets, settings_length: usize,
301 ) -> Result<Frame> {
302     let mut max_header_list_size = None;
303     let mut qpack_max_table_capacity = None;
304     let mut qpack_blocked_streams = None;
305     let mut h3_datagram = None;
306 
307     // Reject SETTINGS frames that are too long.
308     if settings_length > MAX_SETTINGS_PAYLOAD_SIZE {
309         return Err(super::Error::ExcessiveLoad);
310     }
311 
312     while b.off() < settings_length {
313         let setting_ty = b.get_varint()?;
314         let settings_val = b.get_varint()?;
315 
316         match setting_ty {
317             SETTINGS_QPACK_MAX_TABLE_CAPACITY => {
318                 qpack_max_table_capacity = Some(settings_val);
319             },
320 
321             SETTINGS_MAX_HEADER_LIST_SIZE => {
322                 max_header_list_size = Some(settings_val);
323             },
324 
325             SETTINGS_QPACK_BLOCKED_STREAMS => {
326                 qpack_blocked_streams = Some(settings_val);
327             },
328 
329             SETTINGS_H3_DATAGRAM => {
330                 if settings_val > 1 {
331                     return Err(super::Error::SettingsError);
332                 }
333 
334                 h3_datagram = Some(settings_val);
335             },
336 
337             // Reserved values overlap with HTTP/2 and MUST be rejected
338             0x0 | 0x2 | 0x3 | 0x4 | 0x5 =>
339                 return Err(super::Error::SettingsError),
340 
341             // Unknown Settings parameters must be ignored.
342             _ => (),
343         }
344     }
345 
346     Ok(Frame::Settings {
347         max_header_list_size,
348         qpack_max_table_capacity,
349         qpack_blocked_streams,
350         h3_datagram,
351         grease: None,
352     })
353 }
354 
parse_push_promise( payload_length: u64, b: &mut octets::Octets, ) -> Result<Frame>355 fn parse_push_promise(
356     payload_length: u64, b: &mut octets::Octets,
357 ) -> Result<Frame> {
358     let push_id = b.get_varint()?;
359     let header_block_length = payload_length - octets::varint_len(push_id) as u64;
360     let header_block = b.get_bytes(header_block_length as usize)?.to_vec();
361 
362     Ok(Frame::PushPromise {
363         push_id,
364         header_block,
365     })
366 }
367 
368 #[cfg(test)]
369 mod tests {
370     use super::*;
371 
372     #[test]
data()373     fn data() {
374         let mut d = [42; 128];
375 
376         let payload = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
377         let frame_payload_len = payload.len();
378         let frame_header_len = 2;
379 
380         let frame = Frame::Data { payload };
381 
382         let wire_len = {
383             let mut b = octets::OctetsMut::with_slice(&mut d);
384             frame.to_bytes(&mut b).unwrap()
385         };
386 
387         assert_eq!(wire_len, frame_header_len + frame_payload_len);
388 
389         assert_eq!(
390             Frame::from_bytes(
391                 DATA_FRAME_TYPE_ID,
392                 frame_payload_len as u64,
393                 &d[frame_header_len..]
394             )
395             .unwrap(),
396             frame
397         );
398     }
399 
400     #[test]
headers()401     fn headers() {
402         let mut d = [42; 128];
403 
404         let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
405         let frame_payload_len = header_block.len();
406         let frame_header_len = 2;
407 
408         let frame = Frame::Headers { header_block };
409 
410         let wire_len = {
411             let mut b = octets::OctetsMut::with_slice(&mut d);
412             frame.to_bytes(&mut b).unwrap()
413         };
414 
415         assert_eq!(wire_len, frame_header_len + frame_payload_len);
416 
417         assert_eq!(
418             Frame::from_bytes(
419                 HEADERS_FRAME_TYPE_ID,
420                 frame_payload_len as u64,
421                 &d[frame_header_len..]
422             )
423             .unwrap(),
424             frame
425         );
426     }
427 
428     #[test]
cancel_push()429     fn cancel_push() {
430         let mut d = [42; 128];
431 
432         let frame = Frame::CancelPush { push_id: 0 };
433 
434         let frame_payload_len = 1;
435         let frame_header_len = 2;
436 
437         let wire_len = {
438             let mut b = octets::OctetsMut::with_slice(&mut d);
439             frame.to_bytes(&mut b).unwrap()
440         };
441 
442         assert_eq!(wire_len, frame_header_len + frame_payload_len);
443 
444         assert_eq!(
445             Frame::from_bytes(
446                 CANCEL_PUSH_FRAME_TYPE_ID,
447                 frame_payload_len as u64,
448                 &d[frame_header_len..]
449             )
450             .unwrap(),
451             frame
452         );
453     }
454 
455     #[test]
settings_all_no_grease()456     fn settings_all_no_grease() {
457         let mut d = [42; 128];
458 
459         let frame = Frame::Settings {
460             max_header_list_size: Some(0),
461             qpack_max_table_capacity: Some(0),
462             qpack_blocked_streams: Some(0),
463             h3_datagram: Some(0),
464             grease: None,
465         };
466 
467         let frame_payload_len = 9;
468         let frame_header_len = 2;
469 
470         let wire_len = {
471             let mut b = octets::OctetsMut::with_slice(&mut d);
472             frame.to_bytes(&mut b).unwrap()
473         };
474 
475         assert_eq!(wire_len, frame_header_len + frame_payload_len);
476 
477         assert_eq!(
478             Frame::from_bytes(
479                 SETTINGS_FRAME_TYPE_ID,
480                 frame_payload_len as u64,
481                 &d[frame_header_len..]
482             )
483             .unwrap(),
484             frame
485         );
486     }
487 
488     #[test]
settings_all_grease()489     fn settings_all_grease() {
490         let mut d = [42; 128];
491 
492         let frame = Frame::Settings {
493             max_header_list_size: Some(0),
494             qpack_max_table_capacity: Some(0),
495             qpack_blocked_streams: Some(0),
496             h3_datagram: Some(0),
497             grease: Some((33, 33)),
498         };
499 
500         // Frame parsing will always ignore GREASE values.
501         let frame_parsed = Frame::Settings {
502             max_header_list_size: Some(0),
503             qpack_max_table_capacity: Some(0),
504             qpack_blocked_streams: Some(0),
505             h3_datagram: Some(0),
506             grease: None,
507         };
508 
509         let frame_payload_len = 11;
510         let frame_header_len = 2;
511 
512         let wire_len = {
513             let mut b = octets::OctetsMut::with_slice(&mut d);
514             frame.to_bytes(&mut b).unwrap()
515         };
516 
517         assert_eq!(wire_len, frame_header_len + frame_payload_len);
518 
519         assert_eq!(
520             Frame::from_bytes(
521                 SETTINGS_FRAME_TYPE_ID,
522                 frame_payload_len as u64,
523                 &d[frame_header_len..]
524             )
525             .unwrap(),
526             frame_parsed
527         );
528     }
529 
530     #[test]
settings_h3_only()531     fn settings_h3_only() {
532         let mut d = [42; 128];
533 
534         let frame = Frame::Settings {
535             max_header_list_size: Some(1024),
536             qpack_max_table_capacity: None,
537             qpack_blocked_streams: None,
538             h3_datagram: None,
539             grease: None,
540         };
541 
542         let frame_payload_len = 3;
543         let frame_header_len = 2;
544 
545         let wire_len = {
546             let mut b = octets::OctetsMut::with_slice(&mut d);
547             frame.to_bytes(&mut b).unwrap()
548         };
549 
550         assert_eq!(wire_len, frame_header_len + frame_payload_len);
551 
552         assert_eq!(
553             Frame::from_bytes(
554                 SETTINGS_FRAME_TYPE_ID,
555                 frame_payload_len as u64,
556                 &d[frame_header_len..]
557             )
558             .unwrap(),
559             frame
560         );
561     }
562 
563     #[test]
settings_h3_dgram_only()564     fn settings_h3_dgram_only() {
565         let mut d = [42; 128];
566 
567         let frame = Frame::Settings {
568             max_header_list_size: None,
569             qpack_max_table_capacity: None,
570             qpack_blocked_streams: None,
571             h3_datagram: Some(1),
572             grease: None,
573         };
574 
575         let frame_payload_len = 3;
576         let frame_header_len = 2;
577 
578         let wire_len = {
579             let mut b = octets::OctetsMut::with_slice(&mut d);
580             frame.to_bytes(&mut b).unwrap()
581         };
582 
583         assert_eq!(wire_len, frame_header_len + frame_payload_len);
584 
585         assert_eq!(
586             Frame::from_bytes(
587                 SETTINGS_FRAME_TYPE_ID,
588                 frame_payload_len as u64,
589                 &d[frame_header_len..]
590             )
591             .unwrap(),
592             frame
593         );
594     }
595 
596     #[test]
settings_h3_dgram_bad()597     fn settings_h3_dgram_bad() {
598         let mut d = [42; 128];
599 
600         let frame = Frame::Settings {
601             max_header_list_size: None,
602             qpack_max_table_capacity: None,
603             qpack_blocked_streams: None,
604             h3_datagram: Some(5),
605             grease: None,
606         };
607 
608         let frame_payload_len = 3;
609         let frame_header_len = 2;
610 
611         let wire_len = {
612             let mut b = octets::OctetsMut::with_slice(&mut d);
613             frame.to_bytes(&mut b).unwrap()
614         };
615 
616         assert_eq!(wire_len, frame_header_len + frame_payload_len);
617 
618         assert_eq!(
619             Frame::from_bytes(
620                 SETTINGS_FRAME_TYPE_ID,
621                 frame_payload_len as u64,
622                 &d[frame_header_len..]
623             ),
624             Err(crate::h3::Error::SettingsError)
625         );
626     }
627 
628     #[test]
settings_qpack_only()629     fn settings_qpack_only() {
630         let mut d = [42; 128];
631 
632         let frame = Frame::Settings {
633             max_header_list_size: None,
634             qpack_max_table_capacity: Some(0),
635             qpack_blocked_streams: Some(0),
636             h3_datagram: None,
637             grease: None,
638         };
639 
640         let frame_payload_len = 4;
641         let frame_header_len = 2;
642 
643         let wire_len = {
644             let mut b = octets::OctetsMut::with_slice(&mut d);
645             frame.to_bytes(&mut b).unwrap()
646         };
647 
648         assert_eq!(wire_len, frame_header_len + frame_payload_len);
649 
650         assert_eq!(
651             Frame::from_bytes(
652                 SETTINGS_FRAME_TYPE_ID,
653                 frame_payload_len as u64,
654                 &d[frame_header_len..]
655             )
656             .unwrap(),
657             frame
658         );
659     }
660 
661     #[test]
settings_h2_prohibited()662     fn settings_h2_prohibited() {
663         // We need to test the prohibited values (0x0 | 0x2 | 0x3 | 0x4 | 0x5)
664         // but the quiche API doesn't support that, so use a manually created
665         // frame data buffer where d[frame_header_len] is the SETTING type field.
666         let frame_payload_len = 2u64;
667         let frame_header_len = 2;
668         let mut d = [
669             SETTINGS_FRAME_TYPE_ID as u8,
670             frame_payload_len as u8,
671             0x0,
672             1,
673         ];
674 
675         assert_eq!(
676             Frame::from_bytes(
677                 SETTINGS_FRAME_TYPE_ID,
678                 frame_payload_len,
679                 &d[frame_header_len..]
680             ),
681             Err(crate::h3::Error::SettingsError)
682         );
683 
684         d[frame_header_len] = 0x2;
685 
686         assert_eq!(
687             Frame::from_bytes(
688                 SETTINGS_FRAME_TYPE_ID,
689                 frame_payload_len,
690                 &d[frame_header_len..]
691             ),
692             Err(crate::h3::Error::SettingsError)
693         );
694 
695         d[frame_header_len] = 0x3;
696 
697         assert_eq!(
698             Frame::from_bytes(
699                 SETTINGS_FRAME_TYPE_ID,
700                 frame_payload_len,
701                 &d[frame_header_len..]
702             ),
703             Err(crate::h3::Error::SettingsError)
704         );
705 
706         d[frame_header_len] = 0x4;
707 
708         assert_eq!(
709             Frame::from_bytes(
710                 SETTINGS_FRAME_TYPE_ID,
711                 frame_payload_len,
712                 &d[frame_header_len..]
713             ),
714             Err(crate::h3::Error::SettingsError)
715         );
716 
717         d[frame_header_len] = 0x5;
718 
719         assert_eq!(
720             Frame::from_bytes(
721                 SETTINGS_FRAME_TYPE_ID,
722                 frame_payload_len,
723                 &d[frame_header_len..]
724             ),
725             Err(crate::h3::Error::SettingsError)
726         );
727     }
728 
729     #[test]
settings_too_big()730     fn settings_too_big() {
731         // We need to test a SETTINGS frame that exceeds
732         // MAX_SETTINGS_PAYLOAD_SIZE, so just craft a special buffer that look
733         // likes the frame. The payload content doesn't matter since quiche
734         // should abort before then.
735         let frame_payload_len = MAX_SETTINGS_PAYLOAD_SIZE + 1;
736         let frame_header_len = 2;
737         let d = [
738             SETTINGS_FRAME_TYPE_ID as u8,
739             frame_payload_len as u8,
740             0x1,
741             1,
742         ];
743 
744         assert_eq!(
745             Frame::from_bytes(
746                 SETTINGS_FRAME_TYPE_ID,
747                 frame_payload_len as u64,
748                 &d[frame_header_len..]
749             ),
750             Err(crate::h3::Error::ExcessiveLoad)
751         );
752     }
753 
754     #[test]
push_promise()755     fn push_promise() {
756         let mut d = [42; 128];
757 
758         let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
759         let frame_payload_len = 1 + header_block.len();
760         let frame_header_len = 2;
761 
762         let frame = Frame::PushPromise {
763             push_id: 0,
764             header_block,
765         };
766 
767         let wire_len = {
768             let mut b = octets::OctetsMut::with_slice(&mut d);
769             frame.to_bytes(&mut b).unwrap()
770         };
771 
772         assert_eq!(wire_len, frame_header_len + frame_payload_len);
773 
774         assert_eq!(
775             Frame::from_bytes(
776                 PUSH_PROMISE_FRAME_TYPE_ID,
777                 frame_payload_len as u64,
778                 &d[frame_header_len..]
779             )
780             .unwrap(),
781             frame
782         );
783     }
784 
785     #[test]
goaway()786     fn goaway() {
787         let mut d = [42; 128];
788 
789         let frame = Frame::GoAway { id: 32 };
790 
791         let frame_payload_len = 1;
792         let frame_header_len = 2;
793 
794         let wire_len = {
795             let mut b = octets::OctetsMut::with_slice(&mut d);
796             frame.to_bytes(&mut b).unwrap()
797         };
798 
799         assert_eq!(wire_len, frame_header_len + frame_payload_len);
800 
801         assert_eq!(
802             Frame::from_bytes(
803                 GOAWAY_FRAME_TYPE_ID,
804                 frame_payload_len as u64,
805                 &d[frame_header_len..]
806             )
807             .unwrap(),
808             frame
809         );
810     }
811 
812     #[test]
max_push_id()813     fn max_push_id() {
814         let mut d = [42; 128];
815 
816         let frame = Frame::MaxPushId { push_id: 128 };
817 
818         let frame_payload_len = 2;
819         let frame_header_len = 2;
820 
821         let wire_len = {
822             let mut b = octets::OctetsMut::with_slice(&mut d);
823             frame.to_bytes(&mut b).unwrap()
824         };
825 
826         assert_eq!(wire_len, frame_header_len + frame_payload_len);
827 
828         assert_eq!(
829             Frame::from_bytes(
830                 MAX_PUSH_FRAME_TYPE_ID,
831                 frame_payload_len as u64,
832                 &d[frame_header_len..]
833             )
834             .unwrap(),
835             frame
836         );
837     }
838 
839     #[test]
unknown_type()840     fn unknown_type() {
841         let d = [42; 12];
842 
843         assert_eq!(Frame::from_bytes(255, 12345, &d[..]), Ok(Frame::Unknown));
844     }
845 }
846