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