webparse/http/http2/frame/
settings.rs1use crate::{
14 http::http2::{
15 frame::{Kind, StreamIdentifier},
16 DEFAULT_MAX_FRAME_SIZE, MAX_INITIAL_WINDOW_SIZE, MAX_MAX_FRAME_SIZE,
17 },
18 Http2Error, WebResult,
19};
20use algorithm::buf::{Binary, BinaryMut, Bt, BtMut};
21
22use super::{frame::FrameHeader, Flag};
23
24#[derive(Clone, Eq, PartialEq, Debug, Hash)]
25pub struct Settings {
26 flags: Flag,
27 header_table_size: Option<u32>,
29 enable_push: Option<u32>,
30 max_concurrent_streams: Option<u32>,
31 initial_window_size: Option<u32>,
32 max_frame_size: Option<u32>,
33 max_header_list_size: Option<u32>,
34 enable_connect_protocol: Option<u32>,
35}
36
37#[derive(Debug)]
38pub enum Setting {
39 HeaderTableSize(u32),
43 EnablePush(u32),
49 MaxConcurrentStreams(u32),
56 InitialWindowSize(u32),
62 MaxFrameSize(u32),
67 MaxHeaderListSize(u32),
71 EnableConnectProtocol(u32),
72}
73
74impl Default for Settings {
75 fn default() -> Self {
76 Self {
87 flags: Default::default(),
88 header_table_size: Default::default(),
89 enable_push: Default::default(),
90 max_concurrent_streams: Default::default(),
91 initial_window_size: Default::default(),
92 max_frame_size: Default::default(),
93 max_header_list_size: Default::default(),
94 enable_connect_protocol: Default::default(),
95 }
96 }
97}
98
99impl Setting {
102 pub fn from_id(id: u16, val: u32) -> Option<Setting> {
106 use self::Setting::*;
107
108 match id {
109 1 => Some(HeaderTableSize(val)),
110 2 => Some(EnablePush(val)),
111 3 => Some(MaxConcurrentStreams(val)),
112 4 => Some(InitialWindowSize(val)),
113 5 => Some(MaxFrameSize(val)),
114 6 => Some(MaxHeaderListSize(val)),
115 8 => Some(EnableConnectProtocol(val)),
116 _ => None,
117 }
118 }
119
120 fn parse<T: Bt>(bytes: &mut T) -> Option<Setting> {
121 let id: u16 = bytes.get_u16();
122 let val: u32 = bytes.get_u32();
123
124 Setting::from_id(id, val)
125 }
126
127 fn encode<B: Bt + BtMut>(&self, dst: &mut B) -> WebResult<usize> {
128 use self::Setting::*;
129
130 let (kind, val) = match *self {
131 HeaderTableSize(v) => (1, v),
132 EnablePush(v) => (2, v),
133 MaxConcurrentStreams(v) => (3, v),
134 InitialWindowSize(v) => (4, v),
135 MaxFrameSize(v) => (5, v),
136 MaxHeaderListSize(v) => (6, v),
137 EnableConnectProtocol(v) => (8, v),
138 };
139
140 dst.put_u16(kind);
141 dst.put_u32(val);
142 Ok(6)
143 }
144}
145
146impl Settings {
147 pub fn ack() -> Settings {
148 Settings {
149 flags: Flag::ack(),
150 ..Settings::default()
151 }
152 }
153
154 pub fn is_ack(&self) -> bool {
155 self.flags.is_ack()
156 }
157
158 pub fn flags(&self) -> Flag {
159 self.flags
160 }
161
162 pub fn initial_window_size(&self) -> Option<u32> {
163 self.initial_window_size
164 }
165
166 pub fn set_initial_window_size(&mut self, size: Option<u32>) {
167 self.initial_window_size = size;
168 }
169
170 pub fn max_concurrent_streams(&self) -> Option<u32> {
171 self.max_concurrent_streams
172 }
173
174 pub fn set_max_concurrent_streams(&mut self, max: Option<u32>) {
175 self.max_concurrent_streams = max;
176 }
177
178 pub fn max_frame_size(&self) -> Option<u32> {
179 self.max_frame_size
180 }
181
182 pub fn set_max_frame_size(&mut self, size: Option<u32>) {
183 if let Some(val) = size {
184 assert!(DEFAULT_MAX_FRAME_SIZE <= val && val <= MAX_MAX_FRAME_SIZE);
185 }
186 self.max_frame_size = size;
187 }
188
189 pub fn max_header_list_size(&self) -> Option<u32> {
190 self.max_header_list_size
191 }
192
193 pub fn set_max_header_list_size(&mut self, size: Option<u32>) {
194 self.max_header_list_size = size;
195 }
196
197 pub fn is_push_enabled(&self) -> Option<bool> {
198 self.enable_push.map(|val| val != 0)
199 }
200
201 pub fn set_enable_push(&mut self, enable: bool) {
202 self.enable_push = Some(enable as u32);
203 }
204
205 pub fn is_extended_connect_protocol_enabled(&self) -> Option<bool> {
206 self.enable_connect_protocol.map(|val| val != 0)
207 }
208
209 pub fn set_enable_connect_protocol(&mut self, val: Option<u32>) {
210 self.enable_connect_protocol = val;
211 }
212
213 pub fn header_table_size(&self) -> Option<u32> {
214 self.header_table_size
215 }
216
217 fn parse_setting<T: Bt>(payload: &mut T) -> WebResult<Settings> {
224 use self::Setting::*;
225
226 if payload.remaining() % 6 != 0 {
228 return Err(Http2Error::into(Http2Error::InvalidPayloadLength));
229 }
230
231 let mut settings = Settings::default();
232 debug_assert!(!settings.flags.is_ack());
233
234 let len = payload.remaining() / 6;
235 for _ in 0..len {
236 match Setting::parse(payload) {
237 Some(HeaderTableSize(val)) => {
238 settings.header_table_size = Some(val);
239 }
240 Some(EnablePush(val)) => match val {
241 0 | 1 => {
242 settings.enable_push = Some(val);
243 }
244 _ => {
245 return Err(Http2Error::InvalidSettingValue.into());
246 }
247 },
248 Some(MaxConcurrentStreams(val)) => {
249 settings.max_concurrent_streams = Some(val);
250 }
251 Some(InitialWindowSize(val)) => {
252 if val as usize > MAX_INITIAL_WINDOW_SIZE {
253 return Err(Http2Error::InvalidSettingValue.into());
254 } else {
255 settings.initial_window_size = Some(val);
256 }
257 }
258 Some(MaxFrameSize(val)) => {
259 if DEFAULT_MAX_FRAME_SIZE <= val && val <= MAX_MAX_FRAME_SIZE {
260 settings.max_frame_size = Some(val);
261 } else {
262 return Err(Http2Error::InvalidSettingValue.into());
263 }
264 }
265 Some(MaxHeaderListSize(val)) => {
266 settings.max_header_list_size = Some(val);
267 }
268 Some(EnableConnectProtocol(val)) => match val {
269 0 | 1 => {
270 settings.enable_connect_protocol = Some(val);
271 }
272 _ => {
273 return Err(Http2Error::InvalidSettingValue.into());
274 }
275 },
276 None => {}
277 }
278 }
279 Ok(settings)
280 }
281
282 pub fn parse<T: Bt>(head: FrameHeader, payload: &mut T) -> WebResult<Settings> {
283 debug_assert_eq!(head.kind(), &Kind::Settings);
284
285 if !head.stream_id().is_zero() {
286 return Err(Http2Error::into(Http2Error::InvalidStreamId));
287 }
288
289 let flag = head.flag();
291
292 if flag.is_ack() {
293 if payload.has_remaining() {
295 return Err(Http2Error::into(Http2Error::InvalidPayloadLength));
296 }
297
298 return Ok(Settings::ack());
300 }
301
302 Self::parse_setting(payload)
303 }
304
305 pub fn payload_len(&self) -> usize {
306 let mut len = 0;
307 self.for_each(|_| len += 6);
308 len
309 }
310
311 pub fn parse_http_settings(&self, value: &str) -> WebResult<Settings> {
312 use base64::Engine;
313 match base64::engine::general_purpose::URL_SAFE_NO_PAD.decode(value.as_bytes()) {
314 Err(_e) => {
315 return Err(crate::WebError::Http2(Http2Error::InvalidSettingValue));
316 }
317 Ok(v) => {
318 let mut binary = Binary::from(v);
319 return Self::parse_setting(&mut binary);
320 }
321 }
322 }
323
324 pub fn encode_http_settings(&self) -> String {
325 use base64::Engine;
326 let mut dst = BinaryMut::new();
327 self.for_each(|setting| {
328 log::trace!("HTTP2: 编码设置信息; val={:?}", setting);
329 setting.encode(&mut dst).unwrap();
330 });
331 base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(dst.chunk())
332 }
333
334 pub fn encode<B: Bt + BtMut>(&self, dst: &mut B) -> WebResult<usize> {
335 let mut head =
337 FrameHeader::new(Kind::Settings, self.flags.into(), StreamIdentifier::zero());
338 head.length = self.payload_len() as u32;
339
340 let mut size = 0;
341 size += head.encode(dst)?;
342
343 self.for_each(|setting| size += setting.encode(dst).unwrap());
345 log::trace!("HTTP2: 编码设置信息; len={}", size);
346 Ok(size)
347 }
348
349 fn for_each<F: FnMut(Setting)>(&self, mut f: F) {
350 use self::Setting::*;
351
352 if let Some(v) = self.header_table_size {
353 f(HeaderTableSize(v));
354 }
355
356 if let Some(v) = self.enable_push {
357 f(EnablePush(v));
358 }
359
360 if let Some(v) = self.max_concurrent_streams {
361 f(MaxConcurrentStreams(v));
362 }
363
364 if let Some(v) = self.initial_window_size {
365 f(InitialWindowSize(v));
366 }
367
368 if let Some(v) = self.max_frame_size {
369 f(MaxFrameSize(v));
370 }
371
372 if let Some(v) = self.max_header_list_size {
373 f(MaxHeaderListSize(v));
374 }
375
376 if let Some(v) = self.enable_connect_protocol {
377 f(EnableConnectProtocol(v));
378 }
379 }
380}