Skip to main content

quiche/h3/
frame.rs

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