1use 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
49const 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 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 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 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 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 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 0x0 | 0x2 | 0x3 | 0x4 | 0x5 =>
623 return Err(super::Error::SettingsError),
624
625 _ => {
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 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 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 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}