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 use crate::octets;
30
31 pub const DATA_FRAME_TYPE_ID: u64 = 0x0;
32 pub const HEADERS_FRAME_TYPE_ID: u64 = 0x1;
33 pub const CANCEL_PUSH_FRAME_TYPE_ID: u64 = 0x3;
34 pub const SETTINGS_FRAME_TYPE_ID: u64 = 0x4;
35 pub const PUSH_PROMISE_FRAME_TYPE_ID: u64 = 0x5;
36 pub const GOAWAY_FRAME_TYPE_ID: u64 = 0x6;
37 pub const MAX_PUSH_FRAME_TYPE_ID: u64 = 0xD;
38
39 const SETTINGS_QPACK_MAX_TABLE_CAPACITY: u64 = 0x1;
40 const SETTINGS_MAX_HEADER_LIST_SIZE: u64 = 0x6;
41 const SETTINGS_QPACK_BLOCKED_STREAMS: u64 = 0x7;
42 const SETTINGS_H3_DATAGRAM: u64 = 0x276;
43
44 // Permit between 16 maximally-encoded and 128 minimally-encoded SETTINGS.
45 const MAX_SETTINGS_PAYLOAD_SIZE: usize = 256;
46
47 #[derive(Clone, PartialEq)]
48 pub enum Frame {
49 Data {
50 payload: Vec<u8>,
51 },
52
53 Headers {
54 header_block: Vec<u8>,
55 },
56
57 CancelPush {
58 push_id: u64,
59 },
60
61 Settings {
62 max_header_list_size: Option<u64>,
63 qpack_max_table_capacity: Option<u64>,
64 qpack_blocked_streams: Option<u64>,
65 h3_datagram: Option<u64>,
66 grease: Option<(u64, u64)>,
67 },
68
69 PushPromise {
70 push_id: u64,
71 header_block: Vec<u8>,
72 },
73
74 GoAway {
75 id: u64,
76 },
77
78 MaxPushId {
79 push_id: u64,
80 },
81
82 Unknown,
83 }
84
85 impl Frame {
from_bytes( frame_type: u64, payload_length: u64, bytes: &[u8], ) -> Result<Frame>86 pub fn from_bytes(
87 frame_type: u64, payload_length: u64, bytes: &[u8],
88 ) -> Result<Frame> {
89 let mut b = octets::Octets::with_slice(bytes);
90
91 // TODO: handling of 0-length frames
92 let frame = match frame_type {
93 DATA_FRAME_TYPE_ID => Frame::Data {
94 payload: b.get_bytes(payload_length as usize)?.to_vec(),
95 },
96
97 HEADERS_FRAME_TYPE_ID => Frame::Headers {
98 header_block: b.get_bytes(payload_length as usize)?.to_vec(),
99 },
100
101 CANCEL_PUSH_FRAME_TYPE_ID => Frame::CancelPush {
102 push_id: b.get_varint()?,
103 },
104
105 SETTINGS_FRAME_TYPE_ID =>
106 parse_settings_frame(&mut b, payload_length as usize)?,
107
108 PUSH_PROMISE_FRAME_TYPE_ID =>
109 parse_push_promise(payload_length, &mut b)?,
110
111 GOAWAY_FRAME_TYPE_ID => Frame::GoAway {
112 id: b.get_varint()?,
113 },
114
115 MAX_PUSH_FRAME_TYPE_ID => Frame::MaxPushId {
116 push_id: b.get_varint()?,
117 },
118
119 _ => Frame::Unknown,
120 };
121
122 Ok(frame)
123 }
124
to_bytes(&self, b: &mut octets::OctetsMut) -> Result<usize>125 pub fn to_bytes(&self, b: &mut octets::OctetsMut) -> Result<usize> {
126 let before = b.cap();
127
128 match self {
129 Frame::Data { payload } => {
130 b.put_varint(DATA_FRAME_TYPE_ID)?;
131 b.put_varint(payload.len() as u64)?;
132
133 b.put_bytes(payload.as_ref())?;
134 },
135
136 Frame::Headers { header_block } => {
137 b.put_varint(HEADERS_FRAME_TYPE_ID)?;
138 b.put_varint(header_block.len() as u64)?;
139
140 b.put_bytes(header_block.as_ref())?;
141 },
142
143 Frame::CancelPush { push_id } => {
144 b.put_varint(CANCEL_PUSH_FRAME_TYPE_ID)?;
145 b.put_varint(octets::varint_len(*push_id) as u64)?;
146
147 b.put_varint(*push_id)?;
148 },
149
150 Frame::Settings {
151 max_header_list_size,
152 qpack_max_table_capacity,
153 qpack_blocked_streams,
154 h3_datagram,
155 grease,
156 } => {
157 let mut len = 0;
158
159 if let Some(val) = max_header_list_size {
160 len += octets::varint_len(SETTINGS_MAX_HEADER_LIST_SIZE);
161 len += octets::varint_len(*val);
162 }
163
164 if let Some(val) = qpack_max_table_capacity {
165 len += octets::varint_len(SETTINGS_QPACK_MAX_TABLE_CAPACITY);
166 len += octets::varint_len(*val);
167 }
168
169 if let Some(val) = qpack_blocked_streams {
170 len += octets::varint_len(SETTINGS_QPACK_BLOCKED_STREAMS);
171 len += octets::varint_len(*val);
172 }
173
174 if let Some(val) = h3_datagram {
175 len += octets::varint_len(SETTINGS_H3_DATAGRAM);
176 len += octets::varint_len(*val);
177 }
178
179 if let Some(val) = grease {
180 len += octets::varint_len(val.0);
181 len += octets::varint_len(val.1);
182 }
183
184 b.put_varint(SETTINGS_FRAME_TYPE_ID)?;
185 b.put_varint(len as u64)?;
186
187 if let Some(val) = max_header_list_size {
188 b.put_varint(SETTINGS_MAX_HEADER_LIST_SIZE)?;
189 b.put_varint(*val as u64)?;
190 }
191
192 if let Some(val) = qpack_max_table_capacity {
193 b.put_varint(SETTINGS_QPACK_MAX_TABLE_CAPACITY)?;
194 b.put_varint(*val as u64)?;
195 }
196
197 if let Some(val) = qpack_blocked_streams {
198 b.put_varint(SETTINGS_QPACK_BLOCKED_STREAMS)?;
199 b.put_varint(*val as u64)?;
200 }
201
202 if let Some(val) = h3_datagram {
203 b.put_varint(SETTINGS_H3_DATAGRAM)?;
204 b.put_varint(*val as u64)?;
205 }
206
207 if let Some(val) = grease {
208 b.put_varint(val.0)?;
209 b.put_varint(val.1)?;
210 }
211 },
212
213 Frame::PushPromise {
214 push_id,
215 header_block,
216 } => {
217 let len = octets::varint_len(*push_id) + header_block.len();
218 b.put_varint(PUSH_PROMISE_FRAME_TYPE_ID)?;
219 b.put_varint(len as u64)?;
220
221 b.put_varint(*push_id)?;
222 b.put_bytes(header_block.as_ref())?;
223 },
224
225 Frame::GoAway { id } => {
226 b.put_varint(GOAWAY_FRAME_TYPE_ID)?;
227 b.put_varint(octets::varint_len(*id) as u64)?;
228
229 b.put_varint(*id)?;
230 },
231
232 Frame::MaxPushId { push_id } => {
233 b.put_varint(MAX_PUSH_FRAME_TYPE_ID)?;
234 b.put_varint(octets::varint_len(*push_id) as u64)?;
235
236 b.put_varint(*push_id)?;
237 },
238
239 Frame::Unknown => unreachable!(),
240 }
241
242 Ok(before - b.cap())
243 }
244 }
245
246 impl std::fmt::Debug for Frame {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result247 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
248 match self {
249 Frame::Data { payload } => {
250 write!(f, "DATA len={}", payload.len())?;
251 },
252
253 Frame::Headers { header_block } => {
254 write!(f, "HEADERS len={}", header_block.len())?;
255 },
256
257 Frame::CancelPush { push_id } => {
258 write!(f, "CANCEL_PUSH push_id={}", push_id)?;
259 },
260
261 Frame::Settings {
262 max_header_list_size,
263 qpack_max_table_capacity,
264 qpack_blocked_streams,
265 ..
266 } => {
267 write!(f, "SETTINGS max_headers={:?}, qpack_max_table={:?}, qpack_blocked={:?} ", max_header_list_size, qpack_max_table_capacity, qpack_blocked_streams)?;
268 },
269
270 Frame::PushPromise {
271 push_id,
272 header_block,
273 } => {
274 write!(
275 f,
276 "PUSH_PROMISE push_id={} len={}",
277 push_id,
278 header_block.len()
279 )?;
280 },
281
282 Frame::GoAway { id } => {
283 write!(f, "GOAWAY id={}", id)?;
284 },
285
286 Frame::MaxPushId { push_id } => {
287 write!(f, "MAX_PUSH_ID push_id={}", push_id)?;
288 },
289
290 Frame::Unknown => {
291 write!(f, "UNKNOWN")?;
292 },
293 }
294
295 Ok(())
296 }
297 }
298
parse_settings_frame( b: &mut octets::Octets, settings_length: usize, ) -> Result<Frame>299 fn parse_settings_frame(
300 b: &mut octets::Octets, settings_length: usize,
301 ) -> Result<Frame> {
302 let mut max_header_list_size = None;
303 let mut qpack_max_table_capacity = None;
304 let mut qpack_blocked_streams = None;
305 let mut h3_datagram = None;
306
307 // Reject SETTINGS frames that are too long.
308 if settings_length > MAX_SETTINGS_PAYLOAD_SIZE {
309 return Err(super::Error::ExcessiveLoad);
310 }
311
312 while b.off() < settings_length {
313 let setting_ty = b.get_varint()?;
314 let settings_val = b.get_varint()?;
315
316 match setting_ty {
317 SETTINGS_QPACK_MAX_TABLE_CAPACITY => {
318 qpack_max_table_capacity = Some(settings_val);
319 },
320
321 SETTINGS_MAX_HEADER_LIST_SIZE => {
322 max_header_list_size = Some(settings_val);
323 },
324
325 SETTINGS_QPACK_BLOCKED_STREAMS => {
326 qpack_blocked_streams = Some(settings_val);
327 },
328
329 SETTINGS_H3_DATAGRAM => {
330 if settings_val > 1 {
331 return Err(super::Error::SettingsError);
332 }
333
334 h3_datagram = Some(settings_val);
335 },
336
337 // Reserved values overlap with HTTP/2 and MUST be rejected
338 0x0 | 0x2 | 0x3 | 0x4 | 0x5 =>
339 return Err(super::Error::SettingsError),
340
341 // Unknown Settings parameters must be ignored.
342 _ => (),
343 }
344 }
345
346 Ok(Frame::Settings {
347 max_header_list_size,
348 qpack_max_table_capacity,
349 qpack_blocked_streams,
350 h3_datagram,
351 grease: None,
352 })
353 }
354
parse_push_promise( payload_length: u64, b: &mut octets::Octets, ) -> Result<Frame>355 fn parse_push_promise(
356 payload_length: u64, b: &mut octets::Octets,
357 ) -> Result<Frame> {
358 let push_id = b.get_varint()?;
359 let header_block_length = payload_length - octets::varint_len(push_id) as u64;
360 let header_block = b.get_bytes(header_block_length as usize)?.to_vec();
361
362 Ok(Frame::PushPromise {
363 push_id,
364 header_block,
365 })
366 }
367
368 #[cfg(test)]
369 mod tests {
370 use super::*;
371
372 #[test]
data()373 fn data() {
374 let mut d = [42; 128];
375
376 let payload = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
377 let frame_payload_len = payload.len();
378 let frame_header_len = 2;
379
380 let frame = Frame::Data { payload };
381
382 let wire_len = {
383 let mut b = octets::OctetsMut::with_slice(&mut d);
384 frame.to_bytes(&mut b).unwrap()
385 };
386
387 assert_eq!(wire_len, frame_header_len + frame_payload_len);
388
389 assert_eq!(
390 Frame::from_bytes(
391 DATA_FRAME_TYPE_ID,
392 frame_payload_len as u64,
393 &d[frame_header_len..]
394 )
395 .unwrap(),
396 frame
397 );
398 }
399
400 #[test]
headers()401 fn headers() {
402 let mut d = [42; 128];
403
404 let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
405 let frame_payload_len = header_block.len();
406 let frame_header_len = 2;
407
408 let frame = Frame::Headers { header_block };
409
410 let wire_len = {
411 let mut b = octets::OctetsMut::with_slice(&mut d);
412 frame.to_bytes(&mut b).unwrap()
413 };
414
415 assert_eq!(wire_len, frame_header_len + frame_payload_len);
416
417 assert_eq!(
418 Frame::from_bytes(
419 HEADERS_FRAME_TYPE_ID,
420 frame_payload_len as u64,
421 &d[frame_header_len..]
422 )
423 .unwrap(),
424 frame
425 );
426 }
427
428 #[test]
cancel_push()429 fn cancel_push() {
430 let mut d = [42; 128];
431
432 let frame = Frame::CancelPush { push_id: 0 };
433
434 let frame_payload_len = 1;
435 let frame_header_len = 2;
436
437 let wire_len = {
438 let mut b = octets::OctetsMut::with_slice(&mut d);
439 frame.to_bytes(&mut b).unwrap()
440 };
441
442 assert_eq!(wire_len, frame_header_len + frame_payload_len);
443
444 assert_eq!(
445 Frame::from_bytes(
446 CANCEL_PUSH_FRAME_TYPE_ID,
447 frame_payload_len as u64,
448 &d[frame_header_len..]
449 )
450 .unwrap(),
451 frame
452 );
453 }
454
455 #[test]
settings_all_no_grease()456 fn settings_all_no_grease() {
457 let mut d = [42; 128];
458
459 let frame = Frame::Settings {
460 max_header_list_size: Some(0),
461 qpack_max_table_capacity: Some(0),
462 qpack_blocked_streams: Some(0),
463 h3_datagram: Some(0),
464 grease: None,
465 };
466
467 let frame_payload_len = 9;
468 let frame_header_len = 2;
469
470 let wire_len = {
471 let mut b = octets::OctetsMut::with_slice(&mut d);
472 frame.to_bytes(&mut b).unwrap()
473 };
474
475 assert_eq!(wire_len, frame_header_len + frame_payload_len);
476
477 assert_eq!(
478 Frame::from_bytes(
479 SETTINGS_FRAME_TYPE_ID,
480 frame_payload_len as u64,
481 &d[frame_header_len..]
482 )
483 .unwrap(),
484 frame
485 );
486 }
487
488 #[test]
settings_all_grease()489 fn settings_all_grease() {
490 let mut d = [42; 128];
491
492 let frame = Frame::Settings {
493 max_header_list_size: Some(0),
494 qpack_max_table_capacity: Some(0),
495 qpack_blocked_streams: Some(0),
496 h3_datagram: Some(0),
497 grease: Some((33, 33)),
498 };
499
500 // Frame parsing will always ignore GREASE values.
501 let frame_parsed = Frame::Settings {
502 max_header_list_size: Some(0),
503 qpack_max_table_capacity: Some(0),
504 qpack_blocked_streams: Some(0),
505 h3_datagram: Some(0),
506 grease: None,
507 };
508
509 let frame_payload_len = 11;
510 let frame_header_len = 2;
511
512 let wire_len = {
513 let mut b = octets::OctetsMut::with_slice(&mut d);
514 frame.to_bytes(&mut b).unwrap()
515 };
516
517 assert_eq!(wire_len, frame_header_len + frame_payload_len);
518
519 assert_eq!(
520 Frame::from_bytes(
521 SETTINGS_FRAME_TYPE_ID,
522 frame_payload_len as u64,
523 &d[frame_header_len..]
524 )
525 .unwrap(),
526 frame_parsed
527 );
528 }
529
530 #[test]
settings_h3_only()531 fn settings_h3_only() {
532 let mut d = [42; 128];
533
534 let frame = Frame::Settings {
535 max_header_list_size: Some(1024),
536 qpack_max_table_capacity: None,
537 qpack_blocked_streams: None,
538 h3_datagram: None,
539 grease: None,
540 };
541
542 let frame_payload_len = 3;
543 let frame_header_len = 2;
544
545 let wire_len = {
546 let mut b = octets::OctetsMut::with_slice(&mut d);
547 frame.to_bytes(&mut b).unwrap()
548 };
549
550 assert_eq!(wire_len, frame_header_len + frame_payload_len);
551
552 assert_eq!(
553 Frame::from_bytes(
554 SETTINGS_FRAME_TYPE_ID,
555 frame_payload_len as u64,
556 &d[frame_header_len..]
557 )
558 .unwrap(),
559 frame
560 );
561 }
562
563 #[test]
settings_h3_dgram_only()564 fn settings_h3_dgram_only() {
565 let mut d = [42; 128];
566
567 let frame = Frame::Settings {
568 max_header_list_size: None,
569 qpack_max_table_capacity: None,
570 qpack_blocked_streams: None,
571 h3_datagram: Some(1),
572 grease: None,
573 };
574
575 let frame_payload_len = 3;
576 let frame_header_len = 2;
577
578 let wire_len = {
579 let mut b = octets::OctetsMut::with_slice(&mut d);
580 frame.to_bytes(&mut b).unwrap()
581 };
582
583 assert_eq!(wire_len, frame_header_len + frame_payload_len);
584
585 assert_eq!(
586 Frame::from_bytes(
587 SETTINGS_FRAME_TYPE_ID,
588 frame_payload_len as u64,
589 &d[frame_header_len..]
590 )
591 .unwrap(),
592 frame
593 );
594 }
595
596 #[test]
settings_h3_dgram_bad()597 fn settings_h3_dgram_bad() {
598 let mut d = [42; 128];
599
600 let frame = Frame::Settings {
601 max_header_list_size: None,
602 qpack_max_table_capacity: None,
603 qpack_blocked_streams: None,
604 h3_datagram: Some(5),
605 grease: None,
606 };
607
608 let frame_payload_len = 3;
609 let frame_header_len = 2;
610
611 let wire_len = {
612 let mut b = octets::OctetsMut::with_slice(&mut d);
613 frame.to_bytes(&mut b).unwrap()
614 };
615
616 assert_eq!(wire_len, frame_header_len + frame_payload_len);
617
618 assert_eq!(
619 Frame::from_bytes(
620 SETTINGS_FRAME_TYPE_ID,
621 frame_payload_len as u64,
622 &d[frame_header_len..]
623 ),
624 Err(crate::h3::Error::SettingsError)
625 );
626 }
627
628 #[test]
settings_qpack_only()629 fn settings_qpack_only() {
630 let mut d = [42; 128];
631
632 let frame = Frame::Settings {
633 max_header_list_size: None,
634 qpack_max_table_capacity: Some(0),
635 qpack_blocked_streams: Some(0),
636 h3_datagram: None,
637 grease: None,
638 };
639
640 let frame_payload_len = 4;
641 let frame_header_len = 2;
642
643 let wire_len = {
644 let mut b = octets::OctetsMut::with_slice(&mut d);
645 frame.to_bytes(&mut b).unwrap()
646 };
647
648 assert_eq!(wire_len, frame_header_len + frame_payload_len);
649
650 assert_eq!(
651 Frame::from_bytes(
652 SETTINGS_FRAME_TYPE_ID,
653 frame_payload_len as u64,
654 &d[frame_header_len..]
655 )
656 .unwrap(),
657 frame
658 );
659 }
660
661 #[test]
settings_h2_prohibited()662 fn settings_h2_prohibited() {
663 // We need to test the prohibited values (0x0 | 0x2 | 0x3 | 0x4 | 0x5)
664 // but the quiche API doesn't support that, so use a manually created
665 // frame data buffer where d[frame_header_len] is the SETTING type field.
666 let frame_payload_len = 2u64;
667 let frame_header_len = 2;
668 let mut d = [
669 SETTINGS_FRAME_TYPE_ID as u8,
670 frame_payload_len as u8,
671 0x0,
672 1,
673 ];
674
675 assert_eq!(
676 Frame::from_bytes(
677 SETTINGS_FRAME_TYPE_ID,
678 frame_payload_len,
679 &d[frame_header_len..]
680 ),
681 Err(crate::h3::Error::SettingsError)
682 );
683
684 d[frame_header_len] = 0x2;
685
686 assert_eq!(
687 Frame::from_bytes(
688 SETTINGS_FRAME_TYPE_ID,
689 frame_payload_len,
690 &d[frame_header_len..]
691 ),
692 Err(crate::h3::Error::SettingsError)
693 );
694
695 d[frame_header_len] = 0x3;
696
697 assert_eq!(
698 Frame::from_bytes(
699 SETTINGS_FRAME_TYPE_ID,
700 frame_payload_len,
701 &d[frame_header_len..]
702 ),
703 Err(crate::h3::Error::SettingsError)
704 );
705
706 d[frame_header_len] = 0x4;
707
708 assert_eq!(
709 Frame::from_bytes(
710 SETTINGS_FRAME_TYPE_ID,
711 frame_payload_len,
712 &d[frame_header_len..]
713 ),
714 Err(crate::h3::Error::SettingsError)
715 );
716
717 d[frame_header_len] = 0x5;
718
719 assert_eq!(
720 Frame::from_bytes(
721 SETTINGS_FRAME_TYPE_ID,
722 frame_payload_len,
723 &d[frame_header_len..]
724 ),
725 Err(crate::h3::Error::SettingsError)
726 );
727 }
728
729 #[test]
settings_too_big()730 fn settings_too_big() {
731 // We need to test a SETTINGS frame that exceeds
732 // MAX_SETTINGS_PAYLOAD_SIZE, so just craft a special buffer that look
733 // likes the frame. The payload content doesn't matter since quiche
734 // should abort before then.
735 let frame_payload_len = MAX_SETTINGS_PAYLOAD_SIZE + 1;
736 let frame_header_len = 2;
737 let d = [
738 SETTINGS_FRAME_TYPE_ID as u8,
739 frame_payload_len as u8,
740 0x1,
741 1,
742 ];
743
744 assert_eq!(
745 Frame::from_bytes(
746 SETTINGS_FRAME_TYPE_ID,
747 frame_payload_len as u64,
748 &d[frame_header_len..]
749 ),
750 Err(crate::h3::Error::ExcessiveLoad)
751 );
752 }
753
754 #[test]
push_promise()755 fn push_promise() {
756 let mut d = [42; 128];
757
758 let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
759 let frame_payload_len = 1 + header_block.len();
760 let frame_header_len = 2;
761
762 let frame = Frame::PushPromise {
763 push_id: 0,
764 header_block,
765 };
766
767 let wire_len = {
768 let mut b = octets::OctetsMut::with_slice(&mut d);
769 frame.to_bytes(&mut b).unwrap()
770 };
771
772 assert_eq!(wire_len, frame_header_len + frame_payload_len);
773
774 assert_eq!(
775 Frame::from_bytes(
776 PUSH_PROMISE_FRAME_TYPE_ID,
777 frame_payload_len as u64,
778 &d[frame_header_len..]
779 )
780 .unwrap(),
781 frame
782 );
783 }
784
785 #[test]
goaway()786 fn goaway() {
787 let mut d = [42; 128];
788
789 let frame = Frame::GoAway { id: 32 };
790
791 let frame_payload_len = 1;
792 let frame_header_len = 2;
793
794 let wire_len = {
795 let mut b = octets::OctetsMut::with_slice(&mut d);
796 frame.to_bytes(&mut b).unwrap()
797 };
798
799 assert_eq!(wire_len, frame_header_len + frame_payload_len);
800
801 assert_eq!(
802 Frame::from_bytes(
803 GOAWAY_FRAME_TYPE_ID,
804 frame_payload_len as u64,
805 &d[frame_header_len..]
806 )
807 .unwrap(),
808 frame
809 );
810 }
811
812 #[test]
max_push_id()813 fn max_push_id() {
814 let mut d = [42; 128];
815
816 let frame = Frame::MaxPushId { push_id: 128 };
817
818 let frame_payload_len = 2;
819 let frame_header_len = 2;
820
821 let wire_len = {
822 let mut b = octets::OctetsMut::with_slice(&mut d);
823 frame.to_bytes(&mut b).unwrap()
824 };
825
826 assert_eq!(wire_len, frame_header_len + frame_payload_len);
827
828 assert_eq!(
829 Frame::from_bytes(
830 MAX_PUSH_FRAME_TYPE_ID,
831 frame_payload_len as u64,
832 &d[frame_header_len..]
833 )
834 .unwrap(),
835 frame
836 );
837 }
838
839 #[test]
unknown_type()840 fn unknown_type() {
841 let d = [42; 12];
842
843 assert_eq!(Frame::from_bytes(255, 12345, &d[..]), Ok(Frame::Unknown));
844 }
845 }
846