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
43 #[derive(Clone, PartialEq)]
44 pub enum Frame {
45 Data {
46 payload: Vec<u8>,
47 },
48
49 Headers {
50 header_block: Vec<u8>,
51 },
52
53 CancelPush {
54 push_id: u64,
55 },
56
57 Settings {
58 max_header_list_size: Option<u64>,
59 qpack_max_table_capacity: Option<u64>,
60 qpack_blocked_streams: Option<u64>,
61 grease: Option<(u64, u64)>,
62 },
63
64 PushPromise {
65 push_id: u64,
66 header_block: Vec<u8>,
67 },
68
69 GoAway {
70 id: u64,
71 },
72
73 MaxPushId {
74 push_id: u64,
75 },
76
77 Unknown,
78 }
79
80 impl Frame {
from_bytes( frame_type: u64, payload_length: u64, bytes: &[u8], ) -> Result<Frame>81 pub fn from_bytes(
82 frame_type: u64, payload_length: u64, bytes: &[u8],
83 ) -> Result<Frame> {
84 let mut b = octets::Octets::with_slice(bytes);
85
86 // TODO: handling of 0-length frames
87 let frame = match frame_type {
88 DATA_FRAME_TYPE_ID => Frame::Data {
89 payload: b.get_bytes(payload_length as usize)?.to_vec(),
90 },
91
92 HEADERS_FRAME_TYPE_ID => Frame::Headers {
93 header_block: b.get_bytes(payload_length as usize)?.to_vec(),
94 },
95
96 CANCEL_PUSH_FRAME_TYPE_ID => Frame::CancelPush {
97 push_id: b.get_varint()?,
98 },
99
100 SETTINGS_FRAME_TYPE_ID =>
101 parse_settings_frame(&mut b, payload_length as usize)?,
102
103 PUSH_PROMISE_FRAME_TYPE_ID =>
104 parse_push_promise(payload_length, &mut b)?,
105
106 GOAWAY_FRAME_TYPE_ID => Frame::GoAway {
107 id: b.get_varint()?,
108 },
109
110 MAX_PUSH_FRAME_TYPE_ID => Frame::MaxPushId {
111 push_id: b.get_varint()?,
112 },
113
114 _ => Frame::Unknown,
115 };
116
117 Ok(frame)
118 }
119
to_bytes(&self, b: &mut octets::OctetsMut) -> Result<usize>120 pub fn to_bytes(&self, b: &mut octets::OctetsMut) -> Result<usize> {
121 let before = b.cap();
122
123 match self {
124 Frame::Data { payload } => {
125 b.put_varint(DATA_FRAME_TYPE_ID)?;
126 b.put_varint(payload.len() as u64)?;
127
128 b.put_bytes(payload.as_ref())?;
129 },
130
131 Frame::Headers { header_block } => {
132 b.put_varint(HEADERS_FRAME_TYPE_ID)?;
133 b.put_varint(header_block.len() as u64)?;
134
135 b.put_bytes(header_block.as_ref())?;
136 },
137
138 Frame::CancelPush { push_id } => {
139 b.put_varint(CANCEL_PUSH_FRAME_TYPE_ID)?;
140 b.put_varint(octets::varint_len(*push_id) as u64)?;
141
142 b.put_varint(*push_id)?;
143 },
144
145 Frame::Settings {
146 max_header_list_size,
147 qpack_max_table_capacity,
148 qpack_blocked_streams,
149 grease,
150 } => {
151 let mut len = 0;
152
153 if let Some(val) = max_header_list_size {
154 len += octets::varint_len(SETTINGS_MAX_HEADER_LIST_SIZE);
155 len += octets::varint_len(*val);
156 }
157
158 if let Some(val) = qpack_max_table_capacity {
159 len += octets::varint_len(SETTINGS_QPACK_MAX_TABLE_CAPACITY);
160 len += octets::varint_len(*val);
161 }
162
163 if let Some(val) = qpack_blocked_streams {
164 len += octets::varint_len(SETTINGS_QPACK_BLOCKED_STREAMS);
165 len += octets::varint_len(*val);
166 }
167
168 if let Some(val) = grease {
169 len += octets::varint_len(val.0);
170 len += octets::varint_len(val.1);
171 }
172
173 b.put_varint(SETTINGS_FRAME_TYPE_ID)?;
174 b.put_varint(len as u64)?;
175
176 if let Some(val) = max_header_list_size {
177 b.put_varint(SETTINGS_MAX_HEADER_LIST_SIZE)?;
178 b.put_varint(*val as u64)?;
179 }
180
181 if let Some(val) = qpack_max_table_capacity {
182 b.put_varint(SETTINGS_QPACK_MAX_TABLE_CAPACITY)?;
183 b.put_varint(*val as u64)?;
184 }
185
186 if let Some(val) = qpack_blocked_streams {
187 b.put_varint(SETTINGS_QPACK_BLOCKED_STREAMS)?;
188 b.put_varint(*val as u64)?;
189 }
190
191 if let Some(val) = grease {
192 b.put_varint(val.0)?;
193 b.put_varint(val.1)?;
194 }
195 },
196
197 Frame::PushPromise {
198 push_id,
199 header_block,
200 } => {
201 let len = octets::varint_len(*push_id) + header_block.len();
202 b.put_varint(PUSH_PROMISE_FRAME_TYPE_ID)?;
203 b.put_varint(len as u64)?;
204
205 b.put_varint(*push_id)?;
206 b.put_bytes(header_block.as_ref())?;
207 },
208
209 Frame::GoAway { id } => {
210 b.put_varint(GOAWAY_FRAME_TYPE_ID)?;
211 b.put_varint(octets::varint_len(*id) as u64)?;
212
213 b.put_varint(*id)?;
214 },
215
216 Frame::MaxPushId { push_id } => {
217 b.put_varint(MAX_PUSH_FRAME_TYPE_ID)?;
218 b.put_varint(octets::varint_len(*push_id) as u64)?;
219
220 b.put_varint(*push_id)?;
221 },
222
223 Frame::Unknown => unreachable!(),
224 }
225
226 Ok(before - b.cap())
227 }
228 }
229
230 impl std::fmt::Debug for Frame {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result231 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
232 match self {
233 Frame::Data { payload } => {
234 write!(f, "DATA len={}", payload.len())?;
235 },
236
237 Frame::Headers { header_block } => {
238 write!(f, "HEADERS len={}", header_block.len())?;
239 },
240
241 Frame::CancelPush { push_id } => {
242 write!(f, "CANCEL_PUSH push_id={}", push_id)?;
243 },
244
245 Frame::Settings {
246 max_header_list_size,
247 qpack_max_table_capacity,
248 qpack_blocked_streams,
249 ..
250 } => {
251 write!(f, "SETTINGS max_headers={:?}, qpack_max_table={:?}, qpack_blocked={:?} ", max_header_list_size, qpack_max_table_capacity, qpack_blocked_streams)?;
252 },
253
254 Frame::PushPromise {
255 push_id,
256 header_block,
257 } => {
258 write!(
259 f,
260 "PUSH_PROMISE push_id={} len={}",
261 push_id,
262 header_block.len()
263 )?;
264 },
265
266 Frame::GoAway { id } => {
267 write!(f, "GOAWAY id={}", id)?;
268 },
269
270 Frame::MaxPushId { push_id } => {
271 write!(f, "MAX_PUSH_ID push_id={}", push_id)?;
272 },
273
274 Frame::Unknown => {
275 write!(f, "UNKNOWN")?;
276 },
277 }
278
279 Ok(())
280 }
281 }
282
parse_settings_frame( b: &mut octets::Octets, settings_length: usize, ) -> Result<Frame>283 fn parse_settings_frame(
284 b: &mut octets::Octets, settings_length: usize,
285 ) -> Result<Frame> {
286 let mut max_header_list_size = None;
287 let mut qpack_max_table_capacity = None;
288 let mut qpack_blocked_streams = None;
289
290 while b.off() < settings_length {
291 let setting_ty = b.get_varint()?;
292 let settings_val = b.get_varint()?;
293
294 match setting_ty {
295 SETTINGS_QPACK_MAX_TABLE_CAPACITY => {
296 qpack_max_table_capacity = Some(settings_val);
297 },
298
299 SETTINGS_MAX_HEADER_LIST_SIZE => {
300 max_header_list_size = Some(settings_val);
301 },
302
303 SETTINGS_QPACK_BLOCKED_STREAMS => {
304 qpack_blocked_streams = Some(settings_val);
305 },
306
307 // Unknown Settings parameters must be ignored.
308 _ => (),
309 }
310 }
311
312 Ok(Frame::Settings {
313 max_header_list_size,
314 qpack_max_table_capacity,
315 qpack_blocked_streams,
316 grease: None,
317 })
318 }
319
parse_push_promise( payload_length: u64, b: &mut octets::Octets, ) -> Result<Frame>320 fn parse_push_promise(
321 payload_length: u64, b: &mut octets::Octets,
322 ) -> Result<Frame> {
323 let push_id = b.get_varint()?;
324 let header_block_length = payload_length - octets::varint_len(push_id) as u64;
325 let header_block = b.get_bytes(header_block_length as usize)?.to_vec();
326
327 Ok(Frame::PushPromise {
328 push_id,
329 header_block,
330 })
331 }
332
333 #[cfg(test)]
334 mod tests {
335 use super::*;
336
337 #[test]
data()338 fn data() {
339 let mut d = [42; 128];
340
341 let payload = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
342 let frame_payload_len = payload.len();
343 let frame_header_len = 2;
344
345 let frame = Frame::Data { payload };
346
347 let wire_len = {
348 let mut b = octets::OctetsMut::with_slice(&mut d);
349 frame.to_bytes(&mut b).unwrap()
350 };
351
352 assert_eq!(wire_len, frame_header_len + frame_payload_len);
353
354 assert_eq!(
355 Frame::from_bytes(
356 DATA_FRAME_TYPE_ID,
357 frame_payload_len as u64,
358 &d[frame_header_len..]
359 )
360 .unwrap(),
361 frame
362 );
363 }
364
365 #[test]
headers()366 fn headers() {
367 let mut d = [42; 128];
368
369 let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
370 let frame_payload_len = header_block.len();
371 let frame_header_len = 2;
372
373 let frame = Frame::Headers { header_block };
374
375 let wire_len = {
376 let mut b = octets::OctetsMut::with_slice(&mut d);
377 frame.to_bytes(&mut b).unwrap()
378 };
379
380 assert_eq!(wire_len, frame_header_len + frame_payload_len);
381
382 assert_eq!(
383 Frame::from_bytes(
384 HEADERS_FRAME_TYPE_ID,
385 frame_payload_len as u64,
386 &d[frame_header_len..]
387 )
388 .unwrap(),
389 frame
390 );
391 }
392
393 #[test]
cancel_push()394 fn cancel_push() {
395 let mut d = [42; 128];
396
397 let frame = Frame::CancelPush { push_id: 0 };
398
399 let frame_payload_len = 1;
400 let frame_header_len = 2;
401
402 let wire_len = {
403 let mut b = octets::OctetsMut::with_slice(&mut d);
404 frame.to_bytes(&mut b).unwrap()
405 };
406
407 assert_eq!(wire_len, frame_header_len + frame_payload_len);
408
409 assert_eq!(
410 Frame::from_bytes(
411 CANCEL_PUSH_FRAME_TYPE_ID,
412 frame_payload_len as u64,
413 &d[frame_header_len..]
414 )
415 .unwrap(),
416 frame
417 );
418 }
419
420 #[test]
settings_all_no_grease()421 fn settings_all_no_grease() {
422 let mut d = [42; 128];
423
424 let frame = Frame::Settings {
425 max_header_list_size: Some(0),
426 qpack_max_table_capacity: Some(0),
427 qpack_blocked_streams: Some(0),
428 grease: None,
429 };
430
431 let frame_payload_len = 6;
432 let frame_header_len = 2;
433
434 let wire_len = {
435 let mut b = octets::OctetsMut::with_slice(&mut d);
436 frame.to_bytes(&mut b).unwrap()
437 };
438
439 assert_eq!(wire_len, frame_header_len + frame_payload_len);
440
441 assert_eq!(
442 Frame::from_bytes(
443 SETTINGS_FRAME_TYPE_ID,
444 frame_payload_len as u64,
445 &d[frame_header_len..]
446 )
447 .unwrap(),
448 frame
449 );
450 }
451
452 #[test]
settings_all_grease()453 fn settings_all_grease() {
454 let mut d = [42; 128];
455
456 let frame = Frame::Settings {
457 max_header_list_size: Some(0),
458 qpack_max_table_capacity: Some(0),
459 qpack_blocked_streams: Some(0),
460 grease: Some((33, 33)),
461 };
462
463 // Frame parsing will always ignore GREASE values.
464 let frame_parsed = Frame::Settings {
465 max_header_list_size: Some(0),
466 qpack_max_table_capacity: Some(0),
467 qpack_blocked_streams: Some(0),
468 grease: None,
469 };
470
471 let frame_payload_len = 8;
472 let frame_header_len = 2;
473
474 let wire_len = {
475 let mut b = octets::OctetsMut::with_slice(&mut d);
476 frame.to_bytes(&mut b).unwrap()
477 };
478
479 assert_eq!(wire_len, frame_header_len + frame_payload_len);
480
481 assert_eq!(
482 Frame::from_bytes(
483 SETTINGS_FRAME_TYPE_ID,
484 frame_payload_len as u64,
485 &d[frame_header_len..]
486 )
487 .unwrap(),
488 frame_parsed
489 );
490 }
491
492 #[test]
settings_h3_only()493 fn settings_h3_only() {
494 let mut d = [42; 128];
495
496 let frame = Frame::Settings {
497 max_header_list_size: Some(1024),
498 qpack_max_table_capacity: None,
499 qpack_blocked_streams: None,
500 grease: None,
501 };
502
503 let frame_payload_len = 3;
504 let frame_header_len = 2;
505
506 let wire_len = {
507 let mut b = octets::OctetsMut::with_slice(&mut d);
508 frame.to_bytes(&mut b).unwrap()
509 };
510
511 assert_eq!(wire_len, frame_header_len + frame_payload_len);
512
513 assert_eq!(
514 Frame::from_bytes(
515 SETTINGS_FRAME_TYPE_ID,
516 frame_payload_len as u64,
517 &d[frame_header_len..]
518 )
519 .unwrap(),
520 frame
521 );
522 }
523
524 #[test]
settings_qpack_only()525 fn settings_qpack_only() {
526 let mut d = [42; 128];
527
528 let frame = Frame::Settings {
529 max_header_list_size: None,
530 qpack_max_table_capacity: Some(0),
531 qpack_blocked_streams: Some(0),
532 grease: None,
533 };
534
535 let frame_payload_len = 4;
536 let frame_header_len = 2;
537
538 let wire_len = {
539 let mut b = octets::OctetsMut::with_slice(&mut d);
540 frame.to_bytes(&mut b).unwrap()
541 };
542
543 assert_eq!(wire_len, frame_header_len + frame_payload_len);
544
545 assert_eq!(
546 Frame::from_bytes(
547 SETTINGS_FRAME_TYPE_ID,
548 frame_payload_len as u64,
549 &d[frame_header_len..]
550 )
551 .unwrap(),
552 frame
553 );
554 }
555
556 #[test]
push_promise()557 fn push_promise() {
558 let mut d = [42; 128];
559
560 let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
561 let frame_payload_len = 1 + header_block.len();
562 let frame_header_len = 2;
563
564 let frame = Frame::PushPromise {
565 push_id: 0,
566 header_block,
567 };
568
569 let wire_len = {
570 let mut b = octets::OctetsMut::with_slice(&mut d);
571 frame.to_bytes(&mut b).unwrap()
572 };
573
574 assert_eq!(wire_len, frame_header_len + frame_payload_len);
575
576 assert_eq!(
577 Frame::from_bytes(
578 PUSH_PROMISE_FRAME_TYPE_ID,
579 frame_payload_len as u64,
580 &d[frame_header_len..]
581 )
582 .unwrap(),
583 frame
584 );
585 }
586
587 #[test]
goaway()588 fn goaway() {
589 let mut d = [42; 128];
590
591 let frame = Frame::GoAway { id: 32 };
592
593 let frame_payload_len = 1;
594 let frame_header_len = 2;
595
596 let wire_len = {
597 let mut b = octets::OctetsMut::with_slice(&mut d);
598 frame.to_bytes(&mut b).unwrap()
599 };
600
601 assert_eq!(wire_len, frame_header_len + frame_payload_len);
602
603 assert_eq!(
604 Frame::from_bytes(
605 GOAWAY_FRAME_TYPE_ID,
606 frame_payload_len as u64,
607 &d[frame_header_len..]
608 )
609 .unwrap(),
610 frame
611 );
612 }
613
614 #[test]
max_push_id()615 fn max_push_id() {
616 let mut d = [42; 128];
617
618 let frame = Frame::MaxPushId { push_id: 128 };
619
620 let frame_payload_len = 2;
621 let frame_header_len = 2;
622
623 let wire_len = {
624 let mut b = octets::OctetsMut::with_slice(&mut d);
625 frame.to_bytes(&mut b).unwrap()
626 };
627
628 assert_eq!(wire_len, frame_header_len + frame_payload_len);
629
630 assert_eq!(
631 Frame::from_bytes(
632 MAX_PUSH_FRAME_TYPE_ID,
633 frame_payload_len as u64,
634 &d[frame_header_len..]
635 )
636 .unwrap(),
637 frame
638 );
639 }
640
641 #[test]
unknown_type()642 fn unknown_type() {
643 let d = [42; 12];
644
645 assert_eq!(Frame::from_bytes(255, 12345, &d[..]), Ok(Frame::Unknown));
646 }
647 }
648