1use super::Result;
28
29#[cfg(feature = "qlog")]
30use qlog::events::h3::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 { headers: vec![] },
348
349 Frame::CancelPush { push_id } =>
350 Http3Frame::CancelPush { push_id: *push_id },
351
352 Frame::Settings {
353 max_field_section_size,
354 qpack_max_table_capacity,
355 qpack_blocked_streams,
356 connect_protocol_enabled,
357 h3_datagram,
358 grease,
359 additional_settings,
360 ..
361 } => {
362 let mut settings = vec![];
363
364 if let Some(v) = max_field_section_size {
365 settings.push(qlog::events::h3::Setting {
366 name: "MAX_FIELD_SECTION_SIZE".to_string(),
367 value: *v,
368 });
369 }
370
371 if let Some(v) = qpack_max_table_capacity {
372 settings.push(qlog::events::h3::Setting {
373 name: "QPACK_MAX_TABLE_CAPACITY".to_string(),
374 value: *v,
375 });
376 }
377
378 if let Some(v) = qpack_blocked_streams {
379 settings.push(qlog::events::h3::Setting {
380 name: "QPACK_BLOCKED_STREAMS".to_string(),
381 value: *v,
382 });
383 }
384
385 if let Some(v) = connect_protocol_enabled {
386 settings.push(qlog::events::h3::Setting {
387 name: "SETTINGS_ENABLE_CONNECT_PROTOCOL".to_string(),
388 value: *v,
389 });
390 }
391
392 if let Some(v) = h3_datagram {
393 settings.push(qlog::events::h3::Setting {
394 name: "H3_DATAGRAM".to_string(),
395 value: *v,
396 });
397 }
398
399 if let Some((k, v)) = grease {
400 settings.push(qlog::events::h3::Setting {
401 name: k.to_string(),
402 value: *v,
403 });
404 }
405
406 if let Some(additional_settings) = additional_settings {
407 for (k, v) in additional_settings {
408 settings.push(qlog::events::h3::Setting {
409 name: k.to_string(),
410 value: *v,
411 });
412 }
413 }
414
415 qlog::events::h3::Http3Frame::Settings { settings }
416 },
417
418 Frame::PushPromise { push_id, .. } => Http3Frame::PushPromise {
422 push_id: *push_id,
423 headers: vec![],
424 },
425
426 Frame::GoAway { id } => Http3Frame::Goaway { id: *id },
427
428 Frame::MaxPushId { push_id } =>
429 Http3Frame::MaxPushId { push_id: *push_id },
430
431 Frame::PriorityUpdateRequest {
432 prioritized_element_id,
433 priority_field_value,
434 } => Http3Frame::PriorityUpdate {
435 target_stream_type:
436 qlog::events::h3::H3PriorityTargetStreamType::Request,
437 prioritized_element_id: *prioritized_element_id,
438 priority_field_value: String::from_utf8_lossy(
439 priority_field_value,
440 )
441 .into_owned(),
442 },
443
444 Frame::PriorityUpdatePush {
445 prioritized_element_id,
446 priority_field_value,
447 } => Http3Frame::PriorityUpdate {
448 target_stream_type:
449 qlog::events::h3::H3PriorityTargetStreamType::Request,
450 prioritized_element_id: *prioritized_element_id,
451 priority_field_value: String::from_utf8_lossy(
452 priority_field_value,
453 )
454 .into_owned(),
455 },
456
457 Frame::Unknown { raw_type, payload } => Http3Frame::Unknown {
458 frame_type_value: *raw_type,
459 raw: Some(RawInfo {
460 data: None,
461 payload_length: Some(payload.len() as u64),
462 length: None,
463 }),
464 },
465 }
466 }
467}
468
469impl std::fmt::Debug for Frame {
470 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
471 match self {
472 Frame::Data { .. } => {
473 write!(f, "DATA")?;
474 },
475
476 Frame::Headers { .. } => {
477 write!(f, "HEADERS")?;
478 },
479
480 Frame::CancelPush { push_id } => {
481 write!(f, "CANCEL_PUSH push_id={push_id}")?;
482 },
483
484 Frame::Settings {
485 max_field_section_size,
486 qpack_max_table_capacity,
487 qpack_blocked_streams,
488 additional_settings,
489 raw,
490 ..
491 } => {
492 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:?}")?;
493 },
494
495 Frame::PushPromise {
496 push_id,
497 header_block,
498 } => {
499 write!(
500 f,
501 "PUSH_PROMISE push_id={} len={}",
502 push_id,
503 header_block.len()
504 )?;
505 },
506
507 Frame::GoAway { id } => {
508 write!(f, "GOAWAY id={id}")?;
509 },
510
511 Frame::MaxPushId { push_id } => {
512 write!(f, "MAX_PUSH_ID push_id={push_id}")?;
513 },
514
515 Frame::PriorityUpdateRequest {
516 prioritized_element_id,
517 priority_field_value,
518 } => {
519 write!(
520 f,
521 "PRIORITY_UPDATE request_stream_id={}, priority_field_len={}",
522 prioritized_element_id,
523 priority_field_value.len()
524 )?;
525 },
526
527 Frame::PriorityUpdatePush {
528 prioritized_element_id,
529 priority_field_value,
530 } => {
531 write!(
532 f,
533 "PRIORITY_UPDATE push_id={}, priority_field_len={}",
534 prioritized_element_id,
535 priority_field_value.len()
536 )?;
537 },
538
539 Frame::Unknown { raw_type, .. } => {
540 write!(f, "UNKNOWN raw_type={raw_type}",)?;
541 },
542 }
543
544 Ok(())
545 }
546}
547
548fn parse_settings_frame(
549 b: &mut octets::Octets, settings_length: usize,
550) -> Result<Frame> {
551 let mut max_field_section_size = None;
552 let mut qpack_max_table_capacity = None;
553 let mut qpack_blocked_streams = None;
554 let mut connect_protocol_enabled = None;
555 let mut h3_datagram = None;
556 let mut raw = Vec::new();
557 let mut additional_settings: Option<Vec<(u64, u64)>> = None;
558
559 if settings_length > MAX_SETTINGS_PAYLOAD_SIZE {
561 return Err(super::Error::ExcessiveLoad);
562 }
563
564 while b.off() < settings_length {
565 let identifier = b.get_varint()?;
566 let value = b.get_varint()?;
567
568 raw.push((identifier, value));
571
572 match identifier {
573 SETTINGS_QPACK_MAX_TABLE_CAPACITY => {
574 qpack_max_table_capacity = Some(value);
575 },
576
577 SETTINGS_MAX_FIELD_SECTION_SIZE => {
578 max_field_section_size = Some(value);
579 },
580
581 SETTINGS_QPACK_BLOCKED_STREAMS => {
582 qpack_blocked_streams = Some(value);
583 },
584
585 SETTINGS_ENABLE_CONNECT_PROTOCOL => {
586 if value > 1 {
587 return Err(super::Error::SettingsError);
588 }
589
590 connect_protocol_enabled = Some(value);
591 },
592
593 SETTINGS_H3_DATAGRAM_00 | SETTINGS_H3_DATAGRAM => {
594 if value > 1 {
595 return Err(super::Error::SettingsError);
596 }
597
598 h3_datagram = Some(value);
599 },
600
601 0x0 | 0x2 | 0x3 | 0x4 | 0x5 =>
603 return Err(super::Error::SettingsError),
604
605 _ => {
607 let s: &mut Vec<(u64, u64)> =
608 additional_settings.get_or_insert(vec![]);
609 s.push((identifier, value));
610 },
611 }
612 }
613
614 Ok(Frame::Settings {
615 max_field_section_size,
616 qpack_max_table_capacity,
617 qpack_blocked_streams,
618 connect_protocol_enabled,
619 h3_datagram,
620 grease: None,
621 raw: Some(raw),
622 additional_settings,
623 })
624}
625
626fn parse_push_promise(
627 payload_length: u64, b: &mut octets::Octets,
628) -> Result<Frame> {
629 let push_id = b.get_varint()?;
630 let header_block_length = payload_length - octets::varint_len(push_id) as u64;
631 let header_block = b.get_bytes(header_block_length as usize)?.to_vec();
632
633 Ok(Frame::PushPromise {
634 push_id,
635 header_block,
636 })
637}
638
639fn parse_priority_update(
640 frame_type: u64, payload_length: u64, b: &mut octets::Octets,
641) -> Result<Frame> {
642 let prioritized_element_id = b.get_varint()?;
643 let priority_field_value_length =
644 payload_length - octets::varint_len(prioritized_element_id) as u64;
645 let priority_field_value =
646 b.get_bytes(priority_field_value_length as usize)?.to_vec();
647
648 match frame_type {
649 PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID =>
650 Ok(Frame::PriorityUpdateRequest {
651 prioritized_element_id,
652 priority_field_value,
653 }),
654
655 PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID => Ok(Frame::PriorityUpdatePush {
656 prioritized_element_id,
657 priority_field_value,
658 }),
659
660 _ => unreachable!(),
661 }
662}
663
664#[cfg(test)]
665mod tests {
666 use super::*;
667
668 #[test]
669 fn data() {
670 let mut d = [42; 128];
671
672 let payload = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
673 let frame_payload_len = payload.len();
674 let frame_header_len = 2;
675
676 let frame = Frame::Data { payload };
677
678 let wire_len = {
679 let mut b = octets::OctetsMut::with_slice(&mut d);
680 frame.to_bytes(&mut b).unwrap()
681 };
682
683 assert_eq!(wire_len, frame_header_len + frame_payload_len);
684
685 assert_eq!(
686 Frame::from_bytes(
687 DATA_FRAME_TYPE_ID,
688 frame_payload_len as u64,
689 &d[frame_header_len..]
690 )
691 .unwrap(),
692 frame
693 );
694 }
695
696 #[test]
697 fn headers() {
698 let mut d = [42; 128];
699
700 let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
701 let frame_payload_len = header_block.len();
702 let frame_header_len = 2;
703
704 let frame = Frame::Headers { header_block };
705
706 let wire_len = {
707 let mut b = octets::OctetsMut::with_slice(&mut d);
708 frame.to_bytes(&mut b).unwrap()
709 };
710
711 assert_eq!(wire_len, frame_header_len + frame_payload_len);
712
713 assert_eq!(
714 Frame::from_bytes(
715 HEADERS_FRAME_TYPE_ID,
716 frame_payload_len as u64,
717 &d[frame_header_len..]
718 )
719 .unwrap(),
720 frame
721 );
722 }
723
724 #[test]
725 fn cancel_push() {
726 let mut d = [42; 128];
727
728 let frame = Frame::CancelPush { push_id: 0 };
729
730 let frame_payload_len = 1;
731 let frame_header_len = 2;
732
733 let wire_len = {
734 let mut b = octets::OctetsMut::with_slice(&mut d);
735 frame.to_bytes(&mut b).unwrap()
736 };
737
738 assert_eq!(wire_len, frame_header_len + frame_payload_len);
739
740 assert_eq!(
741 Frame::from_bytes(
742 CANCEL_PUSH_FRAME_TYPE_ID,
743 frame_payload_len as u64,
744 &d[frame_header_len..]
745 )
746 .unwrap(),
747 frame
748 );
749 }
750
751 #[test]
752 fn settings_all_no_grease() {
753 let mut d = [42; 128];
754
755 let raw_settings = vec![
756 (SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
757 (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
758 (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
759 (SETTINGS_ENABLE_CONNECT_PROTOCOL, 0),
760 (SETTINGS_H3_DATAGRAM_00, 0),
761 (SETTINGS_H3_DATAGRAM, 0),
762 ];
763
764 let frame = Frame::Settings {
765 max_field_section_size: Some(0),
766 qpack_max_table_capacity: Some(0),
767 qpack_blocked_streams: Some(0),
768 connect_protocol_enabled: Some(0),
769 h3_datagram: Some(0),
770 grease: None,
771 raw: Some(raw_settings),
772 additional_settings: None,
773 };
774
775 let frame_payload_len = 13;
776 let frame_header_len = 2;
777
778 let wire_len = {
779 let mut b = octets::OctetsMut::with_slice(&mut d);
780 frame.to_bytes(&mut b).unwrap()
781 };
782
783 assert_eq!(wire_len, frame_header_len + frame_payload_len);
784
785 assert_eq!(
786 Frame::from_bytes(
787 SETTINGS_FRAME_TYPE_ID,
788 frame_payload_len as u64,
789 &d[frame_header_len..]
790 )
791 .unwrap(),
792 frame
793 );
794 }
795
796 #[test]
797 fn settings_all_grease() {
798 let mut d = [42; 128];
799
800 let frame = Frame::Settings {
801 max_field_section_size: Some(0),
802 qpack_max_table_capacity: Some(0),
803 qpack_blocked_streams: Some(0),
804 connect_protocol_enabled: Some(0),
805 h3_datagram: Some(0),
806 grease: Some((33, 33)),
807 raw: Default::default(),
808 additional_settings: None,
809 };
810
811 let raw_settings = vec![
812 (SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
813 (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
814 (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
815 (SETTINGS_ENABLE_CONNECT_PROTOCOL, 0),
816 (SETTINGS_H3_DATAGRAM_00, 0),
817 (SETTINGS_H3_DATAGRAM, 0),
818 (33, 33),
819 ];
820
821 let frame_parsed = Frame::Settings {
824 max_field_section_size: Some(0),
825 qpack_max_table_capacity: Some(0),
826 qpack_blocked_streams: Some(0),
827 connect_protocol_enabled: Some(0),
828 h3_datagram: Some(0),
829 grease: None,
830 raw: Some(raw_settings),
831 additional_settings: Some(vec![(33, 33)]),
832 };
833
834 let frame_payload_len = 15;
835 let frame_header_len = 2;
836
837 let wire_len = {
838 let mut b = octets::OctetsMut::with_slice(&mut d);
839 frame.to_bytes(&mut b).unwrap()
840 };
841
842 assert_eq!(wire_len, frame_header_len + frame_payload_len);
843
844 assert_eq!(
845 Frame::from_bytes(
846 SETTINGS_FRAME_TYPE_ID,
847 frame_payload_len as u64,
848 &d[frame_header_len..]
849 )
850 .unwrap(),
851 frame_parsed
852 );
853 }
854
855 #[test]
856 fn settings_h3_only() {
857 let mut d = [42; 128];
858
859 let raw_settings = vec![(SETTINGS_MAX_FIELD_SECTION_SIZE, 1024)];
860
861 let frame = Frame::Settings {
862 max_field_section_size: Some(1024),
863 qpack_max_table_capacity: None,
864 qpack_blocked_streams: None,
865 connect_protocol_enabled: None,
866 h3_datagram: None,
867 grease: None,
868 raw: Some(raw_settings),
869 additional_settings: None,
870 };
871
872 let frame_payload_len = 3;
873 let frame_header_len = 2;
874
875 let wire_len = {
876 let mut b = octets::OctetsMut::with_slice(&mut d);
877 frame.to_bytes(&mut b).unwrap()
878 };
879
880 assert_eq!(wire_len, frame_header_len + frame_payload_len);
881
882 assert_eq!(
883 Frame::from_bytes(
884 SETTINGS_FRAME_TYPE_ID,
885 frame_payload_len as u64,
886 &d[frame_header_len..]
887 )
888 .unwrap(),
889 frame
890 );
891 }
892
893 #[test]
894 fn settings_h3_connect_protocol_enabled() {
895 let mut d = [42; 128];
896
897 let raw_settings = vec![(SETTINGS_ENABLE_CONNECT_PROTOCOL, 1)];
898
899 let frame = Frame::Settings {
900 max_field_section_size: None,
901 qpack_max_table_capacity: None,
902 qpack_blocked_streams: None,
903 connect_protocol_enabled: Some(1),
904 h3_datagram: None,
905 grease: None,
906 raw: Some(raw_settings),
907 additional_settings: None,
908 };
909
910 let frame_payload_len = 2;
911 let frame_header_len = 2;
912
913 let wire_len = {
914 let mut b = octets::OctetsMut::with_slice(&mut d);
915 frame.to_bytes(&mut b).unwrap()
916 };
917
918 assert_eq!(wire_len, frame_header_len + frame_payload_len);
919
920 assert_eq!(
921 Frame::from_bytes(
922 SETTINGS_FRAME_TYPE_ID,
923 frame_payload_len as u64,
924 &d[frame_header_len..]
925 )
926 .unwrap(),
927 frame
928 );
929 }
930
931 #[test]
932 fn settings_h3_connect_protocol_enabled_bad() {
933 let mut d = [42; 128];
934
935 let raw_settings = vec![(SETTINGS_ENABLE_CONNECT_PROTOCOL, 9)];
936
937 let frame = Frame::Settings {
938 max_field_section_size: None,
939 qpack_max_table_capacity: None,
940 qpack_blocked_streams: None,
941 connect_protocol_enabled: Some(9),
942 h3_datagram: None,
943 grease: None,
944 raw: Some(raw_settings),
945 additional_settings: None,
946 };
947
948 let frame_payload_len = 2;
949 let frame_header_len = 2;
950
951 let wire_len = {
952 let mut b = octets::OctetsMut::with_slice(&mut d);
953 frame.to_bytes(&mut b).unwrap()
954 };
955
956 assert_eq!(wire_len, frame_header_len + frame_payload_len);
957
958 assert_eq!(
959 Frame::from_bytes(
960 SETTINGS_FRAME_TYPE_ID,
961 frame_payload_len as u64,
962 &d[frame_header_len..]
963 ),
964 Err(crate::h3::Error::SettingsError)
965 );
966 }
967
968 #[test]
969 fn settings_h3_dgram_only() {
970 let mut d = [42; 128];
971
972 let raw_settings =
973 vec![(SETTINGS_H3_DATAGRAM_00, 1), (SETTINGS_H3_DATAGRAM, 1)];
974
975 let frame = Frame::Settings {
976 max_field_section_size: None,
977 qpack_max_table_capacity: None,
978 qpack_blocked_streams: None,
979 connect_protocol_enabled: None,
980 h3_datagram: Some(1),
981 grease: None,
982 raw: Some(raw_settings),
983 additional_settings: None,
984 };
985
986 let frame_payload_len = 5;
987 let frame_header_len = 2;
988
989 let wire_len = {
990 let mut b = octets::OctetsMut::with_slice(&mut d);
991 frame.to_bytes(&mut b).unwrap()
992 };
993
994 assert_eq!(wire_len, frame_header_len + frame_payload_len);
995
996 assert_eq!(
997 Frame::from_bytes(
998 SETTINGS_FRAME_TYPE_ID,
999 frame_payload_len as u64,
1000 &d[frame_header_len..]
1001 )
1002 .unwrap(),
1003 frame
1004 );
1005 }
1006
1007 #[test]
1008 fn settings_h3_dgram_bad() {
1009 let mut d = [42; 128];
1010
1011 let frame = Frame::Settings {
1012 max_field_section_size: None,
1013 qpack_max_table_capacity: None,
1014 qpack_blocked_streams: None,
1015 connect_protocol_enabled: None,
1016 h3_datagram: Some(5),
1017 grease: None,
1018 raw: Default::default(),
1019 additional_settings: None,
1020 };
1021
1022 let frame_payload_len = 5;
1023 let frame_header_len = 2;
1024
1025 let wire_len = {
1026 let mut b = octets::OctetsMut::with_slice(&mut d);
1027 frame.to_bytes(&mut b).unwrap()
1028 };
1029
1030 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1031
1032 assert_eq!(
1033 Frame::from_bytes(
1034 SETTINGS_FRAME_TYPE_ID,
1035 frame_payload_len as u64,
1036 &d[frame_header_len..]
1037 ),
1038 Err(crate::h3::Error::SettingsError)
1039 );
1040 }
1041
1042 #[test]
1043 fn settings_qpack_only() {
1044 let mut d = [42; 128];
1045
1046 let raw_settings = vec![
1047 (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
1048 (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
1049 ];
1050
1051 let frame = Frame::Settings {
1052 max_field_section_size: None,
1053 qpack_max_table_capacity: Some(0),
1054 qpack_blocked_streams: Some(0),
1055 connect_protocol_enabled: None,
1056 h3_datagram: None,
1057 grease: None,
1058 raw: Some(raw_settings),
1059 additional_settings: None,
1060 };
1061
1062 let frame_payload_len = 4;
1063 let frame_header_len = 2;
1064
1065 let wire_len = {
1066 let mut b = octets::OctetsMut::with_slice(&mut d);
1067 frame.to_bytes(&mut b).unwrap()
1068 };
1069
1070 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1071
1072 assert_eq!(
1073 Frame::from_bytes(
1074 SETTINGS_FRAME_TYPE_ID,
1075 frame_payload_len as u64,
1076 &d[frame_header_len..]
1077 )
1078 .unwrap(),
1079 frame
1080 );
1081 }
1082
1083 #[test]
1084 fn settings_h2_prohibited() {
1085 let frame_payload_len = 2u64;
1089 let frame_header_len = 2;
1090 let mut d = [
1091 SETTINGS_FRAME_TYPE_ID as u8,
1092 frame_payload_len as u8,
1093 0x0,
1094 1,
1095 ];
1096
1097 assert_eq!(
1098 Frame::from_bytes(
1099 SETTINGS_FRAME_TYPE_ID,
1100 frame_payload_len,
1101 &d[frame_header_len..]
1102 ),
1103 Err(crate::h3::Error::SettingsError)
1104 );
1105
1106 d[frame_header_len] = 0x2;
1107
1108 assert_eq!(
1109 Frame::from_bytes(
1110 SETTINGS_FRAME_TYPE_ID,
1111 frame_payload_len,
1112 &d[frame_header_len..]
1113 ),
1114 Err(crate::h3::Error::SettingsError)
1115 );
1116
1117 d[frame_header_len] = 0x3;
1118
1119 assert_eq!(
1120 Frame::from_bytes(
1121 SETTINGS_FRAME_TYPE_ID,
1122 frame_payload_len,
1123 &d[frame_header_len..]
1124 ),
1125 Err(crate::h3::Error::SettingsError)
1126 );
1127
1128 d[frame_header_len] = 0x4;
1129
1130 assert_eq!(
1131 Frame::from_bytes(
1132 SETTINGS_FRAME_TYPE_ID,
1133 frame_payload_len,
1134 &d[frame_header_len..]
1135 ),
1136 Err(crate::h3::Error::SettingsError)
1137 );
1138
1139 d[frame_header_len] = 0x5;
1140
1141 assert_eq!(
1142 Frame::from_bytes(
1143 SETTINGS_FRAME_TYPE_ID,
1144 frame_payload_len,
1145 &d[frame_header_len..]
1146 ),
1147 Err(crate::h3::Error::SettingsError)
1148 );
1149 }
1150
1151 #[test]
1152 fn settings_too_big() {
1153 let frame_payload_len = MAX_SETTINGS_PAYLOAD_SIZE + 1;
1158 let frame_header_len = 2;
1159 let d = [
1160 SETTINGS_FRAME_TYPE_ID as u8,
1161 frame_payload_len as u8,
1162 0x1,
1163 1,
1164 ];
1165
1166 assert_eq!(
1167 Frame::from_bytes(
1168 SETTINGS_FRAME_TYPE_ID,
1169 frame_payload_len as u64,
1170 &d[frame_header_len..]
1171 ),
1172 Err(crate::h3::Error::ExcessiveLoad)
1173 );
1174 }
1175
1176 #[test]
1177 fn push_promise() {
1178 let mut d = [42; 128];
1179
1180 let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
1181 let frame_payload_len = 1 + header_block.len();
1182 let frame_header_len = 2;
1183
1184 let frame = Frame::PushPromise {
1185 push_id: 0,
1186 header_block,
1187 };
1188
1189 let wire_len = {
1190 let mut b = octets::OctetsMut::with_slice(&mut d);
1191 frame.to_bytes(&mut b).unwrap()
1192 };
1193
1194 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1195
1196 assert_eq!(
1197 Frame::from_bytes(
1198 PUSH_PROMISE_FRAME_TYPE_ID,
1199 frame_payload_len as u64,
1200 &d[frame_header_len..]
1201 )
1202 .unwrap(),
1203 frame
1204 );
1205 }
1206
1207 #[test]
1208 fn goaway() {
1209 let mut d = [42; 128];
1210
1211 let frame = Frame::GoAway { id: 32 };
1212
1213 let frame_payload_len = 1;
1214 let frame_header_len = 2;
1215
1216 let wire_len = {
1217 let mut b = octets::OctetsMut::with_slice(&mut d);
1218 frame.to_bytes(&mut b).unwrap()
1219 };
1220
1221 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1222
1223 assert_eq!(
1224 Frame::from_bytes(
1225 GOAWAY_FRAME_TYPE_ID,
1226 frame_payload_len as u64,
1227 &d[frame_header_len..]
1228 )
1229 .unwrap(),
1230 frame
1231 );
1232 }
1233
1234 #[test]
1235 fn max_push_id() {
1236 let mut d = [42; 128];
1237
1238 let frame = Frame::MaxPushId { push_id: 128 };
1239
1240 let frame_payload_len = 2;
1241 let frame_header_len = 2;
1242
1243 let wire_len = {
1244 let mut b = octets::OctetsMut::with_slice(&mut d);
1245 frame.to_bytes(&mut b).unwrap()
1246 };
1247
1248 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1249
1250 assert_eq!(
1251 Frame::from_bytes(
1252 MAX_PUSH_FRAME_TYPE_ID,
1253 frame_payload_len as u64,
1254 &d[frame_header_len..]
1255 )
1256 .unwrap(),
1257 frame
1258 );
1259 }
1260
1261 #[test]
1262 fn priority_update_request() {
1263 let mut d = [42; 128];
1264
1265 let prioritized_element_id = 4;
1266 let priority_field_value = b"abcdefghijklm".to_vec();
1267 let frame_payload_len = 1 + priority_field_value.len();
1268 let frame_header_len = 5;
1269
1270 let frame = Frame::PriorityUpdateRequest {
1271 prioritized_element_id,
1272 priority_field_value,
1273 };
1274
1275 let wire_len = {
1276 let mut b = octets::OctetsMut::with_slice(&mut d);
1277 frame.to_bytes(&mut b).unwrap()
1278 };
1279
1280 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1281
1282 assert_eq!(
1283 Frame::from_bytes(
1284 PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID,
1285 frame_payload_len as u64,
1286 &d[frame_header_len..]
1287 )
1288 .unwrap(),
1289 frame
1290 );
1291 }
1292
1293 #[test]
1294 fn priority_update_push() {
1295 let mut d = [42; 128];
1296
1297 let prioritized_element_id = 6;
1298 let priority_field_value = b"abcdefghijklm".to_vec();
1299 let frame_payload_len = 1 + priority_field_value.len();
1300 let frame_header_len = 5;
1301
1302 let frame = Frame::PriorityUpdatePush {
1303 prioritized_element_id,
1304 priority_field_value,
1305 };
1306
1307 let wire_len = {
1308 let mut b = octets::OctetsMut::with_slice(&mut d);
1309 frame.to_bytes(&mut b).unwrap()
1310 };
1311
1312 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1313
1314 assert_eq!(
1315 Frame::from_bytes(
1316 PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID,
1317 frame_payload_len as u64,
1318 &d[frame_header_len..]
1319 )
1320 .unwrap(),
1321 frame
1322 );
1323 }
1324
1325 #[test]
1326 fn unknown_type() {
1327 let d = [42; 12];
1328
1329 assert_eq!(
1330 Frame::from_bytes(255, 12, &d[..]),
1331 Ok(Frame::Unknown {
1332 raw_type: 255,
1333 payload: vec![42; 12]
1334 })
1335 );
1336 }
1337}