1use crate::{code, H3Error};
4use simoom_quic::coding::{put_varint, Reader};
5
6pub const DATA: u64 = 0x00;
7pub const HEADERS: u64 = 0x01;
8pub const CANCEL_PUSH: u64 = 0x03;
9pub const SETTINGS: u64 = 0x04;
10pub const PUSH_PROMISE: u64 = 0x05;
11pub const GOAWAY: u64 = 0x07;
12pub const MAX_PUSH_ID: u64 = 0x0d;
13
14pub fn is_reserved_h2(t: u64) -> bool {
16 matches!(t, 0x02 | 0x06 | 0x08 | 0x09)
17}
18
19pub fn single_varint(p: &[u8]) -> Result<u64, H3Error> {
21 let mut r = Reader::new(p);
22 match r.varint() {
23 Some(v) if r.is_empty() => Ok(v),
24 _ => Err(H3Error::new(code::FRAME_ERROR, "malformed frame")),
25 }
26}
27
28const QPACK_MAX_TABLE_CAPACITY: u64 = 0x01;
29const MAX_FIELD_SECTION_SIZE: u64 = 0x06;
30const QPACK_BLOCKED_STREAMS: u64 = 0x07;
31const ENABLE_CONNECT_PROTOCOL: u64 = 0x08;
33
34#[derive(Clone, Debug, Default, PartialEq, Eq)]
36pub struct Settings {
37 pub qpack_max_table_capacity: Option<u64>,
38 pub max_field_section_size: Option<u64>,
39 pub qpack_blocked_streams: Option<u64>,
40 pub enable_connect_protocol: Option<u64>,
42}
43
44impl Settings {
45 pub fn encode(&self, out: &mut Vec<u8>) {
47 let mut p = Vec::with_capacity(24);
48 for (id, v) in [
49 (QPACK_MAX_TABLE_CAPACITY, self.qpack_max_table_capacity),
50 (MAX_FIELD_SECTION_SIZE, self.max_field_section_size),
51 (QPACK_BLOCKED_STREAMS, self.qpack_blocked_streams),
52 (ENABLE_CONNECT_PROTOCOL, self.enable_connect_protocol),
53 ] {
54 if let Some(v) = v {
55 put_varint(&mut p, id);
56 put_varint(&mut p, v);
57 }
58 }
59 put_varint(&mut p, 0x1f * 3 + 0x21);
61 put_varint(&mut p, 0);
62 put_varint(out, SETTINGS);
63 put_varint(out, p.len() as u64);
64 out.extend_from_slice(&p);
65 }
66
67 pub fn decode(p: &[u8]) -> Result<Self, H3Error> {
68 let err = |r| H3Error::new(code::SETTINGS_ERROR, r);
69 let mut s = Settings::default();
70 let mut r = Reader::new(p);
71 let mut seen: Vec<u64> = Vec::new();
72 while !r.is_empty() {
73 let (Some(id), Some(v)) = (r.varint(), r.varint()) else {
74 return Err(H3Error::new(code::FRAME_ERROR, "malformed SETTINGS"));
75 };
76 if seen.contains(&id) {
77 return Err(err("duplicate setting"));
78 }
79 if seen.len() >= 256 {
80 return Err(H3Error::new(code::EXCESSIVE_LOAD, "too many settings"));
81 }
82 seen.push(id);
83 match id {
84 QPACK_MAX_TABLE_CAPACITY => s.qpack_max_table_capacity = Some(v),
85 MAX_FIELD_SECTION_SIZE => s.max_field_section_size = Some(v),
86 QPACK_BLOCKED_STREAMS => s.qpack_blocked_streams = Some(v),
87 ENABLE_CONNECT_PROTOCOL => {
88 if v > 1 {
89 return Err(err("invalid SETTINGS_ENABLE_CONNECT_PROTOCOL"));
90 }
91 s.enable_connect_protocol = Some(v);
92 }
93 0x00 | 0x02 | 0x03 | 0x04 | 0x05 => return Err(err("HTTP/2 setting")),
95 _ => {}
96 }
97 }
98 Ok(s)
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn settings_roundtrip_and_errors() {
108 let s = Settings { qpack_max_table_capacity: Some(4096), max_field_section_size: Some(16384), qpack_blocked_streams: Some(16), enable_connect_protocol: Some(1) };
109 let mut b = Vec::new();
110 s.encode(&mut b);
111 let mut r = Reader::new(&b);
112 assert_eq!(r.varint(), Some(SETTINGS));
113 let len = r.varint().unwrap() as usize;
114 assert_eq!(Settings::decode(r.bytes(len).unwrap()).unwrap(), s);
115 assert_eq!(Settings::decode(&[0x06, 0x01, 0x06, 0x02]).unwrap_err().code, code::SETTINGS_ERROR);
116 assert_eq!(Settings::decode(&[0x02, 0x01]).unwrap_err().code, code::SETTINGS_ERROR);
117 assert_eq!(Settings::decode(&[0x06]).unwrap_err().code, code::FRAME_ERROR);
118 assert!(Settings::decode(&[0x21, 0x05]).is_ok());
119 assert_eq!(Settings::decode(&[0x08, 0x02]).unwrap_err().code, code::SETTINGS_ERROR);
120 assert_eq!(single_varint(&[0x05, 0x00]).unwrap_err().code, code::FRAME_ERROR);
121 }
122}