1use crate::error::H2Error;
4
5const SETTINGS_HEADER_TABLE_SIZE: u16 = 0x1;
7const SETTINGS_ENABLE_PUSH: u16 = 0x2;
8const SETTINGS_MAX_CONCURRENT_STREAMS: u16 = 0x3;
9const SETTINGS_INITIAL_WINDOW_SIZE: u16 = 0x4;
10const SETTINGS_MAX_FRAME_SIZE: u16 = 0x5;
11const SETTINGS_MAX_HEADER_LIST_SIZE: u16 = 0x6;
12
13pub const MAX_PEER_HEADER_TABLE_SIZE: u32 = 65536;
19
20pub const DEFAULT_MAX_HEADER_LIST_SIZE: u32 = 262_144;
25
26#[derive(Debug, Clone)]
28pub struct Settings {
29 pub header_table_size: u32,
31 pub enable_push: bool,
33 pub max_concurrent_streams: Option<u32>,
35 pub initial_window_size: u32,
37 pub max_frame_size: u32,
39 pub max_header_list_size: Option<u32>,
41}
42
43impl Default for Settings {
44 fn default() -> Self {
45 Self {
46 header_table_size: 4096,
47 enable_push: true,
48 max_concurrent_streams: None,
49 initial_window_size: 65535,
50 max_frame_size: 16384,
51 max_header_list_size: Some(DEFAULT_MAX_HEADER_LIST_SIZE),
52 }
53 }
54}
55
56impl Settings {
57 pub fn client_default() -> Self {
59 Self {
60 enable_push: false,
61 ..Default::default()
62 }
63 }
64
65 pub fn encode_to_vec(&self) -> Vec<u8> {
67 let mut buf = Vec::new();
68 self.encode(&mut buf);
69 buf
70 }
71
72 pub fn encode(&self, buf: &mut Vec<u8>) {
74 encode_setting(buf, SETTINGS_HEADER_TABLE_SIZE, self.header_table_size);
75 encode_setting(
76 buf,
77 SETTINGS_ENABLE_PUSH,
78 if self.enable_push { 1 } else { 0 },
79 );
80 if let Some(v) = self.max_concurrent_streams {
81 encode_setting(buf, SETTINGS_MAX_CONCURRENT_STREAMS, v);
82 }
83 encode_setting(buf, SETTINGS_INITIAL_WINDOW_SIZE, self.initial_window_size);
84 encode_setting(buf, SETTINGS_MAX_FRAME_SIZE, self.max_frame_size);
85 if let Some(v) = self.max_header_list_size {
86 encode_setting(buf, SETTINGS_MAX_HEADER_LIST_SIZE, v);
87 }
88 }
89
90 pub fn decode(buf: &[u8]) -> Result<Self, H2Error> {
92 if !buf.len().is_multiple_of(6) {
93 return Err(H2Error::FrameSizeError);
94 }
95 let mut settings = Settings::default();
96 let mut pos = 0;
97 while pos + 6 <= buf.len() {
98 let id = (u16::from(buf[pos]) << 8) | u16::from(buf[pos + 1]);
99 let value = (u32::from(buf[pos + 2]) << 24)
100 | (u32::from(buf[pos + 3]) << 16)
101 | (u32::from(buf[pos + 4]) << 8)
102 | u32::from(buf[pos + 5]);
103 pos += 6;
104 match id {
105 SETTINGS_HEADER_TABLE_SIZE => {
106 settings.header_table_size = value.min(MAX_PEER_HEADER_TABLE_SIZE);
110 }
111 SETTINGS_ENABLE_PUSH => {
112 if value > 1 {
113 return Err(H2Error::ProtocolError("ENABLE_PUSH must be 0 or 1".into()));
114 }
115 settings.enable_push = value == 1;
116 }
117 SETTINGS_MAX_CONCURRENT_STREAMS => {
118 settings.max_concurrent_streams = Some(value);
119 }
120 SETTINGS_INITIAL_WINDOW_SIZE => {
121 if value > 0x7fff_ffff {
122 return Err(H2Error::FlowControlError);
123 }
124 settings.initial_window_size = value;
125 }
126 SETTINGS_MAX_FRAME_SIZE => {
127 if !(16384..=16_777_215).contains(&value) {
128 return Err(H2Error::ProtocolError("MAX_FRAME_SIZE out of range".into()));
129 }
130 settings.max_frame_size = value;
131 }
132 SETTINGS_MAX_HEADER_LIST_SIZE => {
133 settings.max_header_list_size = Some(value);
134 }
135 _ => {}
137 }
138 }
139 Ok(settings)
140 }
141}
142
143fn encode_setting(buf: &mut Vec<u8>, id: u16, value: u32) {
144 buf.push((id >> 8) as u8);
145 buf.push(id as u8);
146 buf.push((value >> 24) as u8);
147 buf.push((value >> 16) as u8);
148 buf.push((value >> 8) as u8);
149 buf.push(value as u8);
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 #[test]
157 fn default_settings_round_trip() {
158 let settings = Settings::default();
159 let encoded = settings.encode_to_vec();
160 let decoded = Settings::decode(&encoded).unwrap();
161 assert_eq!(decoded.header_table_size, 4096);
162 assert!(decoded.enable_push);
163 assert_eq!(decoded.initial_window_size, 65535);
164 assert_eq!(decoded.max_frame_size, 16384);
165 }
166
167 #[test]
168 fn client_settings_round_trip() {
169 let settings = Settings::client_default();
170 let encoded = settings.encode_to_vec();
171 let decoded = Settings::decode(&encoded).unwrap();
172 assert!(!decoded.enable_push);
173 }
174
175 #[test]
176 fn custom_settings_round_trip() {
177 let settings = Settings {
178 header_table_size: 8192,
179 enable_push: false,
180 max_concurrent_streams: Some(100),
181 initial_window_size: 1048576,
182 max_frame_size: 32768,
183 max_header_list_size: Some(65536),
184 };
185 let encoded = settings.encode_to_vec();
186 let decoded = Settings::decode(&encoded).unwrap();
187 assert_eq!(decoded.header_table_size, 8192);
188 assert!(!decoded.enable_push);
189 assert_eq!(decoded.max_concurrent_streams, Some(100));
190 assert_eq!(decoded.initial_window_size, 1048576);
191 assert_eq!(decoded.max_frame_size, 32768);
192 assert_eq!(decoded.max_header_list_size, Some(65536));
193 }
194
195 #[test]
196 fn invalid_enable_push_rejected() {
197 let mut buf = Vec::new();
198 encode_setting(&mut buf, 0x2, 2); assert!(Settings::decode(&buf).is_err());
200 }
201
202 #[test]
203 fn invalid_window_size_rejected() {
204 let mut buf = Vec::new();
205 encode_setting(&mut buf, 0x4, 0x8000_0000); assert!(Settings::decode(&buf).is_err());
207 }
208
209 #[test]
210 fn invalid_max_frame_size_rejected() {
211 let mut buf = Vec::new();
212 encode_setting(&mut buf, 0x5, 100); assert!(Settings::decode(&buf).is_err());
214 }
215
216 #[test]
217 fn unknown_setting_ignored() {
218 let mut buf = Vec::new();
219 encode_setting(&mut buf, 0xff, 42);
220 let decoded = Settings::decode(&buf).unwrap();
221 assert_eq!(decoded.header_table_size, 4096); }
223}