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
49pub(crate) const 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 before = b.off();
650 let push_id = b.get_varint()?;
651 let header_block_length = payload_length - (b.off() - before) as u64;
652 let header_block = b.get_bytes(header_block_length as usize)?.to_vec();
653
654 Ok(Frame::PushPromise {
655 push_id,
656 header_block,
657 })
658}
659
660fn parse_priority_update(
661 frame_type: u64, payload_length: u64, b: &mut octets::Octets,
662) -> Result<Frame> {
663 let before = b.off();
664 let prioritized_element_id = b.get_varint()?;
665 let priority_field_value_length = payload_length - (b.off() - before) as u64;
666 let priority_field_value =
667 b.get_bytes(priority_field_value_length as usize)?.to_vec();
668
669 match frame_type {
670 PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID =>
671 Ok(Frame::PriorityUpdateRequest {
672 prioritized_element_id,
673 priority_field_value,
674 }),
675
676 PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID => Ok(Frame::PriorityUpdatePush {
677 prioritized_element_id,
678 priority_field_value,
679 }),
680
681 _ => unreachable!(),
682 }
683}
684
685#[cfg(test)]
686mod tests {
687 use super::*;
688
689 #[test]
690 fn data() {
691 let mut d = [42; 128];
692
693 let payload = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
694 let frame_payload_len = payload.len();
695 let frame_header_len = 2;
696
697 let frame = Frame::Data { payload };
698
699 let wire_len = {
700 let mut b = octets::OctetsMut::with_slice(&mut d);
701 frame.to_bytes(&mut b).unwrap()
702 };
703
704 assert_eq!(wire_len, frame_header_len + frame_payload_len);
705
706 assert_eq!(
707 Frame::from_bytes(
708 DATA_FRAME_TYPE_ID,
709 frame_payload_len as u64,
710 &d[frame_header_len..]
711 )
712 .unwrap(),
713 frame
714 );
715 }
716
717 #[test]
718 fn headers() {
719 let mut d = [42; 128];
720
721 let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
722 let frame_payload_len = header_block.len();
723 let frame_header_len = 2;
724
725 let frame = Frame::Headers { header_block };
726
727 let wire_len = {
728 let mut b = octets::OctetsMut::with_slice(&mut d);
729 frame.to_bytes(&mut b).unwrap()
730 };
731
732 assert_eq!(wire_len, frame_header_len + frame_payload_len);
733
734 assert_eq!(
735 Frame::from_bytes(
736 HEADERS_FRAME_TYPE_ID,
737 frame_payload_len as u64,
738 &d[frame_header_len..]
739 )
740 .unwrap(),
741 frame
742 );
743 }
744
745 #[test]
746 fn cancel_push() {
747 let mut d = [42; 128];
748
749 let frame = Frame::CancelPush { push_id: 0 };
750
751 let frame_payload_len = 1;
752 let frame_header_len = 2;
753
754 let wire_len = {
755 let mut b = octets::OctetsMut::with_slice(&mut d);
756 frame.to_bytes(&mut b).unwrap()
757 };
758
759 assert_eq!(wire_len, frame_header_len + frame_payload_len);
760
761 assert_eq!(
762 Frame::from_bytes(
763 CANCEL_PUSH_FRAME_TYPE_ID,
764 frame_payload_len as u64,
765 &d[frame_header_len..]
766 )
767 .unwrap(),
768 frame
769 );
770 }
771
772 #[test]
773 fn settings_all_no_grease() {
774 let mut d = [42; 128];
775
776 let raw_settings = vec![
777 (SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
778 (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
779 (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
780 (SETTINGS_ENABLE_CONNECT_PROTOCOL, 0),
781 (SETTINGS_H3_DATAGRAM_00, 0),
782 (SETTINGS_H3_DATAGRAM, 0),
783 ];
784
785 let frame = Frame::Settings {
786 max_field_section_size: Some(0),
787 qpack_max_table_capacity: Some(0),
788 qpack_blocked_streams: Some(0),
789 connect_protocol_enabled: Some(0),
790 h3_datagram: Some(0),
791 grease: None,
792 raw: Some(raw_settings),
793 additional_settings: None,
794 };
795
796 let frame_payload_len = 13;
797 let frame_header_len = 2;
798
799 let wire_len = {
800 let mut b = octets::OctetsMut::with_slice(&mut d);
801 frame.to_bytes(&mut b).unwrap()
802 };
803
804 assert_eq!(wire_len, frame_header_len + frame_payload_len);
805
806 assert_eq!(
807 Frame::from_bytes(
808 SETTINGS_FRAME_TYPE_ID,
809 frame_payload_len as u64,
810 &d[frame_header_len..]
811 )
812 .unwrap(),
813 frame
814 );
815 }
816
817 #[test]
818 fn settings_all_grease() {
819 let mut d = [42; 128];
820
821 let frame = Frame::Settings {
822 max_field_section_size: Some(0),
823 qpack_max_table_capacity: Some(0),
824 qpack_blocked_streams: Some(0),
825 connect_protocol_enabled: Some(0),
826 h3_datagram: Some(0),
827 grease: Some((33, 33)),
828 raw: Default::default(),
829 additional_settings: None,
830 };
831
832 let raw_settings = vec![
833 (SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
834 (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
835 (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
836 (SETTINGS_ENABLE_CONNECT_PROTOCOL, 0),
837 (SETTINGS_H3_DATAGRAM_00, 0),
838 (SETTINGS_H3_DATAGRAM, 0),
839 (33, 33),
840 ];
841
842 let frame_parsed = Frame::Settings {
845 max_field_section_size: Some(0),
846 qpack_max_table_capacity: Some(0),
847 qpack_blocked_streams: Some(0),
848 connect_protocol_enabled: Some(0),
849 h3_datagram: Some(0),
850 grease: None,
851 raw: Some(raw_settings),
852 additional_settings: Some(vec![(33, 33)]),
853 };
854
855 let frame_payload_len = 15;
856 let frame_header_len = 2;
857
858 let wire_len = {
859 let mut b = octets::OctetsMut::with_slice(&mut d);
860 frame.to_bytes(&mut b).unwrap()
861 };
862
863 assert_eq!(wire_len, frame_header_len + frame_payload_len);
864
865 assert_eq!(
866 Frame::from_bytes(
867 SETTINGS_FRAME_TYPE_ID,
868 frame_payload_len as u64,
869 &d[frame_header_len..]
870 )
871 .unwrap(),
872 frame_parsed
873 );
874 }
875
876 #[test]
877 fn settings_h3_only() {
878 let mut d = [42; 128];
879
880 let raw_settings = vec![(SETTINGS_MAX_FIELD_SECTION_SIZE, 1024)];
881
882 let frame = Frame::Settings {
883 max_field_section_size: Some(1024),
884 qpack_max_table_capacity: None,
885 qpack_blocked_streams: None,
886 connect_protocol_enabled: None,
887 h3_datagram: None,
888 grease: None,
889 raw: Some(raw_settings),
890 additional_settings: None,
891 };
892
893 let frame_payload_len = 3;
894 let frame_header_len = 2;
895
896 let wire_len = {
897 let mut b = octets::OctetsMut::with_slice(&mut d);
898 frame.to_bytes(&mut b).unwrap()
899 };
900
901 assert_eq!(wire_len, frame_header_len + frame_payload_len);
902
903 assert_eq!(
904 Frame::from_bytes(
905 SETTINGS_FRAME_TYPE_ID,
906 frame_payload_len as u64,
907 &d[frame_header_len..]
908 )
909 .unwrap(),
910 frame
911 );
912 }
913
914 #[test]
915 fn settings_h3_connect_protocol_enabled() {
916 let mut d = [42; 128];
917
918 let raw_settings = vec![(SETTINGS_ENABLE_CONNECT_PROTOCOL, 1)];
919
920 let frame = Frame::Settings {
921 max_field_section_size: None,
922 qpack_max_table_capacity: None,
923 qpack_blocked_streams: None,
924 connect_protocol_enabled: Some(1),
925 h3_datagram: None,
926 grease: None,
927 raw: Some(raw_settings),
928 additional_settings: None,
929 };
930
931 let frame_payload_len = 2;
932 let frame_header_len = 2;
933
934 let wire_len = {
935 let mut b = octets::OctetsMut::with_slice(&mut d);
936 frame.to_bytes(&mut b).unwrap()
937 };
938
939 assert_eq!(wire_len, frame_header_len + frame_payload_len);
940
941 assert_eq!(
942 Frame::from_bytes(
943 SETTINGS_FRAME_TYPE_ID,
944 frame_payload_len as u64,
945 &d[frame_header_len..]
946 )
947 .unwrap(),
948 frame
949 );
950 }
951
952 #[test]
953 fn settings_h3_connect_protocol_enabled_bad() {
954 let mut d = [42; 128];
955
956 let raw_settings = vec![(SETTINGS_ENABLE_CONNECT_PROTOCOL, 9)];
957
958 let frame = Frame::Settings {
959 max_field_section_size: None,
960 qpack_max_table_capacity: None,
961 qpack_blocked_streams: None,
962 connect_protocol_enabled: Some(9),
963 h3_datagram: None,
964 grease: None,
965 raw: Some(raw_settings),
966 additional_settings: None,
967 };
968
969 let frame_payload_len = 2;
970 let frame_header_len = 2;
971
972 let wire_len = {
973 let mut b = octets::OctetsMut::with_slice(&mut d);
974 frame.to_bytes(&mut b).unwrap()
975 };
976
977 assert_eq!(wire_len, frame_header_len + frame_payload_len);
978
979 assert_eq!(
980 Frame::from_bytes(
981 SETTINGS_FRAME_TYPE_ID,
982 frame_payload_len as u64,
983 &d[frame_header_len..]
984 ),
985 Err(crate::h3::Error::SettingsError)
986 );
987 }
988
989 #[test]
990 fn settings_h3_dgram_only() {
991 let mut d = [42; 128];
992
993 let raw_settings =
994 vec![(SETTINGS_H3_DATAGRAM_00, 1), (SETTINGS_H3_DATAGRAM, 1)];
995
996 let frame = Frame::Settings {
997 max_field_section_size: None,
998 qpack_max_table_capacity: None,
999 qpack_blocked_streams: None,
1000 connect_protocol_enabled: None,
1001 h3_datagram: Some(1),
1002 grease: None,
1003 raw: Some(raw_settings),
1004 additional_settings: None,
1005 };
1006
1007 let frame_payload_len = 5;
1008 let frame_header_len = 2;
1009
1010 let wire_len = {
1011 let mut b = octets::OctetsMut::with_slice(&mut d);
1012 frame.to_bytes(&mut b).unwrap()
1013 };
1014
1015 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1016
1017 assert_eq!(
1018 Frame::from_bytes(
1019 SETTINGS_FRAME_TYPE_ID,
1020 frame_payload_len as u64,
1021 &d[frame_header_len..]
1022 )
1023 .unwrap(),
1024 frame
1025 );
1026 }
1027
1028 #[test]
1029 fn settings_h3_dgram_bad() {
1030 let mut d = [42; 128];
1031
1032 let frame = Frame::Settings {
1033 max_field_section_size: None,
1034 qpack_max_table_capacity: None,
1035 qpack_blocked_streams: None,
1036 connect_protocol_enabled: None,
1037 h3_datagram: Some(5),
1038 grease: None,
1039 raw: Default::default(),
1040 additional_settings: None,
1041 };
1042
1043 let frame_payload_len = 5;
1044 let frame_header_len = 2;
1045
1046 let wire_len = {
1047 let mut b = octets::OctetsMut::with_slice(&mut d);
1048 frame.to_bytes(&mut b).unwrap()
1049 };
1050
1051 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1052
1053 assert_eq!(
1054 Frame::from_bytes(
1055 SETTINGS_FRAME_TYPE_ID,
1056 frame_payload_len as u64,
1057 &d[frame_header_len..]
1058 ),
1059 Err(crate::h3::Error::SettingsError)
1060 );
1061 }
1062
1063 #[test]
1064 fn settings_qpack_only() {
1065 let mut d = [42; 128];
1066
1067 let raw_settings = vec![
1068 (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
1069 (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
1070 ];
1071
1072 let frame = Frame::Settings {
1073 max_field_section_size: None,
1074 qpack_max_table_capacity: Some(0),
1075 qpack_blocked_streams: Some(0),
1076 connect_protocol_enabled: None,
1077 h3_datagram: None,
1078 grease: None,
1079 raw: Some(raw_settings),
1080 additional_settings: None,
1081 };
1082
1083 let frame_payload_len = 4;
1084 let frame_header_len = 2;
1085
1086 let wire_len = {
1087 let mut b = octets::OctetsMut::with_slice(&mut d);
1088 frame.to_bytes(&mut b).unwrap()
1089 };
1090
1091 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1092
1093 assert_eq!(
1094 Frame::from_bytes(
1095 SETTINGS_FRAME_TYPE_ID,
1096 frame_payload_len as u64,
1097 &d[frame_header_len..]
1098 )
1099 .unwrap(),
1100 frame
1101 );
1102 }
1103
1104 #[test]
1105 fn settings_h2_prohibited() {
1106 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 push_promise_non_minimal_varint() {
1229 let header_block = b"\x00\x01\x02";
1234 let mut payload = vec![0x40u8, 0x25]; payload.extend_from_slice(header_block);
1236 let payload_length = payload.len() as u64;
1237 let frame = Frame::from_bytes(
1238 PUSH_PROMISE_FRAME_TYPE_ID,
1239 payload_length,
1240 &payload,
1241 )
1242 .expect("non-minimal varint was parsed correctly");
1243 assert_eq!(frame, Frame::PushPromise {
1244 push_id: 37,
1245 header_block: header_block.to_vec(),
1246 });
1247 }
1248
1249 #[test]
1250 fn goaway() {
1251 let mut d = [42; 128];
1252
1253 let frame = Frame::GoAway { id: 32 };
1254
1255 let frame_payload_len = 1;
1256 let frame_header_len = 2;
1257
1258 let wire_len = {
1259 let mut b = octets::OctetsMut::with_slice(&mut d);
1260 frame.to_bytes(&mut b).unwrap()
1261 };
1262
1263 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1264
1265 assert_eq!(
1266 Frame::from_bytes(
1267 GOAWAY_FRAME_TYPE_ID,
1268 frame_payload_len as u64,
1269 &d[frame_header_len..]
1270 )
1271 .unwrap(),
1272 frame
1273 );
1274 }
1275
1276 #[test]
1277 fn max_push_id() {
1278 let mut d = [42; 128];
1279
1280 let frame = Frame::MaxPushId { push_id: 128 };
1281
1282 let frame_payload_len = 2;
1283 let frame_header_len = 2;
1284
1285 let wire_len = {
1286 let mut b = octets::OctetsMut::with_slice(&mut d);
1287 frame.to_bytes(&mut b).unwrap()
1288 };
1289
1290 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1291
1292 assert_eq!(
1293 Frame::from_bytes(
1294 MAX_PUSH_FRAME_TYPE_ID,
1295 frame_payload_len as u64,
1296 &d[frame_header_len..]
1297 )
1298 .unwrap(),
1299 frame
1300 );
1301 }
1302
1303 #[test]
1304 fn priority_update_request() {
1305 let mut d = [42; 128];
1306
1307 let prioritized_element_id = 4;
1308 let priority_field_value = b"abcdefghijklm".to_vec();
1309 let frame_payload_len = 1 + priority_field_value.len();
1310 let frame_header_len = 5;
1311
1312 let frame = Frame::PriorityUpdateRequest {
1313 prioritized_element_id,
1314 priority_field_value,
1315 };
1316
1317 let wire_len = {
1318 let mut b = octets::OctetsMut::with_slice(&mut d);
1319 frame.to_bytes(&mut b).unwrap()
1320 };
1321
1322 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1323
1324 assert_eq!(
1325 Frame::from_bytes(
1326 PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID,
1327 frame_payload_len as u64,
1328 &d[frame_header_len..]
1329 )
1330 .unwrap(),
1331 frame
1332 );
1333 }
1334
1335 #[test]
1336 fn priority_update_push() {
1337 let mut d = [42; 128];
1338
1339 let prioritized_element_id = 6;
1340 let priority_field_value = b"abcdefghijklm".to_vec();
1341 let frame_payload_len = 1 + priority_field_value.len();
1342 let frame_header_len = 5;
1343
1344 let frame = Frame::PriorityUpdatePush {
1345 prioritized_element_id,
1346 priority_field_value,
1347 };
1348
1349 let wire_len = {
1350 let mut b = octets::OctetsMut::with_slice(&mut d);
1351 frame.to_bytes(&mut b).unwrap()
1352 };
1353
1354 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1355
1356 assert_eq!(
1357 Frame::from_bytes(
1358 PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID,
1359 frame_payload_len as u64,
1360 &d[frame_header_len..]
1361 )
1362 .unwrap(),
1363 frame
1364 );
1365 }
1366
1367 #[test]
1368 fn priority_update_non_minimal_varint() {
1369 let priority_field = b"u=3";
1374 let mut payload = vec![0x40u8, 0x25];
1375 payload.extend_from_slice(priority_field);
1376 let payload_length = payload.len() as u64;
1377
1378 let frame = Frame::from_bytes(
1379 PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID,
1380 payload_length,
1381 &payload,
1382 )
1383 .expect("non-minimal varint was parsed correctly");
1384
1385 assert_eq!(frame, Frame::PriorityUpdateRequest {
1386 prioritized_element_id: 37,
1387 priority_field_value: priority_field.to_vec(),
1388 });
1389 }
1390
1391 #[test]
1392 fn unknown_type() {
1393 let d = [42; 12];
1394
1395 assert_eq!(
1396 Frame::from_bytes(255, 12, &d[..]),
1397 Ok(Frame::Unknown {
1398 raw_type: 255,
1399 payload: vec![42; 12]
1400 })
1401 );
1402 }
1403}