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::h3::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 { headers: vec![] },
348
349            Frame::CancelPush { push_id } =>
350                Http3Frame::CancelPush { push_id: *push_id },
351
352            Frame::Settings {
353                max_field_section_size,
354                qpack_max_table_capacity,
355                qpack_blocked_streams,
356                connect_protocol_enabled,
357                h3_datagram,
358                grease,
359                additional_settings,
360                ..
361            } => {
362                let mut settings = vec![];
363
364                if let Some(v) = max_field_section_size {
365                    settings.push(qlog::events::h3::Setting {
366                        name: "MAX_FIELD_SECTION_SIZE".to_string(),
367                        value: *v,
368                    });
369                }
370
371                if let Some(v) = qpack_max_table_capacity {
372                    settings.push(qlog::events::h3::Setting {
373                        name: "QPACK_MAX_TABLE_CAPACITY".to_string(),
374                        value: *v,
375                    });
376                }
377
378                if let Some(v) = qpack_blocked_streams {
379                    settings.push(qlog::events::h3::Setting {
380                        name: "QPACK_BLOCKED_STREAMS".to_string(),
381                        value: *v,
382                    });
383                }
384
385                if let Some(v) = connect_protocol_enabled {
386                    settings.push(qlog::events::h3::Setting {
387                        name: "SETTINGS_ENABLE_CONNECT_PROTOCOL".to_string(),
388                        value: *v,
389                    });
390                }
391
392                if let Some(v) = h3_datagram {
393                    settings.push(qlog::events::h3::Setting {
394                        name: "H3_DATAGRAM".to_string(),
395                        value: *v,
396                    });
397                }
398
399                if let Some((k, v)) = grease {
400                    settings.push(qlog::events::h3::Setting {
401                        name: k.to_string(),
402                        value: *v,
403                    });
404                }
405
406                if let Some(additional_settings) = additional_settings {
407                    for (k, v) in additional_settings {
408                        settings.push(qlog::events::h3::Setting {
409                            name: k.to_string(),
410                            value: *v,
411                        });
412                    }
413                }
414
415                qlog::events::h3::Http3Frame::Settings { settings }
416            },
417
418            // Qlog expects the `headers` to be represented as an array of
419            // name:value pairs. At this stage, we only have the qpack block, so
420            // populate the field with an empty vec.
421            Frame::PushPromise { push_id, .. } => Http3Frame::PushPromise {
422                push_id: *push_id,
423                headers: vec![],
424            },
425
426            Frame::GoAway { id } => Http3Frame::Goaway { id: *id },
427
428            Frame::MaxPushId { push_id } =>
429                Http3Frame::MaxPushId { push_id: *push_id },
430
431            Frame::PriorityUpdateRequest {
432                prioritized_element_id,
433                priority_field_value,
434            } => Http3Frame::PriorityUpdate {
435                target_stream_type:
436                    qlog::events::h3::H3PriorityTargetStreamType::Request,
437                prioritized_element_id: *prioritized_element_id,
438                priority_field_value: String::from_utf8_lossy(
439                    priority_field_value,
440                )
441                .into_owned(),
442            },
443
444            Frame::PriorityUpdatePush {
445                prioritized_element_id,
446                priority_field_value,
447            } => Http3Frame::PriorityUpdate {
448                target_stream_type:
449                    qlog::events::h3::H3PriorityTargetStreamType::Request,
450                prioritized_element_id: *prioritized_element_id,
451                priority_field_value: String::from_utf8_lossy(
452                    priority_field_value,
453                )
454                .into_owned(),
455            },
456
457            Frame::Unknown { raw_type, payload } => Http3Frame::Unknown {
458                frame_type_value: *raw_type,
459                raw: Some(RawInfo {
460                    data: None,
461                    payload_length: Some(payload.len() as u64),
462                    length: None,
463                }),
464            },
465        }
466    }
467}
468
469impl std::fmt::Debug for Frame {
470    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
471        match self {
472            Frame::Data { .. } => {
473                write!(f, "DATA")?;
474            },
475
476            Frame::Headers { .. } => {
477                write!(f, "HEADERS")?;
478            },
479
480            Frame::CancelPush { push_id } => {
481                write!(f, "CANCEL_PUSH push_id={push_id}")?;
482            },
483
484            Frame::Settings {
485                max_field_section_size,
486                qpack_max_table_capacity,
487                qpack_blocked_streams,
488                additional_settings,
489                raw,
490                ..
491            } => {
492                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:?}")?;
493            },
494
495            Frame::PushPromise {
496                push_id,
497                header_block,
498            } => {
499                write!(
500                    f,
501                    "PUSH_PROMISE push_id={} len={}",
502                    push_id,
503                    header_block.len()
504                )?;
505            },
506
507            Frame::GoAway { id } => {
508                write!(f, "GOAWAY id={id}")?;
509            },
510
511            Frame::MaxPushId { push_id } => {
512                write!(f, "MAX_PUSH_ID push_id={push_id}")?;
513            },
514
515            Frame::PriorityUpdateRequest {
516                prioritized_element_id,
517                priority_field_value,
518            } => {
519                write!(
520                    f,
521                    "PRIORITY_UPDATE request_stream_id={}, priority_field_len={}",
522                    prioritized_element_id,
523                    priority_field_value.len()
524                )?;
525            },
526
527            Frame::PriorityUpdatePush {
528                prioritized_element_id,
529                priority_field_value,
530            } => {
531                write!(
532                    f,
533                    "PRIORITY_UPDATE push_id={}, priority_field_len={}",
534                    prioritized_element_id,
535                    priority_field_value.len()
536                )?;
537            },
538
539            Frame::Unknown { raw_type, .. } => {
540                write!(f, "UNKNOWN raw_type={raw_type}",)?;
541            },
542        }
543
544        Ok(())
545    }
546}
547
548fn parse_settings_frame(
549    b: &mut octets::Octets, settings_length: usize,
550) -> Result<Frame> {
551    let mut max_field_section_size = None;
552    let mut qpack_max_table_capacity = None;
553    let mut qpack_blocked_streams = None;
554    let mut connect_protocol_enabled = None;
555    let mut h3_datagram = None;
556    let mut raw = Vec::new();
557    let mut additional_settings: Option<Vec<(u64, u64)>> = None;
558
559    // Reject SETTINGS frames that are too long.
560    if settings_length > MAX_SETTINGS_PAYLOAD_SIZE {
561        return Err(super::Error::ExcessiveLoad);
562    }
563
564    while b.off() < settings_length {
565        let identifier = b.get_varint()?;
566        let value = b.get_varint()?;
567
568        // MAX_SETTINGS_PAYLOAD_SIZE protects us from storing too many raw
569        // settings.
570        raw.push((identifier, value));
571
572        match identifier {
573            SETTINGS_QPACK_MAX_TABLE_CAPACITY => {
574                qpack_max_table_capacity = Some(value);
575            },
576
577            SETTINGS_MAX_FIELD_SECTION_SIZE => {
578                max_field_section_size = Some(value);
579            },
580
581            SETTINGS_QPACK_BLOCKED_STREAMS => {
582                qpack_blocked_streams = Some(value);
583            },
584
585            SETTINGS_ENABLE_CONNECT_PROTOCOL => {
586                if value > 1 {
587                    return Err(super::Error::SettingsError);
588                }
589
590                connect_protocol_enabled = Some(value);
591            },
592
593            SETTINGS_H3_DATAGRAM_00 | SETTINGS_H3_DATAGRAM => {
594                if value > 1 {
595                    return Err(super::Error::SettingsError);
596                }
597
598                h3_datagram = Some(value);
599            },
600
601            // Reserved values overlap with HTTP/2 and MUST be rejected
602            0x0 | 0x2 | 0x3 | 0x4 | 0x5 =>
603                return Err(super::Error::SettingsError),
604
605            // Unknown Settings parameters go into additional_settings.
606            _ => {
607                let s: &mut Vec<(u64, u64)> =
608                    additional_settings.get_or_insert(vec![]);
609                s.push((identifier, value));
610            },
611        }
612    }
613
614    Ok(Frame::Settings {
615        max_field_section_size,
616        qpack_max_table_capacity,
617        qpack_blocked_streams,
618        connect_protocol_enabled,
619        h3_datagram,
620        grease: None,
621        raw: Some(raw),
622        additional_settings,
623    })
624}
625
626fn parse_push_promise(
627    payload_length: u64, b: &mut octets::Octets,
628) -> Result<Frame> {
629    let push_id = b.get_varint()?;
630    let header_block_length = payload_length - octets::varint_len(push_id) as u64;
631    let header_block = b.get_bytes(header_block_length as usize)?.to_vec();
632
633    Ok(Frame::PushPromise {
634        push_id,
635        header_block,
636    })
637}
638
639fn parse_priority_update(
640    frame_type: u64, payload_length: u64, b: &mut octets::Octets,
641) -> Result<Frame> {
642    let prioritized_element_id = b.get_varint()?;
643    let priority_field_value_length =
644        payload_length - octets::varint_len(prioritized_element_id) as u64;
645    let priority_field_value =
646        b.get_bytes(priority_field_value_length as usize)?.to_vec();
647
648    match frame_type {
649        PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID =>
650            Ok(Frame::PriorityUpdateRequest {
651                prioritized_element_id,
652                priority_field_value,
653            }),
654
655        PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID => Ok(Frame::PriorityUpdatePush {
656            prioritized_element_id,
657            priority_field_value,
658        }),
659
660        _ => unreachable!(),
661    }
662}
663
664#[cfg(test)]
665mod tests {
666    use super::*;
667
668    #[test]
669    fn data() {
670        let mut d = [42; 128];
671
672        let payload = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
673        let frame_payload_len = payload.len();
674        let frame_header_len = 2;
675
676        let frame = Frame::Data { payload };
677
678        let wire_len = {
679            let mut b = octets::OctetsMut::with_slice(&mut d);
680            frame.to_bytes(&mut b).unwrap()
681        };
682
683        assert_eq!(wire_len, frame_header_len + frame_payload_len);
684
685        assert_eq!(
686            Frame::from_bytes(
687                DATA_FRAME_TYPE_ID,
688                frame_payload_len as u64,
689                &d[frame_header_len..]
690            )
691            .unwrap(),
692            frame
693        );
694    }
695
696    #[test]
697    fn headers() {
698        let mut d = [42; 128];
699
700        let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
701        let frame_payload_len = header_block.len();
702        let frame_header_len = 2;
703
704        let frame = Frame::Headers { header_block };
705
706        let wire_len = {
707            let mut b = octets::OctetsMut::with_slice(&mut d);
708            frame.to_bytes(&mut b).unwrap()
709        };
710
711        assert_eq!(wire_len, frame_header_len + frame_payload_len);
712
713        assert_eq!(
714            Frame::from_bytes(
715                HEADERS_FRAME_TYPE_ID,
716                frame_payload_len as u64,
717                &d[frame_header_len..]
718            )
719            .unwrap(),
720            frame
721        );
722    }
723
724    #[test]
725    fn cancel_push() {
726        let mut d = [42; 128];
727
728        let frame = Frame::CancelPush { push_id: 0 };
729
730        let frame_payload_len = 1;
731        let frame_header_len = 2;
732
733        let wire_len = {
734            let mut b = octets::OctetsMut::with_slice(&mut d);
735            frame.to_bytes(&mut b).unwrap()
736        };
737
738        assert_eq!(wire_len, frame_header_len + frame_payload_len);
739
740        assert_eq!(
741            Frame::from_bytes(
742                CANCEL_PUSH_FRAME_TYPE_ID,
743                frame_payload_len as u64,
744                &d[frame_header_len..]
745            )
746            .unwrap(),
747            frame
748        );
749    }
750
751    #[test]
752    fn settings_all_no_grease() {
753        let mut d = [42; 128];
754
755        let raw_settings = vec![
756            (SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
757            (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
758            (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
759            (SETTINGS_ENABLE_CONNECT_PROTOCOL, 0),
760            (SETTINGS_H3_DATAGRAM_00, 0),
761            (SETTINGS_H3_DATAGRAM, 0),
762        ];
763
764        let frame = Frame::Settings {
765            max_field_section_size: Some(0),
766            qpack_max_table_capacity: Some(0),
767            qpack_blocked_streams: Some(0),
768            connect_protocol_enabled: Some(0),
769            h3_datagram: Some(0),
770            grease: None,
771            raw: Some(raw_settings),
772            additional_settings: None,
773        };
774
775        let frame_payload_len = 13;
776        let frame_header_len = 2;
777
778        let wire_len = {
779            let mut b = octets::OctetsMut::with_slice(&mut d);
780            frame.to_bytes(&mut b).unwrap()
781        };
782
783        assert_eq!(wire_len, frame_header_len + frame_payload_len);
784
785        assert_eq!(
786            Frame::from_bytes(
787                SETTINGS_FRAME_TYPE_ID,
788                frame_payload_len as u64,
789                &d[frame_header_len..]
790            )
791            .unwrap(),
792            frame
793        );
794    }
795
796    #[test]
797    fn settings_all_grease() {
798        let mut d = [42; 128];
799
800        let frame = Frame::Settings {
801            max_field_section_size: Some(0),
802            qpack_max_table_capacity: Some(0),
803            qpack_blocked_streams: Some(0),
804            connect_protocol_enabled: Some(0),
805            h3_datagram: Some(0),
806            grease: Some((33, 33)),
807            raw: Default::default(),
808            additional_settings: None,
809        };
810
811        let raw_settings = vec![
812            (SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
813            (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
814            (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
815            (SETTINGS_ENABLE_CONNECT_PROTOCOL, 0),
816            (SETTINGS_H3_DATAGRAM_00, 0),
817            (SETTINGS_H3_DATAGRAM, 0),
818            (33, 33),
819        ];
820
821        // Frame parsing will not populate GREASE property but will be in the
822        // raw info.
823        let frame_parsed = Frame::Settings {
824            max_field_section_size: Some(0),
825            qpack_max_table_capacity: Some(0),
826            qpack_blocked_streams: Some(0),
827            connect_protocol_enabled: Some(0),
828            h3_datagram: Some(0),
829            grease: None,
830            raw: Some(raw_settings),
831            additional_settings: Some(vec![(33, 33)]),
832        };
833
834        let frame_payload_len = 15;
835        let frame_header_len = 2;
836
837        let wire_len = {
838            let mut b = octets::OctetsMut::with_slice(&mut d);
839            frame.to_bytes(&mut b).unwrap()
840        };
841
842        assert_eq!(wire_len, frame_header_len + frame_payload_len);
843
844        assert_eq!(
845            Frame::from_bytes(
846                SETTINGS_FRAME_TYPE_ID,
847                frame_payload_len as u64,
848                &d[frame_header_len..]
849            )
850            .unwrap(),
851            frame_parsed
852        );
853    }
854
855    #[test]
856    fn settings_h3_only() {
857        let mut d = [42; 128];
858
859        let raw_settings = vec![(SETTINGS_MAX_FIELD_SECTION_SIZE, 1024)];
860
861        let frame = Frame::Settings {
862            max_field_section_size: Some(1024),
863            qpack_max_table_capacity: None,
864            qpack_blocked_streams: None,
865            connect_protocol_enabled: None,
866            h3_datagram: None,
867            grease: None,
868            raw: Some(raw_settings),
869            additional_settings: None,
870        };
871
872        let frame_payload_len = 3;
873        let frame_header_len = 2;
874
875        let wire_len = {
876            let mut b = octets::OctetsMut::with_slice(&mut d);
877            frame.to_bytes(&mut b).unwrap()
878        };
879
880        assert_eq!(wire_len, frame_header_len + frame_payload_len);
881
882        assert_eq!(
883            Frame::from_bytes(
884                SETTINGS_FRAME_TYPE_ID,
885                frame_payload_len as u64,
886                &d[frame_header_len..]
887            )
888            .unwrap(),
889            frame
890        );
891    }
892
893    #[test]
894    fn settings_h3_connect_protocol_enabled() {
895        let mut d = [42; 128];
896
897        let raw_settings = vec![(SETTINGS_ENABLE_CONNECT_PROTOCOL, 1)];
898
899        let frame = Frame::Settings {
900            max_field_section_size: None,
901            qpack_max_table_capacity: None,
902            qpack_blocked_streams: None,
903            connect_protocol_enabled: Some(1),
904            h3_datagram: None,
905            grease: None,
906            raw: Some(raw_settings),
907            additional_settings: None,
908        };
909
910        let frame_payload_len = 2;
911        let frame_header_len = 2;
912
913        let wire_len = {
914            let mut b = octets::OctetsMut::with_slice(&mut d);
915            frame.to_bytes(&mut b).unwrap()
916        };
917
918        assert_eq!(wire_len, frame_header_len + frame_payload_len);
919
920        assert_eq!(
921            Frame::from_bytes(
922                SETTINGS_FRAME_TYPE_ID,
923                frame_payload_len as u64,
924                &d[frame_header_len..]
925            )
926            .unwrap(),
927            frame
928        );
929    }
930
931    #[test]
932    fn settings_h3_connect_protocol_enabled_bad() {
933        let mut d = [42; 128];
934
935        let raw_settings = vec![(SETTINGS_ENABLE_CONNECT_PROTOCOL, 9)];
936
937        let frame = Frame::Settings {
938            max_field_section_size: None,
939            qpack_max_table_capacity: None,
940            qpack_blocked_streams: None,
941            connect_protocol_enabled: Some(9),
942            h3_datagram: None,
943            grease: None,
944            raw: Some(raw_settings),
945            additional_settings: None,
946        };
947
948        let frame_payload_len = 2;
949        let frame_header_len = 2;
950
951        let wire_len = {
952            let mut b = octets::OctetsMut::with_slice(&mut d);
953            frame.to_bytes(&mut b).unwrap()
954        };
955
956        assert_eq!(wire_len, frame_header_len + frame_payload_len);
957
958        assert_eq!(
959            Frame::from_bytes(
960                SETTINGS_FRAME_TYPE_ID,
961                frame_payload_len as u64,
962                &d[frame_header_len..]
963            ),
964            Err(crate::h3::Error::SettingsError)
965        );
966    }
967
968    #[test]
969    fn settings_h3_dgram_only() {
970        let mut d = [42; 128];
971
972        let raw_settings =
973            vec![(SETTINGS_H3_DATAGRAM_00, 1), (SETTINGS_H3_DATAGRAM, 1)];
974
975        let frame = Frame::Settings {
976            max_field_section_size: None,
977            qpack_max_table_capacity: None,
978            qpack_blocked_streams: None,
979            connect_protocol_enabled: None,
980            h3_datagram: Some(1),
981            grease: None,
982            raw: Some(raw_settings),
983            additional_settings: None,
984        };
985
986        let frame_payload_len = 5;
987        let frame_header_len = 2;
988
989        let wire_len = {
990            let mut b = octets::OctetsMut::with_slice(&mut d);
991            frame.to_bytes(&mut b).unwrap()
992        };
993
994        assert_eq!(wire_len, frame_header_len + frame_payload_len);
995
996        assert_eq!(
997            Frame::from_bytes(
998                SETTINGS_FRAME_TYPE_ID,
999                frame_payload_len as u64,
1000                &d[frame_header_len..]
1001            )
1002            .unwrap(),
1003            frame
1004        );
1005    }
1006
1007    #[test]
1008    fn settings_h3_dgram_bad() {
1009        let mut d = [42; 128];
1010
1011        let frame = Frame::Settings {
1012            max_field_section_size: None,
1013            qpack_max_table_capacity: None,
1014            qpack_blocked_streams: None,
1015            connect_protocol_enabled: None,
1016            h3_datagram: Some(5),
1017            grease: None,
1018            raw: Default::default(),
1019            additional_settings: None,
1020        };
1021
1022        let frame_payload_len = 5;
1023        let frame_header_len = 2;
1024
1025        let wire_len = {
1026            let mut b = octets::OctetsMut::with_slice(&mut d);
1027            frame.to_bytes(&mut b).unwrap()
1028        };
1029
1030        assert_eq!(wire_len, frame_header_len + frame_payload_len);
1031
1032        assert_eq!(
1033            Frame::from_bytes(
1034                SETTINGS_FRAME_TYPE_ID,
1035                frame_payload_len as u64,
1036                &d[frame_header_len..]
1037            ),
1038            Err(crate::h3::Error::SettingsError)
1039        );
1040    }
1041
1042    #[test]
1043    fn settings_qpack_only() {
1044        let mut d = [42; 128];
1045
1046        let raw_settings = vec![
1047            (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
1048            (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
1049        ];
1050
1051        let frame = Frame::Settings {
1052            max_field_section_size: None,
1053            qpack_max_table_capacity: Some(0),
1054            qpack_blocked_streams: Some(0),
1055            connect_protocol_enabled: None,
1056            h3_datagram: None,
1057            grease: None,
1058            raw: Some(raw_settings),
1059            additional_settings: None,
1060        };
1061
1062        let frame_payload_len = 4;
1063        let frame_header_len = 2;
1064
1065        let wire_len = {
1066            let mut b = octets::OctetsMut::with_slice(&mut d);
1067            frame.to_bytes(&mut b).unwrap()
1068        };
1069
1070        assert_eq!(wire_len, frame_header_len + frame_payload_len);
1071
1072        assert_eq!(
1073            Frame::from_bytes(
1074                SETTINGS_FRAME_TYPE_ID,
1075                frame_payload_len as u64,
1076                &d[frame_header_len..]
1077            )
1078            .unwrap(),
1079            frame
1080        );
1081    }
1082
1083    #[test]
1084    fn settings_h2_prohibited() {
1085        // We need to test the prohibited values (0x0 | 0x2 | 0x3 | 0x4 | 0x5)
1086        // but the quiche API doesn't support that, so use a manually created
1087        // frame data buffer where d[frame_header_len] is the SETTING type field.
1088        let frame_payload_len = 2u64;
1089        let frame_header_len = 2;
1090        let mut d = [
1091            SETTINGS_FRAME_TYPE_ID as u8,
1092            frame_payload_len as u8,
1093            0x0,
1094            1,
1095        ];
1096
1097        assert_eq!(
1098            Frame::from_bytes(
1099                SETTINGS_FRAME_TYPE_ID,
1100                frame_payload_len,
1101                &d[frame_header_len..]
1102            ),
1103            Err(crate::h3::Error::SettingsError)
1104        );
1105
1106        d[frame_header_len] = 0x2;
1107
1108        assert_eq!(
1109            Frame::from_bytes(
1110                SETTINGS_FRAME_TYPE_ID,
1111                frame_payload_len,
1112                &d[frame_header_len..]
1113            ),
1114            Err(crate::h3::Error::SettingsError)
1115        );
1116
1117        d[frame_header_len] = 0x3;
1118
1119        assert_eq!(
1120            Frame::from_bytes(
1121                SETTINGS_FRAME_TYPE_ID,
1122                frame_payload_len,
1123                &d[frame_header_len..]
1124            ),
1125            Err(crate::h3::Error::SettingsError)
1126        );
1127
1128        d[frame_header_len] = 0x4;
1129
1130        assert_eq!(
1131            Frame::from_bytes(
1132                SETTINGS_FRAME_TYPE_ID,
1133                frame_payload_len,
1134                &d[frame_header_len..]
1135            ),
1136            Err(crate::h3::Error::SettingsError)
1137        );
1138
1139        d[frame_header_len] = 0x5;
1140
1141        assert_eq!(
1142            Frame::from_bytes(
1143                SETTINGS_FRAME_TYPE_ID,
1144                frame_payload_len,
1145                &d[frame_header_len..]
1146            ),
1147            Err(crate::h3::Error::SettingsError)
1148        );
1149    }
1150
1151    #[test]
1152    fn settings_too_big() {
1153        // We need to test a SETTINGS frame that exceeds
1154        // MAX_SETTINGS_PAYLOAD_SIZE, so just craft a special buffer that look
1155        // likes the frame. The payload content doesn't matter since quiche
1156        // should abort before then.
1157        let frame_payload_len = MAX_SETTINGS_PAYLOAD_SIZE + 1;
1158        let frame_header_len = 2;
1159        let d = [
1160            SETTINGS_FRAME_TYPE_ID as u8,
1161            frame_payload_len as u8,
1162            0x1,
1163            1,
1164        ];
1165
1166        assert_eq!(
1167            Frame::from_bytes(
1168                SETTINGS_FRAME_TYPE_ID,
1169                frame_payload_len as u64,
1170                &d[frame_header_len..]
1171            ),
1172            Err(crate::h3::Error::ExcessiveLoad)
1173        );
1174    }
1175
1176    #[test]
1177    fn push_promise() {
1178        let mut d = [42; 128];
1179
1180        let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
1181        let frame_payload_len = 1 + header_block.len();
1182        let frame_header_len = 2;
1183
1184        let frame = Frame::PushPromise {
1185            push_id: 0,
1186            header_block,
1187        };
1188
1189        let wire_len = {
1190            let mut b = octets::OctetsMut::with_slice(&mut d);
1191            frame.to_bytes(&mut b).unwrap()
1192        };
1193
1194        assert_eq!(wire_len, frame_header_len + frame_payload_len);
1195
1196        assert_eq!(
1197            Frame::from_bytes(
1198                PUSH_PROMISE_FRAME_TYPE_ID,
1199                frame_payload_len as u64,
1200                &d[frame_header_len..]
1201            )
1202            .unwrap(),
1203            frame
1204        );
1205    }
1206
1207    #[test]
1208    fn goaway() {
1209        let mut d = [42; 128];
1210
1211        let frame = Frame::GoAway { id: 32 };
1212
1213        let frame_payload_len = 1;
1214        let frame_header_len = 2;
1215
1216        let wire_len = {
1217            let mut b = octets::OctetsMut::with_slice(&mut d);
1218            frame.to_bytes(&mut b).unwrap()
1219        };
1220
1221        assert_eq!(wire_len, frame_header_len + frame_payload_len);
1222
1223        assert_eq!(
1224            Frame::from_bytes(
1225                GOAWAY_FRAME_TYPE_ID,
1226                frame_payload_len as u64,
1227                &d[frame_header_len..]
1228            )
1229            .unwrap(),
1230            frame
1231        );
1232    }
1233
1234    #[test]
1235    fn max_push_id() {
1236        let mut d = [42; 128];
1237
1238        let frame = Frame::MaxPushId { push_id: 128 };
1239
1240        let frame_payload_len = 2;
1241        let frame_header_len = 2;
1242
1243        let wire_len = {
1244            let mut b = octets::OctetsMut::with_slice(&mut d);
1245            frame.to_bytes(&mut b).unwrap()
1246        };
1247
1248        assert_eq!(wire_len, frame_header_len + frame_payload_len);
1249
1250        assert_eq!(
1251            Frame::from_bytes(
1252                MAX_PUSH_FRAME_TYPE_ID,
1253                frame_payload_len as u64,
1254                &d[frame_header_len..]
1255            )
1256            .unwrap(),
1257            frame
1258        );
1259    }
1260
1261    #[test]
1262    fn priority_update_request() {
1263        let mut d = [42; 128];
1264
1265        let prioritized_element_id = 4;
1266        let priority_field_value = b"abcdefghijklm".to_vec();
1267        let frame_payload_len = 1 + priority_field_value.len();
1268        let frame_header_len = 5;
1269
1270        let frame = Frame::PriorityUpdateRequest {
1271            prioritized_element_id,
1272            priority_field_value,
1273        };
1274
1275        let wire_len = {
1276            let mut b = octets::OctetsMut::with_slice(&mut d);
1277            frame.to_bytes(&mut b).unwrap()
1278        };
1279
1280        assert_eq!(wire_len, frame_header_len + frame_payload_len);
1281
1282        assert_eq!(
1283            Frame::from_bytes(
1284                PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID,
1285                frame_payload_len as u64,
1286                &d[frame_header_len..]
1287            )
1288            .unwrap(),
1289            frame
1290        );
1291    }
1292
1293    #[test]
1294    fn priority_update_push() {
1295        let mut d = [42; 128];
1296
1297        let prioritized_element_id = 6;
1298        let priority_field_value = b"abcdefghijklm".to_vec();
1299        let frame_payload_len = 1 + priority_field_value.len();
1300        let frame_header_len = 5;
1301
1302        let frame = Frame::PriorityUpdatePush {
1303            prioritized_element_id,
1304            priority_field_value,
1305        };
1306
1307        let wire_len = {
1308            let mut b = octets::OctetsMut::with_slice(&mut d);
1309            frame.to_bytes(&mut b).unwrap()
1310        };
1311
1312        assert_eq!(wire_len, frame_header_len + frame_payload_len);
1313
1314        assert_eq!(
1315            Frame::from_bytes(
1316                PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID,
1317                frame_payload_len as u64,
1318                &d[frame_header_len..]
1319            )
1320            .unwrap(),
1321            frame
1322        );
1323    }
1324
1325    #[test]
1326    fn unknown_type() {
1327        let d = [42; 12];
1328
1329        assert_eq!(
1330            Frame::from_bytes(255, 12, &d[..]),
1331            Ok(Frame::Unknown {
1332                raw_type: 255,
1333                payload: vec![42; 12]
1334            })
1335        );
1336    }
1337}