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 #[cfg(feature = "qlog")]
30 use qlog::events::h3::Http3Frame;
31 
32 pub const DATA_FRAME_TYPE_ID: u64 = 0x0;
33 pub const HEADERS_FRAME_TYPE_ID: u64 = 0x1;
34 pub const CANCEL_PUSH_FRAME_TYPE_ID: u64 = 0x3;
35 pub const SETTINGS_FRAME_TYPE_ID: u64 = 0x4;
36 pub const PUSH_PROMISE_FRAME_TYPE_ID: u64 = 0x5;
37 pub const GOAWAY_FRAME_TYPE_ID: u64 = 0x6;
38 pub const MAX_PUSH_FRAME_TYPE_ID: u64 = 0xD;
39 pub const PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID: u64 = 0xF0700;
40 pub const PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID: u64 = 0xF0701;
41 
42 pub const SETTINGS_QPACK_MAX_TABLE_CAPACITY: u64 = 0x1;
43 pub const SETTINGS_MAX_FIELD_SECTION_SIZE: u64 = 0x6;
44 pub const SETTINGS_QPACK_BLOCKED_STREAMS: u64 = 0x7;
45 pub const SETTINGS_ENABLE_CONNECT_PROTOCOL: u64 = 0x8;
46 pub const SETTINGS_H3_DATAGRAM: u64 = 0x276;
47 
48 // Permit between 16 maximally-encoded and 128 minimally-encoded SETTINGS.
49 const MAX_SETTINGS_PAYLOAD_SIZE: usize = 256;
50 
51 #[derive(Clone, PartialEq, Eq)]
52 pub enum Frame {
53     Data {
54         payload: Vec<u8>,
55     },
56 
57     Headers {
58         header_block: Vec<u8>,
59     },
60 
61     CancelPush {
62         push_id: u64,
63     },
64 
65     Settings {
66         max_field_section_size: Option<u64>,
67         qpack_max_table_capacity: Option<u64>,
68         qpack_blocked_streams: Option<u64>,
69         connect_protocol_enabled: Option<u64>,
70         h3_datagram: Option<u64>,
71         grease: Option<(u64, u64)>,
72         raw: Option<Vec<(u64, u64)>>,
73     },
74 
75     PushPromise {
76         push_id: u64,
77         header_block: Vec<u8>,
78     },
79 
80     GoAway {
81         id: u64,
82     },
83 
84     MaxPushId {
85         push_id: u64,
86     },
87 
88     PriorityUpdateRequest {
89         prioritized_element_id: u64,
90         priority_field_value: Vec<u8>,
91     },
92 
93     PriorityUpdatePush {
94         prioritized_element_id: u64,
95         priority_field_value: Vec<u8>,
96     },
97 
98     Unknown {
99         raw_type: u64,
100         payload_length: u64,
101     },
102 }
103 
104 impl Frame {
from_bytes( frame_type: u64, payload_length: u64, bytes: &[u8], ) -> Result<Frame>105     pub fn from_bytes(
106         frame_type: u64, payload_length: u64, bytes: &[u8],
107     ) -> Result<Frame> {
108         let mut b = octets::Octets::with_slice(bytes);
109 
110         // TODO: handling of 0-length frames
111         let frame = match frame_type {
112             DATA_FRAME_TYPE_ID => Frame::Data {
113                 payload: b.get_bytes(payload_length as usize)?.to_vec(),
114             },
115 
116             HEADERS_FRAME_TYPE_ID => Frame::Headers {
117                 header_block: b.get_bytes(payload_length as usize)?.to_vec(),
118             },
119 
120             CANCEL_PUSH_FRAME_TYPE_ID => Frame::CancelPush {
121                 push_id: b.get_varint()?,
122             },
123 
124             SETTINGS_FRAME_TYPE_ID =>
125                 parse_settings_frame(&mut b, payload_length as usize)?,
126 
127             PUSH_PROMISE_FRAME_TYPE_ID =>
128                 parse_push_promise(payload_length, &mut b)?,
129 
130             GOAWAY_FRAME_TYPE_ID => Frame::GoAway {
131                 id: b.get_varint()?,
132             },
133 
134             MAX_PUSH_FRAME_TYPE_ID => Frame::MaxPushId {
135                 push_id: b.get_varint()?,
136             },
137 
138             PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID |
139             PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID =>
140                 parse_priority_update(frame_type, payload_length, &mut b)?,
141 
142             _ => Frame::Unknown {
143                 raw_type: frame_type,
144                 payload_length,
145             },
146         };
147 
148         Ok(frame)
149     }
150 
to_bytes(&self, b: &mut octets::OctetsMut) -> Result<usize>151     pub fn to_bytes(&self, b: &mut octets::OctetsMut) -> Result<usize> {
152         let before = b.cap();
153 
154         match self {
155             Frame::Data { payload } => {
156                 b.put_varint(DATA_FRAME_TYPE_ID)?;
157                 b.put_varint(payload.len() as u64)?;
158 
159                 b.put_bytes(payload.as_ref())?;
160             },
161 
162             Frame::Headers { header_block } => {
163                 b.put_varint(HEADERS_FRAME_TYPE_ID)?;
164                 b.put_varint(header_block.len() as u64)?;
165 
166                 b.put_bytes(header_block.as_ref())?;
167             },
168 
169             Frame::CancelPush { push_id } => {
170                 b.put_varint(CANCEL_PUSH_FRAME_TYPE_ID)?;
171                 b.put_varint(octets::varint_len(*push_id) as u64)?;
172 
173                 b.put_varint(*push_id)?;
174             },
175 
176             Frame::Settings {
177                 max_field_section_size,
178                 qpack_max_table_capacity,
179                 qpack_blocked_streams,
180                 connect_protocol_enabled,
181                 h3_datagram,
182                 grease,
183                 ..
184             } => {
185                 let mut len = 0;
186 
187                 if let Some(val) = max_field_section_size {
188                     len += octets::varint_len(SETTINGS_MAX_FIELD_SECTION_SIZE);
189                     len += octets::varint_len(*val);
190                 }
191 
192                 if let Some(val) = qpack_max_table_capacity {
193                     len += octets::varint_len(SETTINGS_QPACK_MAX_TABLE_CAPACITY);
194                     len += octets::varint_len(*val);
195                 }
196 
197                 if let Some(val) = qpack_blocked_streams {
198                     len += octets::varint_len(SETTINGS_QPACK_BLOCKED_STREAMS);
199                     len += octets::varint_len(*val);
200                 }
201 
202                 if let Some(val) = connect_protocol_enabled {
203                     len += octets::varint_len(SETTINGS_ENABLE_CONNECT_PROTOCOL);
204                     len += octets::varint_len(*val);
205                 }
206 
207                 if let Some(val) = h3_datagram {
208                     len += octets::varint_len(SETTINGS_H3_DATAGRAM);
209                     len += octets::varint_len(*val);
210                 }
211 
212                 if let Some(val) = grease {
213                     len += octets::varint_len(val.0);
214                     len += octets::varint_len(val.1);
215                 }
216 
217                 b.put_varint(SETTINGS_FRAME_TYPE_ID)?;
218                 b.put_varint(len as u64)?;
219 
220                 if let Some(val) = max_field_section_size {
221                     b.put_varint(SETTINGS_MAX_FIELD_SECTION_SIZE)?;
222                     b.put_varint(*val)?;
223                 }
224 
225                 if let Some(val) = qpack_max_table_capacity {
226                     b.put_varint(SETTINGS_QPACK_MAX_TABLE_CAPACITY)?;
227                     b.put_varint(*val)?;
228                 }
229 
230                 if let Some(val) = qpack_blocked_streams {
231                     b.put_varint(SETTINGS_QPACK_BLOCKED_STREAMS)?;
232                     b.put_varint(*val)?;
233                 }
234 
235                 if let Some(val) = connect_protocol_enabled {
236                     b.put_varint(SETTINGS_ENABLE_CONNECT_PROTOCOL)?;
237                     b.put_varint(*val)?;
238                 }
239 
240                 if let Some(val) = h3_datagram {
241                     b.put_varint(SETTINGS_H3_DATAGRAM)?;
242                     b.put_varint(*val)?;
243                 }
244 
245                 if let Some(val) = grease {
246                     b.put_varint(val.0)?;
247                     b.put_varint(val.1)?;
248                 }
249             },
250 
251             Frame::PushPromise {
252                 push_id,
253                 header_block,
254             } => {
255                 let len = octets::varint_len(*push_id) + header_block.len();
256                 b.put_varint(PUSH_PROMISE_FRAME_TYPE_ID)?;
257                 b.put_varint(len as u64)?;
258 
259                 b.put_varint(*push_id)?;
260                 b.put_bytes(header_block.as_ref())?;
261             },
262 
263             Frame::GoAway { id } => {
264                 b.put_varint(GOAWAY_FRAME_TYPE_ID)?;
265                 b.put_varint(octets::varint_len(*id) as u64)?;
266 
267                 b.put_varint(*id)?;
268             },
269 
270             Frame::MaxPushId { push_id } => {
271                 b.put_varint(MAX_PUSH_FRAME_TYPE_ID)?;
272                 b.put_varint(octets::varint_len(*push_id) as u64)?;
273 
274                 b.put_varint(*push_id)?;
275             },
276 
277             Frame::PriorityUpdateRequest {
278                 prioritized_element_id,
279                 priority_field_value,
280             } => {
281                 let len = octets::varint_len(*prioritized_element_id) +
282                     priority_field_value.len();
283 
284                 b.put_varint(PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID)?;
285                 b.put_varint(len as u64)?;
286 
287                 b.put_varint(*prioritized_element_id)?;
288                 b.put_bytes(priority_field_value)?;
289             },
290 
291             Frame::PriorityUpdatePush {
292                 prioritized_element_id,
293                 priority_field_value,
294             } => {
295                 let len = octets::varint_len(*prioritized_element_id) +
296                     priority_field_value.len();
297 
298                 b.put_varint(PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID)?;
299                 b.put_varint(len as u64)?;
300 
301                 b.put_varint(*prioritized_element_id)?;
302                 b.put_bytes(priority_field_value)?;
303             },
304 
305             Frame::Unknown { .. } => unreachable!(),
306         }
307 
308         Ok(before - b.cap())
309     }
310 
311     #[cfg(feature = "qlog")]
to_qlog(&self) -> Http3Frame312     pub fn to_qlog(&self) -> Http3Frame {
313         use qlog::events::RawInfo;
314 
315         match self {
316             Frame::Data { .. } => Http3Frame::Data { raw: None },
317 
318             // Qlog expects the `headers` to be represented as an array of
319             // name:value pairs. At this stage, we only have the qpack block, so
320             // populate the field with an empty vec.
321             Frame::Headers { .. } => Http3Frame::Headers { headers: vec![] },
322 
323             Frame::CancelPush { push_id } =>
324                 Http3Frame::CancelPush { push_id: *push_id },
325 
326             Frame::Settings {
327                 max_field_section_size,
328                 qpack_max_table_capacity,
329                 qpack_blocked_streams,
330                 connect_protocol_enabled,
331                 h3_datagram,
332                 grease,
333                 ..
334             } => {
335                 let mut settings = vec![];
336 
337                 if let Some(v) = max_field_section_size {
338                     settings.push(qlog::events::h3::Setting {
339                         name: "MAX_FIELD_SECTION_SIZE".to_string(),
340                         value: *v,
341                     });
342                 }
343 
344                 if let Some(v) = qpack_max_table_capacity {
345                     settings.push(qlog::events::h3::Setting {
346                         name: "QPACK_MAX_TABLE_CAPACITY".to_string(),
347                         value: *v,
348                     });
349                 }
350 
351                 if let Some(v) = qpack_blocked_streams {
352                     settings.push(qlog::events::h3::Setting {
353                         name: "QPACK_BLOCKED_STREAMS".to_string(),
354                         value: *v,
355                     });
356                 }
357 
358                 if let Some(v) = connect_protocol_enabled {
359                     settings.push(qlog::events::h3::Setting {
360                         name: "SETTINGS_ENABLE_CONNECT_PROTOCOL".to_string(),
361                         value: *v,
362                     });
363                 }
364 
365                 if let Some(v) = h3_datagram {
366                     settings.push(qlog::events::h3::Setting {
367                         name: "H3_DATAGRAM".to_string(),
368                         value: *v,
369                     });
370                 }
371 
372                 if let Some((k, v)) = grease {
373                     settings.push(qlog::events::h3::Setting {
374                         name: k.to_string(),
375                         value: *v,
376                     });
377                 }
378 
379                 qlog::events::h3::Http3Frame::Settings { settings }
380             },
381 
382             // Qlog expects the `headers` to be represented as an array of
383             // name:value pairs. At this stage, we only have the qpack block, so
384             // populate the field with an empty vec.
385             Frame::PushPromise { push_id, .. } => Http3Frame::PushPromise {
386                 push_id: *push_id,
387                 headers: vec![],
388             },
389 
390             Frame::GoAway { id } => Http3Frame::Goaway { id: *id },
391 
392             Frame::MaxPushId { push_id } =>
393                 Http3Frame::MaxPushId { push_id: *push_id },
394 
395             Frame::PriorityUpdateRequest {
396                 prioritized_element_id,
397                 priority_field_value,
398             } => Http3Frame::PriorityUpdate {
399                 target_stream_type:
400                     qlog::events::h3::H3PriorityTargetStreamType::Request,
401                 prioritized_element_id: *prioritized_element_id,
402                 priority_field_value: String::from_utf8_lossy(
403                     priority_field_value,
404                 )
405                 .into_owned(),
406             },
407 
408             Frame::PriorityUpdatePush {
409                 prioritized_element_id,
410                 priority_field_value,
411             } => Http3Frame::PriorityUpdate {
412                 target_stream_type:
413                     qlog::events::h3::H3PriorityTargetStreamType::Request,
414                 prioritized_element_id: *prioritized_element_id,
415                 priority_field_value: String::from_utf8_lossy(
416                     priority_field_value,
417                 )
418                 .into_owned(),
419             },
420 
421             Frame::Unknown {
422                 raw_type,
423                 payload_length,
424             } => Http3Frame::Unknown {
425                 frame_type_value: *raw_type,
426                 raw: Some(RawInfo {
427                     data: None,
428                     payload_length: Some(*payload_length),
429                     length: None,
430                 }),
431             },
432         }
433     }
434 }
435 
436 impl std::fmt::Debug for Frame {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result437     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
438         match self {
439             Frame::Data { .. } => {
440                 write!(f, "DATA")?;
441             },
442 
443             Frame::Headers { .. } => {
444                 write!(f, "HEADERS")?;
445             },
446 
447             Frame::CancelPush { push_id } => {
448                 write!(f, "CANCEL_PUSH push_id={push_id}")?;
449             },
450 
451             Frame::Settings {
452                 max_field_section_size,
453                 qpack_max_table_capacity,
454                 qpack_blocked_streams,
455                 raw,
456                 ..
457             } => {
458                 write!(f, "SETTINGS max_field_section={max_field_section_size:?}, qpack_max_table={qpack_max_table_capacity:?}, qpack_blocked={qpack_blocked_streams:?} raw={raw:?}")?;
459             },
460 
461             Frame::PushPromise {
462                 push_id,
463                 header_block,
464             } => {
465                 write!(
466                     f,
467                     "PUSH_PROMISE push_id={} len={}",
468                     push_id,
469                     header_block.len()
470                 )?;
471             },
472 
473             Frame::GoAway { id } => {
474                 write!(f, "GOAWAY id={id}")?;
475             },
476 
477             Frame::MaxPushId { push_id } => {
478                 write!(f, "MAX_PUSH_ID push_id={push_id}")?;
479             },
480 
481             Frame::PriorityUpdateRequest {
482                 prioritized_element_id,
483                 priority_field_value,
484             } => {
485                 write!(
486                     f,
487                     "PRIORITY_UPDATE request_stream_id={}, priority_field_len={}",
488                     prioritized_element_id,
489                     priority_field_value.len()
490                 )?;
491             },
492 
493             Frame::PriorityUpdatePush {
494                 prioritized_element_id,
495                 priority_field_value,
496             } => {
497                 write!(
498                     f,
499                     "PRIORITY_UPDATE push_id={}, priority_field_len={}",
500                     prioritized_element_id,
501                     priority_field_value.len()
502                 )?;
503             },
504 
505             Frame::Unknown { raw_type, .. } => {
506                 write!(f, "UNKNOWN raw_type={raw_type}",)?;
507             },
508         }
509 
510         Ok(())
511     }
512 }
513 
parse_settings_frame( b: &mut octets::Octets, settings_length: usize, ) -> Result<Frame>514 fn parse_settings_frame(
515     b: &mut octets::Octets, settings_length: usize,
516 ) -> Result<Frame> {
517     let mut max_field_section_size = None;
518     let mut qpack_max_table_capacity = None;
519     let mut qpack_blocked_streams = None;
520     let mut connect_protocol_enabled = None;
521     let mut h3_datagram = None;
522     let mut raw = Vec::new();
523 
524     // Reject SETTINGS frames that are too long.
525     if settings_length > MAX_SETTINGS_PAYLOAD_SIZE {
526         return Err(super::Error::ExcessiveLoad);
527     }
528 
529     while b.off() < settings_length {
530         let identifier = b.get_varint()?;
531         let value = b.get_varint()?;
532 
533         // MAX_SETTINGS_PAYLOAD_SIZE protects us from storing too many raw
534         // settings.
535         raw.push((identifier, value));
536 
537         match identifier {
538             SETTINGS_QPACK_MAX_TABLE_CAPACITY => {
539                 qpack_max_table_capacity = Some(value);
540             },
541 
542             SETTINGS_MAX_FIELD_SECTION_SIZE => {
543                 max_field_section_size = Some(value);
544             },
545 
546             SETTINGS_QPACK_BLOCKED_STREAMS => {
547                 qpack_blocked_streams = Some(value);
548             },
549 
550             SETTINGS_ENABLE_CONNECT_PROTOCOL => {
551                 if value > 1 {
552                     return Err(super::Error::SettingsError);
553                 }
554 
555                 connect_protocol_enabled = Some(value);
556             },
557 
558             SETTINGS_H3_DATAGRAM => {
559                 if value > 1 {
560                     return Err(super::Error::SettingsError);
561                 }
562 
563                 h3_datagram = Some(value);
564             },
565 
566             // Reserved values overlap with HTTP/2 and MUST be rejected
567             0x0 | 0x2 | 0x3 | 0x4 | 0x5 =>
568                 return Err(super::Error::SettingsError),
569 
570             // Unknown Settings parameters must be ignored.
571             _ => (),
572         }
573     }
574 
575     Ok(Frame::Settings {
576         max_field_section_size,
577         qpack_max_table_capacity,
578         qpack_blocked_streams,
579         connect_protocol_enabled,
580         h3_datagram,
581         grease: None,
582         raw: Some(raw),
583     })
584 }
585 
parse_push_promise( payload_length: u64, b: &mut octets::Octets, ) -> Result<Frame>586 fn parse_push_promise(
587     payload_length: u64, b: &mut octets::Octets,
588 ) -> Result<Frame> {
589     let push_id = b.get_varint()?;
590     let header_block_length = payload_length - octets::varint_len(push_id) as u64;
591     let header_block = b.get_bytes(header_block_length as usize)?.to_vec();
592 
593     Ok(Frame::PushPromise {
594         push_id,
595         header_block,
596     })
597 }
598 
parse_priority_update( frame_type: u64, payload_length: u64, b: &mut octets::Octets, ) -> Result<Frame>599 fn parse_priority_update(
600     frame_type: u64, payload_length: u64, b: &mut octets::Octets,
601 ) -> Result<Frame> {
602     let prioritized_element_id = b.get_varint()?;
603     let priority_field_value_length =
604         payload_length - octets::varint_len(prioritized_element_id) as u64;
605     let priority_field_value =
606         b.get_bytes(priority_field_value_length as usize)?.to_vec();
607 
608     match frame_type {
609         PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID =>
610             Ok(Frame::PriorityUpdateRequest {
611                 prioritized_element_id,
612                 priority_field_value,
613             }),
614 
615         PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID => Ok(Frame::PriorityUpdatePush {
616             prioritized_element_id,
617             priority_field_value,
618         }),
619 
620         _ => unreachable!(),
621     }
622 }
623 
624 #[cfg(test)]
625 mod tests {
626     use super::*;
627 
628     #[test]
data()629     fn data() {
630         let mut d = [42; 128];
631 
632         let payload = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
633         let frame_payload_len = payload.len();
634         let frame_header_len = 2;
635 
636         let frame = Frame::Data { payload };
637 
638         let wire_len = {
639             let mut b = octets::OctetsMut::with_slice(&mut d);
640             frame.to_bytes(&mut b).unwrap()
641         };
642 
643         assert_eq!(wire_len, frame_header_len + frame_payload_len);
644 
645         assert_eq!(
646             Frame::from_bytes(
647                 DATA_FRAME_TYPE_ID,
648                 frame_payload_len as u64,
649                 &d[frame_header_len..]
650             )
651             .unwrap(),
652             frame
653         );
654     }
655 
656     #[test]
headers()657     fn headers() {
658         let mut d = [42; 128];
659 
660         let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
661         let frame_payload_len = header_block.len();
662         let frame_header_len = 2;
663 
664         let frame = Frame::Headers { header_block };
665 
666         let wire_len = {
667             let mut b = octets::OctetsMut::with_slice(&mut d);
668             frame.to_bytes(&mut b).unwrap()
669         };
670 
671         assert_eq!(wire_len, frame_header_len + frame_payload_len);
672 
673         assert_eq!(
674             Frame::from_bytes(
675                 HEADERS_FRAME_TYPE_ID,
676                 frame_payload_len as u64,
677                 &d[frame_header_len..]
678             )
679             .unwrap(),
680             frame
681         );
682     }
683 
684     #[test]
cancel_push()685     fn cancel_push() {
686         let mut d = [42; 128];
687 
688         let frame = Frame::CancelPush { push_id: 0 };
689 
690         let frame_payload_len = 1;
691         let frame_header_len = 2;
692 
693         let wire_len = {
694             let mut b = octets::OctetsMut::with_slice(&mut d);
695             frame.to_bytes(&mut b).unwrap()
696         };
697 
698         assert_eq!(wire_len, frame_header_len + frame_payload_len);
699 
700         assert_eq!(
701             Frame::from_bytes(
702                 CANCEL_PUSH_FRAME_TYPE_ID,
703                 frame_payload_len as u64,
704                 &d[frame_header_len..]
705             )
706             .unwrap(),
707             frame
708         );
709     }
710 
711     #[test]
settings_all_no_grease()712     fn settings_all_no_grease() {
713         let mut d = [42; 128];
714 
715         let raw_settings = vec![
716             (SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
717             (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
718             (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
719             (SETTINGS_ENABLE_CONNECT_PROTOCOL, 0),
720             (SETTINGS_H3_DATAGRAM, 0),
721         ];
722 
723         let frame = Frame::Settings {
724             max_field_section_size: Some(0),
725             qpack_max_table_capacity: Some(0),
726             qpack_blocked_streams: Some(0),
727             connect_protocol_enabled: Some(0),
728             h3_datagram: Some(0),
729             grease: None,
730             raw: Some(raw_settings),
731         };
732 
733         let frame_payload_len = 11;
734         let frame_header_len = 2;
735 
736         let wire_len = {
737             let mut b = octets::OctetsMut::with_slice(&mut d);
738             frame.to_bytes(&mut b).unwrap()
739         };
740 
741         assert_eq!(wire_len, frame_header_len + frame_payload_len);
742 
743         assert_eq!(
744             Frame::from_bytes(
745                 SETTINGS_FRAME_TYPE_ID,
746                 frame_payload_len as u64,
747                 &d[frame_header_len..]
748             )
749             .unwrap(),
750             frame
751         );
752     }
753 
754     #[test]
settings_all_grease()755     fn settings_all_grease() {
756         let mut d = [42; 128];
757 
758         let frame = Frame::Settings {
759             max_field_section_size: Some(0),
760             qpack_max_table_capacity: Some(0),
761             qpack_blocked_streams: Some(0),
762             connect_protocol_enabled: Some(0),
763             h3_datagram: Some(0),
764             grease: Some((33, 33)),
765             raw: Default::default(),
766         };
767 
768         let raw_settings = vec![
769             (SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
770             (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
771             (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
772             (SETTINGS_ENABLE_CONNECT_PROTOCOL, 0),
773             (SETTINGS_H3_DATAGRAM, 0),
774             (33, 33),
775         ];
776 
777         // Frame parsing will not populate GREASE property but will be in the
778         // raw info.
779         let frame_parsed = Frame::Settings {
780             max_field_section_size: Some(0),
781             qpack_max_table_capacity: Some(0),
782             qpack_blocked_streams: Some(0),
783             connect_protocol_enabled: Some(0),
784             h3_datagram: Some(0),
785             grease: None,
786             raw: Some(raw_settings),
787         };
788 
789         let frame_payload_len = 13;
790         let frame_header_len = 2;
791 
792         let wire_len = {
793             let mut b = octets::OctetsMut::with_slice(&mut d);
794             frame.to_bytes(&mut b).unwrap()
795         };
796 
797         assert_eq!(wire_len, frame_header_len + frame_payload_len);
798 
799         assert_eq!(
800             Frame::from_bytes(
801                 SETTINGS_FRAME_TYPE_ID,
802                 frame_payload_len as u64,
803                 &d[frame_header_len..]
804             )
805             .unwrap(),
806             frame_parsed
807         );
808     }
809 
810     #[test]
settings_h3_only()811     fn settings_h3_only() {
812         let mut d = [42; 128];
813 
814         let raw_settings = vec![(SETTINGS_MAX_FIELD_SECTION_SIZE, 1024)];
815 
816         let frame = Frame::Settings {
817             max_field_section_size: Some(1024),
818             qpack_max_table_capacity: None,
819             qpack_blocked_streams: None,
820             connect_protocol_enabled: None,
821             h3_datagram: None,
822             grease: None,
823             raw: Some(raw_settings),
824         };
825 
826         let frame_payload_len = 3;
827         let frame_header_len = 2;
828 
829         let wire_len = {
830             let mut b = octets::OctetsMut::with_slice(&mut d);
831             frame.to_bytes(&mut b).unwrap()
832         };
833 
834         assert_eq!(wire_len, frame_header_len + frame_payload_len);
835 
836         assert_eq!(
837             Frame::from_bytes(
838                 SETTINGS_FRAME_TYPE_ID,
839                 frame_payload_len as u64,
840                 &d[frame_header_len..]
841             )
842             .unwrap(),
843             frame
844         );
845     }
846 
847     #[test]
settings_h3_connect_protocol_enabled()848     fn settings_h3_connect_protocol_enabled() {
849         let mut d = [42; 128];
850 
851         let raw_settings = vec![(SETTINGS_ENABLE_CONNECT_PROTOCOL, 1)];
852 
853         let frame = Frame::Settings {
854             max_field_section_size: None,
855             qpack_max_table_capacity: None,
856             qpack_blocked_streams: None,
857             connect_protocol_enabled: Some(1),
858             h3_datagram: None,
859             grease: None,
860             raw: Some(raw_settings),
861         };
862 
863         let frame_payload_len = 2;
864         let frame_header_len = 2;
865 
866         let wire_len = {
867             let mut b = octets::OctetsMut::with_slice(&mut d);
868             frame.to_bytes(&mut b).unwrap()
869         };
870 
871         assert_eq!(wire_len, frame_header_len + frame_payload_len);
872 
873         assert_eq!(
874             Frame::from_bytes(
875                 SETTINGS_FRAME_TYPE_ID,
876                 frame_payload_len as u64,
877                 &d[frame_header_len..]
878             )
879             .unwrap(),
880             frame
881         );
882     }
883 
884     #[test]
settings_h3_connect_protocol_enabled_bad()885     fn settings_h3_connect_protocol_enabled_bad() {
886         let mut d = [42; 128];
887 
888         let raw_settings = vec![(SETTINGS_ENABLE_CONNECT_PROTOCOL, 9)];
889 
890         let frame = Frame::Settings {
891             max_field_section_size: None,
892             qpack_max_table_capacity: None,
893             qpack_blocked_streams: None,
894             connect_protocol_enabled: Some(9),
895             h3_datagram: None,
896             grease: None,
897             raw: Some(raw_settings),
898         };
899 
900         let frame_payload_len = 2;
901         let frame_header_len = 2;
902 
903         let wire_len = {
904             let mut b = octets::OctetsMut::with_slice(&mut d);
905             frame.to_bytes(&mut b).unwrap()
906         };
907 
908         assert_eq!(wire_len, frame_header_len + frame_payload_len);
909 
910         assert_eq!(
911             Frame::from_bytes(
912                 SETTINGS_FRAME_TYPE_ID,
913                 frame_payload_len as u64,
914                 &d[frame_header_len..]
915             ),
916             Err(crate::h3::Error::SettingsError)
917         );
918     }
919 
920     #[test]
settings_h3_dgram_only()921     fn settings_h3_dgram_only() {
922         let mut d = [42; 128];
923 
924         let raw_settings = vec![(SETTINGS_H3_DATAGRAM, 1)];
925 
926         let frame = Frame::Settings {
927             max_field_section_size: None,
928             qpack_max_table_capacity: None,
929             qpack_blocked_streams: None,
930             connect_protocol_enabled: None,
931             h3_datagram: Some(1),
932             grease: None,
933             raw: Some(raw_settings),
934         };
935 
936         let frame_payload_len = 3;
937         let frame_header_len = 2;
938 
939         let wire_len = {
940             let mut b = octets::OctetsMut::with_slice(&mut d);
941             frame.to_bytes(&mut b).unwrap()
942         };
943 
944         assert_eq!(wire_len, frame_header_len + frame_payload_len);
945 
946         assert_eq!(
947             Frame::from_bytes(
948                 SETTINGS_FRAME_TYPE_ID,
949                 frame_payload_len as u64,
950                 &d[frame_header_len..]
951             )
952             .unwrap(),
953             frame
954         );
955     }
956 
957     #[test]
settings_h3_dgram_bad()958     fn settings_h3_dgram_bad() {
959         let mut d = [42; 128];
960 
961         let frame = Frame::Settings {
962             max_field_section_size: None,
963             qpack_max_table_capacity: None,
964             qpack_blocked_streams: None,
965             connect_protocol_enabled: None,
966             h3_datagram: Some(5),
967             grease: None,
968             raw: Default::default(),
969         };
970 
971         let frame_payload_len = 3;
972         let frame_header_len = 2;
973 
974         let wire_len = {
975             let mut b = octets::OctetsMut::with_slice(&mut d);
976             frame.to_bytes(&mut b).unwrap()
977         };
978 
979         assert_eq!(wire_len, frame_header_len + frame_payload_len);
980 
981         assert_eq!(
982             Frame::from_bytes(
983                 SETTINGS_FRAME_TYPE_ID,
984                 frame_payload_len as u64,
985                 &d[frame_header_len..]
986             ),
987             Err(crate::h3::Error::SettingsError)
988         );
989     }
990 
991     #[test]
settings_qpack_only()992     fn settings_qpack_only() {
993         let mut d = [42; 128];
994 
995         let raw_settings = vec![
996             (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
997             (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
998         ];
999 
1000         let frame = Frame::Settings {
1001             max_field_section_size: None,
1002             qpack_max_table_capacity: Some(0),
1003             qpack_blocked_streams: Some(0),
1004             connect_protocol_enabled: None,
1005             h3_datagram: None,
1006             grease: None,
1007             raw: Some(raw_settings),
1008         };
1009 
1010         let frame_payload_len = 4;
1011         let frame_header_len = 2;
1012 
1013         let wire_len = {
1014             let mut b = octets::OctetsMut::with_slice(&mut d);
1015             frame.to_bytes(&mut b).unwrap()
1016         };
1017 
1018         assert_eq!(wire_len, frame_header_len + frame_payload_len);
1019 
1020         assert_eq!(
1021             Frame::from_bytes(
1022                 SETTINGS_FRAME_TYPE_ID,
1023                 frame_payload_len as u64,
1024                 &d[frame_header_len..]
1025             )
1026             .unwrap(),
1027             frame
1028         );
1029     }
1030 
1031     #[test]
settings_h2_prohibited()1032     fn settings_h2_prohibited() {
1033         // We need to test the prohibited values (0x0 | 0x2 | 0x3 | 0x4 | 0x5)
1034         // but the quiche API doesn't support that, so use a manually created
1035         // frame data buffer where d[frame_header_len] is the SETTING type field.
1036         let frame_payload_len = 2u64;
1037         let frame_header_len = 2;
1038         let mut d = [
1039             SETTINGS_FRAME_TYPE_ID as u8,
1040             frame_payload_len as u8,
1041             0x0,
1042             1,
1043         ];
1044 
1045         assert_eq!(
1046             Frame::from_bytes(
1047                 SETTINGS_FRAME_TYPE_ID,
1048                 frame_payload_len,
1049                 &d[frame_header_len..]
1050             ),
1051             Err(crate::h3::Error::SettingsError)
1052         );
1053 
1054         d[frame_header_len] = 0x2;
1055 
1056         assert_eq!(
1057             Frame::from_bytes(
1058                 SETTINGS_FRAME_TYPE_ID,
1059                 frame_payload_len,
1060                 &d[frame_header_len..]
1061             ),
1062             Err(crate::h3::Error::SettingsError)
1063         );
1064 
1065         d[frame_header_len] = 0x3;
1066 
1067         assert_eq!(
1068             Frame::from_bytes(
1069                 SETTINGS_FRAME_TYPE_ID,
1070                 frame_payload_len,
1071                 &d[frame_header_len..]
1072             ),
1073             Err(crate::h3::Error::SettingsError)
1074         );
1075 
1076         d[frame_header_len] = 0x4;
1077 
1078         assert_eq!(
1079             Frame::from_bytes(
1080                 SETTINGS_FRAME_TYPE_ID,
1081                 frame_payload_len,
1082                 &d[frame_header_len..]
1083             ),
1084             Err(crate::h3::Error::SettingsError)
1085         );
1086 
1087         d[frame_header_len] = 0x5;
1088 
1089         assert_eq!(
1090             Frame::from_bytes(
1091                 SETTINGS_FRAME_TYPE_ID,
1092                 frame_payload_len,
1093                 &d[frame_header_len..]
1094             ),
1095             Err(crate::h3::Error::SettingsError)
1096         );
1097     }
1098 
1099     #[test]
settings_too_big()1100     fn settings_too_big() {
1101         // We need to test a SETTINGS frame that exceeds
1102         // MAX_SETTINGS_PAYLOAD_SIZE, so just craft a special buffer that look
1103         // likes the frame. The payload content doesn't matter since quiche
1104         // should abort before then.
1105         let frame_payload_len = MAX_SETTINGS_PAYLOAD_SIZE + 1;
1106         let frame_header_len = 2;
1107         let d = [
1108             SETTINGS_FRAME_TYPE_ID as u8,
1109             frame_payload_len as u8,
1110             0x1,
1111             1,
1112         ];
1113 
1114         assert_eq!(
1115             Frame::from_bytes(
1116                 SETTINGS_FRAME_TYPE_ID,
1117                 frame_payload_len as u64,
1118                 &d[frame_header_len..]
1119             ),
1120             Err(crate::h3::Error::ExcessiveLoad)
1121         );
1122     }
1123 
1124     #[test]
push_promise()1125     fn push_promise() {
1126         let mut d = [42; 128];
1127 
1128         let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
1129         let frame_payload_len = 1 + header_block.len();
1130         let frame_header_len = 2;
1131 
1132         let frame = Frame::PushPromise {
1133             push_id: 0,
1134             header_block,
1135         };
1136 
1137         let wire_len = {
1138             let mut b = octets::OctetsMut::with_slice(&mut d);
1139             frame.to_bytes(&mut b).unwrap()
1140         };
1141 
1142         assert_eq!(wire_len, frame_header_len + frame_payload_len);
1143 
1144         assert_eq!(
1145             Frame::from_bytes(
1146                 PUSH_PROMISE_FRAME_TYPE_ID,
1147                 frame_payload_len as u64,
1148                 &d[frame_header_len..]
1149             )
1150             .unwrap(),
1151             frame
1152         );
1153     }
1154 
1155     #[test]
goaway()1156     fn goaway() {
1157         let mut d = [42; 128];
1158 
1159         let frame = Frame::GoAway { id: 32 };
1160 
1161         let frame_payload_len = 1;
1162         let frame_header_len = 2;
1163 
1164         let wire_len = {
1165             let mut b = octets::OctetsMut::with_slice(&mut d);
1166             frame.to_bytes(&mut b).unwrap()
1167         };
1168 
1169         assert_eq!(wire_len, frame_header_len + frame_payload_len);
1170 
1171         assert_eq!(
1172             Frame::from_bytes(
1173                 GOAWAY_FRAME_TYPE_ID,
1174                 frame_payload_len as u64,
1175                 &d[frame_header_len..]
1176             )
1177             .unwrap(),
1178             frame
1179         );
1180     }
1181 
1182     #[test]
max_push_id()1183     fn max_push_id() {
1184         let mut d = [42; 128];
1185 
1186         let frame = Frame::MaxPushId { push_id: 128 };
1187 
1188         let frame_payload_len = 2;
1189         let frame_header_len = 2;
1190 
1191         let wire_len = {
1192             let mut b = octets::OctetsMut::with_slice(&mut d);
1193             frame.to_bytes(&mut b).unwrap()
1194         };
1195 
1196         assert_eq!(wire_len, frame_header_len + frame_payload_len);
1197 
1198         assert_eq!(
1199             Frame::from_bytes(
1200                 MAX_PUSH_FRAME_TYPE_ID,
1201                 frame_payload_len as u64,
1202                 &d[frame_header_len..]
1203             )
1204             .unwrap(),
1205             frame
1206         );
1207     }
1208 
1209     #[test]
priority_update_request()1210     fn priority_update_request() {
1211         let mut d = [42; 128];
1212 
1213         let prioritized_element_id = 4;
1214         let priority_field_value = b"abcdefghijklm".to_vec();
1215         let frame_payload_len = 1 + priority_field_value.len();
1216         let frame_header_len = 5;
1217 
1218         let frame = Frame::PriorityUpdateRequest {
1219             prioritized_element_id,
1220             priority_field_value,
1221         };
1222 
1223         let wire_len = {
1224             let mut b = octets::OctetsMut::with_slice(&mut d);
1225             frame.to_bytes(&mut b).unwrap()
1226         };
1227 
1228         assert_eq!(wire_len, frame_header_len + frame_payload_len);
1229 
1230         assert_eq!(
1231             Frame::from_bytes(
1232                 PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID,
1233                 frame_payload_len as u64,
1234                 &d[frame_header_len..]
1235             )
1236             .unwrap(),
1237             frame
1238         );
1239     }
1240 
1241     #[test]
priority_update_push()1242     fn priority_update_push() {
1243         let mut d = [42; 128];
1244 
1245         let prioritized_element_id = 6;
1246         let priority_field_value = b"abcdefghijklm".to_vec();
1247         let frame_payload_len = 1 + priority_field_value.len();
1248         let frame_header_len = 5;
1249 
1250         let frame = Frame::PriorityUpdatePush {
1251             prioritized_element_id,
1252             priority_field_value,
1253         };
1254 
1255         let wire_len = {
1256             let mut b = octets::OctetsMut::with_slice(&mut d);
1257             frame.to_bytes(&mut b).unwrap()
1258         };
1259 
1260         assert_eq!(wire_len, frame_header_len + frame_payload_len);
1261 
1262         assert_eq!(
1263             Frame::from_bytes(
1264                 PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID,
1265                 frame_payload_len as u64,
1266                 &d[frame_header_len..]
1267             )
1268             .unwrap(),
1269             frame
1270         );
1271     }
1272 
1273     #[test]
unknown_type()1274     fn unknown_type() {
1275         let d = [42; 12];
1276 
1277         assert_eq!(
1278             Frame::from_bytes(255, 12345, &d[..]),
1279             Ok(Frame::Unknown {
1280                 raw_type: 255,
1281                 payload_length: 12345
1282             })
1283         );
1284     }
1285 }
1286