1 // Copyright (C) 2019, Cloudflare, Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 //
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 use super::Result;
28
29 #[cfg(feature = "qlog")]
30 use qlog::events::h3::Http3Frame;
31
32 pub const DATA_FRAME_TYPE_ID: u64 = 0x0;
33 pub const HEADERS_FRAME_TYPE_ID: u64 = 0x1;
34 pub const CANCEL_PUSH_FRAME_TYPE_ID: u64 = 0x3;
35 pub const SETTINGS_FRAME_TYPE_ID: u64 = 0x4;
36 pub const PUSH_PROMISE_FRAME_TYPE_ID: u64 = 0x5;
37 pub const GOAWAY_FRAME_TYPE_ID: u64 = 0x6;
38 pub const MAX_PUSH_FRAME_TYPE_ID: u64 = 0xD;
39 pub const PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID: u64 = 0xF0700;
40 pub const PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID: u64 = 0xF0701;
41
42 pub const SETTINGS_QPACK_MAX_TABLE_CAPACITY: u64 = 0x1;
43 pub const SETTINGS_MAX_FIELD_SECTION_SIZE: u64 = 0x6;
44 pub const SETTINGS_QPACK_BLOCKED_STREAMS: u64 = 0x7;
45 pub const SETTINGS_ENABLE_CONNECT_PROTOCOL: u64 = 0x8;
46 pub const SETTINGS_H3_DATAGRAM: u64 = 0x276;
47
48 // Permit between 16 maximally-encoded and 128 minimally-encoded SETTINGS.
49 const MAX_SETTINGS_PAYLOAD_SIZE: usize = 256;
50
51 #[derive(Clone, PartialEq, Eq)]
52 pub enum Frame {
53 Data {
54 payload: Vec<u8>,
55 },
56
57 Headers {
58 header_block: Vec<u8>,
59 },
60
61 CancelPush {
62 push_id: u64,
63 },
64
65 Settings {
66 max_field_section_size: Option<u64>,
67 qpack_max_table_capacity: Option<u64>,
68 qpack_blocked_streams: Option<u64>,
69 connect_protocol_enabled: Option<u64>,
70 h3_datagram: Option<u64>,
71 grease: Option<(u64, u64)>,
72 raw: Option<Vec<(u64, u64)>>,
73 },
74
75 PushPromise {
76 push_id: u64,
77 header_block: Vec<u8>,
78 },
79
80 GoAway {
81 id: u64,
82 },
83
84 MaxPushId {
85 push_id: u64,
86 },
87
88 PriorityUpdateRequest {
89 prioritized_element_id: u64,
90 priority_field_value: Vec<u8>,
91 },
92
93 PriorityUpdatePush {
94 prioritized_element_id: u64,
95 priority_field_value: Vec<u8>,
96 },
97
98 Unknown {
99 raw_type: u64,
100 payload_length: u64,
101 },
102 }
103
104 impl Frame {
from_bytes( frame_type: u64, payload_length: u64, bytes: &[u8], ) -> Result<Frame>105 pub fn from_bytes(
106 frame_type: u64, payload_length: u64, bytes: &[u8],
107 ) -> Result<Frame> {
108 let mut b = octets::Octets::with_slice(bytes);
109
110 // TODO: handling of 0-length frames
111 let frame = match frame_type {
112 DATA_FRAME_TYPE_ID => Frame::Data {
113 payload: b.get_bytes(payload_length as usize)?.to_vec(),
114 },
115
116 HEADERS_FRAME_TYPE_ID => Frame::Headers {
117 header_block: b.get_bytes(payload_length as usize)?.to_vec(),
118 },
119
120 CANCEL_PUSH_FRAME_TYPE_ID => Frame::CancelPush {
121 push_id: b.get_varint()?,
122 },
123
124 SETTINGS_FRAME_TYPE_ID =>
125 parse_settings_frame(&mut b, payload_length as usize)?,
126
127 PUSH_PROMISE_FRAME_TYPE_ID =>
128 parse_push_promise(payload_length, &mut b)?,
129
130 GOAWAY_FRAME_TYPE_ID => Frame::GoAway {
131 id: b.get_varint()?,
132 },
133
134 MAX_PUSH_FRAME_TYPE_ID => Frame::MaxPushId {
135 push_id: b.get_varint()?,
136 },
137
138 PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID |
139 PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID =>
140 parse_priority_update(frame_type, payload_length, &mut b)?,
141
142 _ => Frame::Unknown {
143 raw_type: frame_type,
144 payload_length,
145 },
146 };
147
148 Ok(frame)
149 }
150
to_bytes(&self, b: &mut octets::OctetsMut) -> Result<usize>151 pub fn to_bytes(&self, b: &mut octets::OctetsMut) -> Result<usize> {
152 let before = b.cap();
153
154 match self {
155 Frame::Data { payload } => {
156 b.put_varint(DATA_FRAME_TYPE_ID)?;
157 b.put_varint(payload.len() as u64)?;
158
159 b.put_bytes(payload.as_ref())?;
160 },
161
162 Frame::Headers { header_block } => {
163 b.put_varint(HEADERS_FRAME_TYPE_ID)?;
164 b.put_varint(header_block.len() as u64)?;
165
166 b.put_bytes(header_block.as_ref())?;
167 },
168
169 Frame::CancelPush { push_id } => {
170 b.put_varint(CANCEL_PUSH_FRAME_TYPE_ID)?;
171 b.put_varint(octets::varint_len(*push_id) as u64)?;
172
173 b.put_varint(*push_id)?;
174 },
175
176 Frame::Settings {
177 max_field_section_size,
178 qpack_max_table_capacity,
179 qpack_blocked_streams,
180 connect_protocol_enabled,
181 h3_datagram,
182 grease,
183 ..
184 } => {
185 let mut len = 0;
186
187 if let Some(val) = max_field_section_size {
188 len += octets::varint_len(SETTINGS_MAX_FIELD_SECTION_SIZE);
189 len += octets::varint_len(*val);
190 }
191
192 if let Some(val) = qpack_max_table_capacity {
193 len += octets::varint_len(SETTINGS_QPACK_MAX_TABLE_CAPACITY);
194 len += octets::varint_len(*val);
195 }
196
197 if let Some(val) = qpack_blocked_streams {
198 len += octets::varint_len(SETTINGS_QPACK_BLOCKED_STREAMS);
199 len += octets::varint_len(*val);
200 }
201
202 if let Some(val) = connect_protocol_enabled {
203 len += octets::varint_len(SETTINGS_ENABLE_CONNECT_PROTOCOL);
204 len += octets::varint_len(*val);
205 }
206
207 if let Some(val) = h3_datagram {
208 len += octets::varint_len(SETTINGS_H3_DATAGRAM);
209 len += octets::varint_len(*val);
210 }
211
212 if let Some(val) = grease {
213 len += octets::varint_len(val.0);
214 len += octets::varint_len(val.1);
215 }
216
217 b.put_varint(SETTINGS_FRAME_TYPE_ID)?;
218 b.put_varint(len as u64)?;
219
220 if let Some(val) = max_field_section_size {
221 b.put_varint(SETTINGS_MAX_FIELD_SECTION_SIZE)?;
222 b.put_varint(*val)?;
223 }
224
225 if let Some(val) = qpack_max_table_capacity {
226 b.put_varint(SETTINGS_QPACK_MAX_TABLE_CAPACITY)?;
227 b.put_varint(*val)?;
228 }
229
230 if let Some(val) = qpack_blocked_streams {
231 b.put_varint(SETTINGS_QPACK_BLOCKED_STREAMS)?;
232 b.put_varint(*val)?;
233 }
234
235 if let Some(val) = connect_protocol_enabled {
236 b.put_varint(SETTINGS_ENABLE_CONNECT_PROTOCOL)?;
237 b.put_varint(*val)?;
238 }
239
240 if let Some(val) = h3_datagram {
241 b.put_varint(SETTINGS_H3_DATAGRAM)?;
242 b.put_varint(*val)?;
243 }
244
245 if let Some(val) = grease {
246 b.put_varint(val.0)?;
247 b.put_varint(val.1)?;
248 }
249 },
250
251 Frame::PushPromise {
252 push_id,
253 header_block,
254 } => {
255 let len = octets::varint_len(*push_id) + header_block.len();
256 b.put_varint(PUSH_PROMISE_FRAME_TYPE_ID)?;
257 b.put_varint(len as u64)?;
258
259 b.put_varint(*push_id)?;
260 b.put_bytes(header_block.as_ref())?;
261 },
262
263 Frame::GoAway { id } => {
264 b.put_varint(GOAWAY_FRAME_TYPE_ID)?;
265 b.put_varint(octets::varint_len(*id) as u64)?;
266
267 b.put_varint(*id)?;
268 },
269
270 Frame::MaxPushId { push_id } => {
271 b.put_varint(MAX_PUSH_FRAME_TYPE_ID)?;
272 b.put_varint(octets::varint_len(*push_id) as u64)?;
273
274 b.put_varint(*push_id)?;
275 },
276
277 Frame::PriorityUpdateRequest {
278 prioritized_element_id,
279 priority_field_value,
280 } => {
281 let len = octets::varint_len(*prioritized_element_id) +
282 priority_field_value.len();
283
284 b.put_varint(PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID)?;
285 b.put_varint(len as u64)?;
286
287 b.put_varint(*prioritized_element_id)?;
288 b.put_bytes(priority_field_value)?;
289 },
290
291 Frame::PriorityUpdatePush {
292 prioritized_element_id,
293 priority_field_value,
294 } => {
295 let len = octets::varint_len(*prioritized_element_id) +
296 priority_field_value.len();
297
298 b.put_varint(PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID)?;
299 b.put_varint(len as u64)?;
300
301 b.put_varint(*prioritized_element_id)?;
302 b.put_bytes(priority_field_value)?;
303 },
304
305 Frame::Unknown { .. } => unreachable!(),
306 }
307
308 Ok(before - b.cap())
309 }
310
311 #[cfg(feature = "qlog")]
to_qlog(&self) -> Http3Frame312 pub fn to_qlog(&self) -> Http3Frame {
313 use qlog::events::RawInfo;
314
315 match self {
316 Frame::Data { .. } => Http3Frame::Data { raw: None },
317
318 // Qlog expects the `headers` to be represented as an array of
319 // name:value pairs. At this stage, we only have the qpack block, so
320 // populate the field with an empty vec.
321 Frame::Headers { .. } => Http3Frame::Headers { headers: vec![] },
322
323 Frame::CancelPush { push_id } =>
324 Http3Frame::CancelPush { push_id: *push_id },
325
326 Frame::Settings {
327 max_field_section_size,
328 qpack_max_table_capacity,
329 qpack_blocked_streams,
330 connect_protocol_enabled,
331 h3_datagram,
332 grease,
333 ..
334 } => {
335 let mut settings = vec![];
336
337 if let Some(v) = max_field_section_size {
338 settings.push(qlog::events::h3::Setting {
339 name: "MAX_FIELD_SECTION_SIZE".to_string(),
340 value: *v,
341 });
342 }
343
344 if let Some(v) = qpack_max_table_capacity {
345 settings.push(qlog::events::h3::Setting {
346 name: "QPACK_MAX_TABLE_CAPACITY".to_string(),
347 value: *v,
348 });
349 }
350
351 if let Some(v) = qpack_blocked_streams {
352 settings.push(qlog::events::h3::Setting {
353 name: "QPACK_BLOCKED_STREAMS".to_string(),
354 value: *v,
355 });
356 }
357
358 if let Some(v) = connect_protocol_enabled {
359 settings.push(qlog::events::h3::Setting {
360 name: "SETTINGS_ENABLE_CONNECT_PROTOCOL".to_string(),
361 value: *v,
362 });
363 }
364
365 if let Some(v) = h3_datagram {
366 settings.push(qlog::events::h3::Setting {
367 name: "H3_DATAGRAM".to_string(),
368 value: *v,
369 });
370 }
371
372 if let Some((k, v)) = grease {
373 settings.push(qlog::events::h3::Setting {
374 name: k.to_string(),
375 value: *v,
376 });
377 }
378
379 qlog::events::h3::Http3Frame::Settings { settings }
380 },
381
382 // Qlog expects the `headers` to be represented as an array of
383 // name:value pairs. At this stage, we only have the qpack block, so
384 // populate the field with an empty vec.
385 Frame::PushPromise { push_id, .. } => Http3Frame::PushPromise {
386 push_id: *push_id,
387 headers: vec![],
388 },
389
390 Frame::GoAway { id } => Http3Frame::Goaway { id: *id },
391
392 Frame::MaxPushId { push_id } =>
393 Http3Frame::MaxPushId { push_id: *push_id },
394
395 Frame::PriorityUpdateRequest {
396 prioritized_element_id,
397 priority_field_value,
398 } => Http3Frame::PriorityUpdate {
399 target_stream_type:
400 qlog::events::h3::H3PriorityTargetStreamType::Request,
401 prioritized_element_id: *prioritized_element_id,
402 priority_field_value: String::from_utf8_lossy(
403 priority_field_value,
404 )
405 .into_owned(),
406 },
407
408 Frame::PriorityUpdatePush {
409 prioritized_element_id,
410 priority_field_value,
411 } => Http3Frame::PriorityUpdate {
412 target_stream_type:
413 qlog::events::h3::H3PriorityTargetStreamType::Request,
414 prioritized_element_id: *prioritized_element_id,
415 priority_field_value: String::from_utf8_lossy(
416 priority_field_value,
417 )
418 .into_owned(),
419 },
420
421 Frame::Unknown {
422 raw_type,
423 payload_length,
424 } => Http3Frame::Unknown {
425 frame_type_value: *raw_type,
426 raw: Some(RawInfo {
427 data: None,
428 payload_length: Some(*payload_length),
429 length: None,
430 }),
431 },
432 }
433 }
434 }
435
436 impl std::fmt::Debug for Frame {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result437 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
438 match self {
439 Frame::Data { .. } => {
440 write!(f, "DATA")?;
441 },
442
443 Frame::Headers { .. } => {
444 write!(f, "HEADERS")?;
445 },
446
447 Frame::CancelPush { push_id } => {
448 write!(f, "CANCEL_PUSH push_id={push_id}")?;
449 },
450
451 Frame::Settings {
452 max_field_section_size,
453 qpack_max_table_capacity,
454 qpack_blocked_streams,
455 raw,
456 ..
457 } => {
458 write!(f, "SETTINGS max_field_section={max_field_section_size:?}, qpack_max_table={qpack_max_table_capacity:?}, qpack_blocked={qpack_blocked_streams:?} raw={raw:?}")?;
459 },
460
461 Frame::PushPromise {
462 push_id,
463 header_block,
464 } => {
465 write!(
466 f,
467 "PUSH_PROMISE push_id={} len={}",
468 push_id,
469 header_block.len()
470 )?;
471 },
472
473 Frame::GoAway { id } => {
474 write!(f, "GOAWAY id={id}")?;
475 },
476
477 Frame::MaxPushId { push_id } => {
478 write!(f, "MAX_PUSH_ID push_id={push_id}")?;
479 },
480
481 Frame::PriorityUpdateRequest {
482 prioritized_element_id,
483 priority_field_value,
484 } => {
485 write!(
486 f,
487 "PRIORITY_UPDATE request_stream_id={}, priority_field_len={}",
488 prioritized_element_id,
489 priority_field_value.len()
490 )?;
491 },
492
493 Frame::PriorityUpdatePush {
494 prioritized_element_id,
495 priority_field_value,
496 } => {
497 write!(
498 f,
499 "PRIORITY_UPDATE push_id={}, priority_field_len={}",
500 prioritized_element_id,
501 priority_field_value.len()
502 )?;
503 },
504
505 Frame::Unknown { raw_type, .. } => {
506 write!(f, "UNKNOWN raw_type={raw_type}",)?;
507 },
508 }
509
510 Ok(())
511 }
512 }
513
parse_settings_frame( b: &mut octets::Octets, settings_length: usize, ) -> Result<Frame>514 fn parse_settings_frame(
515 b: &mut octets::Octets, settings_length: usize,
516 ) -> Result<Frame> {
517 let mut max_field_section_size = None;
518 let mut qpack_max_table_capacity = None;
519 let mut qpack_blocked_streams = None;
520 let mut connect_protocol_enabled = None;
521 let mut h3_datagram = None;
522 let mut raw = Vec::new();
523
524 // Reject SETTINGS frames that are too long.
525 if settings_length > MAX_SETTINGS_PAYLOAD_SIZE {
526 return Err(super::Error::ExcessiveLoad);
527 }
528
529 while b.off() < settings_length {
530 let identifier = b.get_varint()?;
531 let value = b.get_varint()?;
532
533 // MAX_SETTINGS_PAYLOAD_SIZE protects us from storing too many raw
534 // settings.
535 raw.push((identifier, value));
536
537 match identifier {
538 SETTINGS_QPACK_MAX_TABLE_CAPACITY => {
539 qpack_max_table_capacity = Some(value);
540 },
541
542 SETTINGS_MAX_FIELD_SECTION_SIZE => {
543 max_field_section_size = Some(value);
544 },
545
546 SETTINGS_QPACK_BLOCKED_STREAMS => {
547 qpack_blocked_streams = Some(value);
548 },
549
550 SETTINGS_ENABLE_CONNECT_PROTOCOL => {
551 if value > 1 {
552 return Err(super::Error::SettingsError);
553 }
554
555 connect_protocol_enabled = Some(value);
556 },
557
558 SETTINGS_H3_DATAGRAM => {
559 if value > 1 {
560 return Err(super::Error::SettingsError);
561 }
562
563 h3_datagram = Some(value);
564 },
565
566 // Reserved values overlap with HTTP/2 and MUST be rejected
567 0x0 | 0x2 | 0x3 | 0x4 | 0x5 =>
568 return Err(super::Error::SettingsError),
569
570 // Unknown Settings parameters must be ignored.
571 _ => (),
572 }
573 }
574
575 Ok(Frame::Settings {
576 max_field_section_size,
577 qpack_max_table_capacity,
578 qpack_blocked_streams,
579 connect_protocol_enabled,
580 h3_datagram,
581 grease: None,
582 raw: Some(raw),
583 })
584 }
585
parse_push_promise( payload_length: u64, b: &mut octets::Octets, ) -> Result<Frame>586 fn parse_push_promise(
587 payload_length: u64, b: &mut octets::Octets,
588 ) -> Result<Frame> {
589 let push_id = b.get_varint()?;
590 let header_block_length = payload_length - octets::varint_len(push_id) as u64;
591 let header_block = b.get_bytes(header_block_length as usize)?.to_vec();
592
593 Ok(Frame::PushPromise {
594 push_id,
595 header_block,
596 })
597 }
598
parse_priority_update( frame_type: u64, payload_length: u64, b: &mut octets::Octets, ) -> Result<Frame>599 fn parse_priority_update(
600 frame_type: u64, payload_length: u64, b: &mut octets::Octets,
601 ) -> Result<Frame> {
602 let prioritized_element_id = b.get_varint()?;
603 let priority_field_value_length =
604 payload_length - octets::varint_len(prioritized_element_id) as u64;
605 let priority_field_value =
606 b.get_bytes(priority_field_value_length as usize)?.to_vec();
607
608 match frame_type {
609 PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID =>
610 Ok(Frame::PriorityUpdateRequest {
611 prioritized_element_id,
612 priority_field_value,
613 }),
614
615 PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID => Ok(Frame::PriorityUpdatePush {
616 prioritized_element_id,
617 priority_field_value,
618 }),
619
620 _ => unreachable!(),
621 }
622 }
623
624 #[cfg(test)]
625 mod tests {
626 use super::*;
627
628 #[test]
data()629 fn data() {
630 let mut d = [42; 128];
631
632 let payload = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
633 let frame_payload_len = payload.len();
634 let frame_header_len = 2;
635
636 let frame = Frame::Data { payload };
637
638 let wire_len = {
639 let mut b = octets::OctetsMut::with_slice(&mut d);
640 frame.to_bytes(&mut b).unwrap()
641 };
642
643 assert_eq!(wire_len, frame_header_len + frame_payload_len);
644
645 assert_eq!(
646 Frame::from_bytes(
647 DATA_FRAME_TYPE_ID,
648 frame_payload_len as u64,
649 &d[frame_header_len..]
650 )
651 .unwrap(),
652 frame
653 );
654 }
655
656 #[test]
headers()657 fn headers() {
658 let mut d = [42; 128];
659
660 let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
661 let frame_payload_len = header_block.len();
662 let frame_header_len = 2;
663
664 let frame = Frame::Headers { header_block };
665
666 let wire_len = {
667 let mut b = octets::OctetsMut::with_slice(&mut d);
668 frame.to_bytes(&mut b).unwrap()
669 };
670
671 assert_eq!(wire_len, frame_header_len + frame_payload_len);
672
673 assert_eq!(
674 Frame::from_bytes(
675 HEADERS_FRAME_TYPE_ID,
676 frame_payload_len as u64,
677 &d[frame_header_len..]
678 )
679 .unwrap(),
680 frame
681 );
682 }
683
684 #[test]
cancel_push()685 fn cancel_push() {
686 let mut d = [42; 128];
687
688 let frame = Frame::CancelPush { push_id: 0 };
689
690 let frame_payload_len = 1;
691 let frame_header_len = 2;
692
693 let wire_len = {
694 let mut b = octets::OctetsMut::with_slice(&mut d);
695 frame.to_bytes(&mut b).unwrap()
696 };
697
698 assert_eq!(wire_len, frame_header_len + frame_payload_len);
699
700 assert_eq!(
701 Frame::from_bytes(
702 CANCEL_PUSH_FRAME_TYPE_ID,
703 frame_payload_len as u64,
704 &d[frame_header_len..]
705 )
706 .unwrap(),
707 frame
708 );
709 }
710
711 #[test]
settings_all_no_grease()712 fn settings_all_no_grease() {
713 let mut d = [42; 128];
714
715 let raw_settings = vec![
716 (SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
717 (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
718 (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
719 (SETTINGS_ENABLE_CONNECT_PROTOCOL, 0),
720 (SETTINGS_H3_DATAGRAM, 0),
721 ];
722
723 let frame = Frame::Settings {
724 max_field_section_size: Some(0),
725 qpack_max_table_capacity: Some(0),
726 qpack_blocked_streams: Some(0),
727 connect_protocol_enabled: Some(0),
728 h3_datagram: Some(0),
729 grease: None,
730 raw: Some(raw_settings),
731 };
732
733 let frame_payload_len = 11;
734 let frame_header_len = 2;
735
736 let wire_len = {
737 let mut b = octets::OctetsMut::with_slice(&mut d);
738 frame.to_bytes(&mut b).unwrap()
739 };
740
741 assert_eq!(wire_len, frame_header_len + frame_payload_len);
742
743 assert_eq!(
744 Frame::from_bytes(
745 SETTINGS_FRAME_TYPE_ID,
746 frame_payload_len as u64,
747 &d[frame_header_len..]
748 )
749 .unwrap(),
750 frame
751 );
752 }
753
754 #[test]
settings_all_grease()755 fn settings_all_grease() {
756 let mut d = [42; 128];
757
758 let frame = Frame::Settings {
759 max_field_section_size: Some(0),
760 qpack_max_table_capacity: Some(0),
761 qpack_blocked_streams: Some(0),
762 connect_protocol_enabled: Some(0),
763 h3_datagram: Some(0),
764 grease: Some((33, 33)),
765 raw: Default::default(),
766 };
767
768 let raw_settings = vec![
769 (SETTINGS_MAX_FIELD_SECTION_SIZE, 0),
770 (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
771 (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
772 (SETTINGS_ENABLE_CONNECT_PROTOCOL, 0),
773 (SETTINGS_H3_DATAGRAM, 0),
774 (33, 33),
775 ];
776
777 // Frame parsing will not populate GREASE property but will be in the
778 // raw info.
779 let frame_parsed = Frame::Settings {
780 max_field_section_size: Some(0),
781 qpack_max_table_capacity: Some(0),
782 qpack_blocked_streams: Some(0),
783 connect_protocol_enabled: Some(0),
784 h3_datagram: Some(0),
785 grease: None,
786 raw: Some(raw_settings),
787 };
788
789 let frame_payload_len = 13;
790 let frame_header_len = 2;
791
792 let wire_len = {
793 let mut b = octets::OctetsMut::with_slice(&mut d);
794 frame.to_bytes(&mut b).unwrap()
795 };
796
797 assert_eq!(wire_len, frame_header_len + frame_payload_len);
798
799 assert_eq!(
800 Frame::from_bytes(
801 SETTINGS_FRAME_TYPE_ID,
802 frame_payload_len as u64,
803 &d[frame_header_len..]
804 )
805 .unwrap(),
806 frame_parsed
807 );
808 }
809
810 #[test]
settings_h3_only()811 fn settings_h3_only() {
812 let mut d = [42; 128];
813
814 let raw_settings = vec![(SETTINGS_MAX_FIELD_SECTION_SIZE, 1024)];
815
816 let frame = Frame::Settings {
817 max_field_section_size: Some(1024),
818 qpack_max_table_capacity: None,
819 qpack_blocked_streams: None,
820 connect_protocol_enabled: None,
821 h3_datagram: None,
822 grease: None,
823 raw: Some(raw_settings),
824 };
825
826 let frame_payload_len = 3;
827 let frame_header_len = 2;
828
829 let wire_len = {
830 let mut b = octets::OctetsMut::with_slice(&mut d);
831 frame.to_bytes(&mut b).unwrap()
832 };
833
834 assert_eq!(wire_len, frame_header_len + frame_payload_len);
835
836 assert_eq!(
837 Frame::from_bytes(
838 SETTINGS_FRAME_TYPE_ID,
839 frame_payload_len as u64,
840 &d[frame_header_len..]
841 )
842 .unwrap(),
843 frame
844 );
845 }
846
847 #[test]
settings_h3_connect_protocol_enabled()848 fn settings_h3_connect_protocol_enabled() {
849 let mut d = [42; 128];
850
851 let raw_settings = vec![(SETTINGS_ENABLE_CONNECT_PROTOCOL, 1)];
852
853 let frame = Frame::Settings {
854 max_field_section_size: None,
855 qpack_max_table_capacity: None,
856 qpack_blocked_streams: None,
857 connect_protocol_enabled: Some(1),
858 h3_datagram: None,
859 grease: None,
860 raw: Some(raw_settings),
861 };
862
863 let frame_payload_len = 2;
864 let frame_header_len = 2;
865
866 let wire_len = {
867 let mut b = octets::OctetsMut::with_slice(&mut d);
868 frame.to_bytes(&mut b).unwrap()
869 };
870
871 assert_eq!(wire_len, frame_header_len + frame_payload_len);
872
873 assert_eq!(
874 Frame::from_bytes(
875 SETTINGS_FRAME_TYPE_ID,
876 frame_payload_len as u64,
877 &d[frame_header_len..]
878 )
879 .unwrap(),
880 frame
881 );
882 }
883
884 #[test]
settings_h3_connect_protocol_enabled_bad()885 fn settings_h3_connect_protocol_enabled_bad() {
886 let mut d = [42; 128];
887
888 let raw_settings = vec![(SETTINGS_ENABLE_CONNECT_PROTOCOL, 9)];
889
890 let frame = Frame::Settings {
891 max_field_section_size: None,
892 qpack_max_table_capacity: None,
893 qpack_blocked_streams: None,
894 connect_protocol_enabled: Some(9),
895 h3_datagram: None,
896 grease: None,
897 raw: Some(raw_settings),
898 };
899
900 let frame_payload_len = 2;
901 let frame_header_len = 2;
902
903 let wire_len = {
904 let mut b = octets::OctetsMut::with_slice(&mut d);
905 frame.to_bytes(&mut b).unwrap()
906 };
907
908 assert_eq!(wire_len, frame_header_len + frame_payload_len);
909
910 assert_eq!(
911 Frame::from_bytes(
912 SETTINGS_FRAME_TYPE_ID,
913 frame_payload_len as u64,
914 &d[frame_header_len..]
915 ),
916 Err(crate::h3::Error::SettingsError)
917 );
918 }
919
920 #[test]
settings_h3_dgram_only()921 fn settings_h3_dgram_only() {
922 let mut d = [42; 128];
923
924 let raw_settings = vec![(SETTINGS_H3_DATAGRAM, 1)];
925
926 let frame = Frame::Settings {
927 max_field_section_size: None,
928 qpack_max_table_capacity: None,
929 qpack_blocked_streams: None,
930 connect_protocol_enabled: None,
931 h3_datagram: Some(1),
932 grease: None,
933 raw: Some(raw_settings),
934 };
935
936 let frame_payload_len = 3;
937 let frame_header_len = 2;
938
939 let wire_len = {
940 let mut b = octets::OctetsMut::with_slice(&mut d);
941 frame.to_bytes(&mut b).unwrap()
942 };
943
944 assert_eq!(wire_len, frame_header_len + frame_payload_len);
945
946 assert_eq!(
947 Frame::from_bytes(
948 SETTINGS_FRAME_TYPE_ID,
949 frame_payload_len as u64,
950 &d[frame_header_len..]
951 )
952 .unwrap(),
953 frame
954 );
955 }
956
957 #[test]
settings_h3_dgram_bad()958 fn settings_h3_dgram_bad() {
959 let mut d = [42; 128];
960
961 let frame = Frame::Settings {
962 max_field_section_size: None,
963 qpack_max_table_capacity: None,
964 qpack_blocked_streams: None,
965 connect_protocol_enabled: None,
966 h3_datagram: Some(5),
967 grease: None,
968 raw: Default::default(),
969 };
970
971 let frame_payload_len = 3;
972 let frame_header_len = 2;
973
974 let wire_len = {
975 let mut b = octets::OctetsMut::with_slice(&mut d);
976 frame.to_bytes(&mut b).unwrap()
977 };
978
979 assert_eq!(wire_len, frame_header_len + frame_payload_len);
980
981 assert_eq!(
982 Frame::from_bytes(
983 SETTINGS_FRAME_TYPE_ID,
984 frame_payload_len as u64,
985 &d[frame_header_len..]
986 ),
987 Err(crate::h3::Error::SettingsError)
988 );
989 }
990
991 #[test]
settings_qpack_only()992 fn settings_qpack_only() {
993 let mut d = [42; 128];
994
995 let raw_settings = vec![
996 (SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0),
997 (SETTINGS_QPACK_BLOCKED_STREAMS, 0),
998 ];
999
1000 let frame = Frame::Settings {
1001 max_field_section_size: None,
1002 qpack_max_table_capacity: Some(0),
1003 qpack_blocked_streams: Some(0),
1004 connect_protocol_enabled: None,
1005 h3_datagram: None,
1006 grease: None,
1007 raw: Some(raw_settings),
1008 };
1009
1010 let frame_payload_len = 4;
1011 let frame_header_len = 2;
1012
1013 let wire_len = {
1014 let mut b = octets::OctetsMut::with_slice(&mut d);
1015 frame.to_bytes(&mut b).unwrap()
1016 };
1017
1018 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1019
1020 assert_eq!(
1021 Frame::from_bytes(
1022 SETTINGS_FRAME_TYPE_ID,
1023 frame_payload_len as u64,
1024 &d[frame_header_len..]
1025 )
1026 .unwrap(),
1027 frame
1028 );
1029 }
1030
1031 #[test]
settings_h2_prohibited()1032 fn settings_h2_prohibited() {
1033 // We need to test the prohibited values (0x0 | 0x2 | 0x3 | 0x4 | 0x5)
1034 // but the quiche API doesn't support that, so use a manually created
1035 // frame data buffer where d[frame_header_len] is the SETTING type field.
1036 let frame_payload_len = 2u64;
1037 let frame_header_len = 2;
1038 let mut d = [
1039 SETTINGS_FRAME_TYPE_ID as u8,
1040 frame_payload_len as u8,
1041 0x0,
1042 1,
1043 ];
1044
1045 assert_eq!(
1046 Frame::from_bytes(
1047 SETTINGS_FRAME_TYPE_ID,
1048 frame_payload_len,
1049 &d[frame_header_len..]
1050 ),
1051 Err(crate::h3::Error::SettingsError)
1052 );
1053
1054 d[frame_header_len] = 0x2;
1055
1056 assert_eq!(
1057 Frame::from_bytes(
1058 SETTINGS_FRAME_TYPE_ID,
1059 frame_payload_len,
1060 &d[frame_header_len..]
1061 ),
1062 Err(crate::h3::Error::SettingsError)
1063 );
1064
1065 d[frame_header_len] = 0x3;
1066
1067 assert_eq!(
1068 Frame::from_bytes(
1069 SETTINGS_FRAME_TYPE_ID,
1070 frame_payload_len,
1071 &d[frame_header_len..]
1072 ),
1073 Err(crate::h3::Error::SettingsError)
1074 );
1075
1076 d[frame_header_len] = 0x4;
1077
1078 assert_eq!(
1079 Frame::from_bytes(
1080 SETTINGS_FRAME_TYPE_ID,
1081 frame_payload_len,
1082 &d[frame_header_len..]
1083 ),
1084 Err(crate::h3::Error::SettingsError)
1085 );
1086
1087 d[frame_header_len] = 0x5;
1088
1089 assert_eq!(
1090 Frame::from_bytes(
1091 SETTINGS_FRAME_TYPE_ID,
1092 frame_payload_len,
1093 &d[frame_header_len..]
1094 ),
1095 Err(crate::h3::Error::SettingsError)
1096 );
1097 }
1098
1099 #[test]
settings_too_big()1100 fn settings_too_big() {
1101 // We need to test a SETTINGS frame that exceeds
1102 // MAX_SETTINGS_PAYLOAD_SIZE, so just craft a special buffer that look
1103 // likes the frame. The payload content doesn't matter since quiche
1104 // should abort before then.
1105 let frame_payload_len = MAX_SETTINGS_PAYLOAD_SIZE + 1;
1106 let frame_header_len = 2;
1107 let d = [
1108 SETTINGS_FRAME_TYPE_ID as u8,
1109 frame_payload_len as u8,
1110 0x1,
1111 1,
1112 ];
1113
1114 assert_eq!(
1115 Frame::from_bytes(
1116 SETTINGS_FRAME_TYPE_ID,
1117 frame_payload_len as u64,
1118 &d[frame_header_len..]
1119 ),
1120 Err(crate::h3::Error::ExcessiveLoad)
1121 );
1122 }
1123
1124 #[test]
push_promise()1125 fn push_promise() {
1126 let mut d = [42; 128];
1127
1128 let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
1129 let frame_payload_len = 1 + header_block.len();
1130 let frame_header_len = 2;
1131
1132 let frame = Frame::PushPromise {
1133 push_id: 0,
1134 header_block,
1135 };
1136
1137 let wire_len = {
1138 let mut b = octets::OctetsMut::with_slice(&mut d);
1139 frame.to_bytes(&mut b).unwrap()
1140 };
1141
1142 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1143
1144 assert_eq!(
1145 Frame::from_bytes(
1146 PUSH_PROMISE_FRAME_TYPE_ID,
1147 frame_payload_len as u64,
1148 &d[frame_header_len..]
1149 )
1150 .unwrap(),
1151 frame
1152 );
1153 }
1154
1155 #[test]
goaway()1156 fn goaway() {
1157 let mut d = [42; 128];
1158
1159 let frame = Frame::GoAway { id: 32 };
1160
1161 let frame_payload_len = 1;
1162 let frame_header_len = 2;
1163
1164 let wire_len = {
1165 let mut b = octets::OctetsMut::with_slice(&mut d);
1166 frame.to_bytes(&mut b).unwrap()
1167 };
1168
1169 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1170
1171 assert_eq!(
1172 Frame::from_bytes(
1173 GOAWAY_FRAME_TYPE_ID,
1174 frame_payload_len as u64,
1175 &d[frame_header_len..]
1176 )
1177 .unwrap(),
1178 frame
1179 );
1180 }
1181
1182 #[test]
max_push_id()1183 fn max_push_id() {
1184 let mut d = [42; 128];
1185
1186 let frame = Frame::MaxPushId { push_id: 128 };
1187
1188 let frame_payload_len = 2;
1189 let frame_header_len = 2;
1190
1191 let wire_len = {
1192 let mut b = octets::OctetsMut::with_slice(&mut d);
1193 frame.to_bytes(&mut b).unwrap()
1194 };
1195
1196 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1197
1198 assert_eq!(
1199 Frame::from_bytes(
1200 MAX_PUSH_FRAME_TYPE_ID,
1201 frame_payload_len as u64,
1202 &d[frame_header_len..]
1203 )
1204 .unwrap(),
1205 frame
1206 );
1207 }
1208
1209 #[test]
priority_update_request()1210 fn priority_update_request() {
1211 let mut d = [42; 128];
1212
1213 let prioritized_element_id = 4;
1214 let priority_field_value = b"abcdefghijklm".to_vec();
1215 let frame_payload_len = 1 + priority_field_value.len();
1216 let frame_header_len = 5;
1217
1218 let frame = Frame::PriorityUpdateRequest {
1219 prioritized_element_id,
1220 priority_field_value,
1221 };
1222
1223 let wire_len = {
1224 let mut b = octets::OctetsMut::with_slice(&mut d);
1225 frame.to_bytes(&mut b).unwrap()
1226 };
1227
1228 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1229
1230 assert_eq!(
1231 Frame::from_bytes(
1232 PRIORITY_UPDATE_FRAME_REQUEST_TYPE_ID,
1233 frame_payload_len as u64,
1234 &d[frame_header_len..]
1235 )
1236 .unwrap(),
1237 frame
1238 );
1239 }
1240
1241 #[test]
priority_update_push()1242 fn priority_update_push() {
1243 let mut d = [42; 128];
1244
1245 let prioritized_element_id = 6;
1246 let priority_field_value = b"abcdefghijklm".to_vec();
1247 let frame_payload_len = 1 + priority_field_value.len();
1248 let frame_header_len = 5;
1249
1250 let frame = Frame::PriorityUpdatePush {
1251 prioritized_element_id,
1252 priority_field_value,
1253 };
1254
1255 let wire_len = {
1256 let mut b = octets::OctetsMut::with_slice(&mut d);
1257 frame.to_bytes(&mut b).unwrap()
1258 };
1259
1260 assert_eq!(wire_len, frame_header_len + frame_payload_len);
1261
1262 assert_eq!(
1263 Frame::from_bytes(
1264 PRIORITY_UPDATE_FRAME_PUSH_TYPE_ID,
1265 frame_payload_len as u64,
1266 &d[frame_header_len..]
1267 )
1268 .unwrap(),
1269 frame
1270 );
1271 }
1272
1273 #[test]
unknown_type()1274 fn unknown_type() {
1275 let d = [42; 12];
1276
1277 assert_eq!(
1278 Frame::from_bytes(255, 12345, &d[..]),
1279 Ok(Frame::Unknown {
1280 raw_type: 255,
1281 payload_length: 12345
1282 })
1283 );
1284 }
1285 }
1286