1use std::{fmt, io::Write, ops::RangeInclusive};
7
8use byteorder::{BigEndian, WriteBytesExt};
9use enum_repr::EnumRepr;
10
11pub use enumflags2;
12use enumflags2::{bitflags, BitFlags};
13
14pub use nom;
15
16use nom::{
17 combinator::map,
18 number::streaming::{be_u16, be_u24, be_u32, be_u8},
19 sequence::tuple,
20 IResult,
21};
22
23use fluke_buffet::{Piece, Roll, RollMut};
24
25pub const PREFACE: &[u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
27
28pub fn preface(i: Roll) -> IResult<Roll, ()> {
29 let (i, _) = nom::bytes::streaming::tag(PREFACE)(i)?;
30 Ok((i, ()))
31}
32
33pub trait IntoPiece {
34 fn into_piece(self, scratch: &mut RollMut) -> std::io::Result<Piece>;
35}
36
37#[EnumRepr(type = "u8")]
39#[derive(Debug, Clone, Copy)]
40pub enum RawFrameType {
41 Data = 0x00,
42 Headers = 0x01,
43 Priority = 0x02,
44 RstStream = 0x03,
45 Settings = 0x04,
46 PushPromise = 0x05,
47 Ping = 0x06,
48 GoAway = 0x07,
49 WindowUpdate = 0x08,
50 Continuation = 0x09,
51}
52
53#[derive(Debug, Clone, Copy)]
55pub enum FrameType {
56 Data(BitFlags<DataFlags>),
57 Headers(BitFlags<HeadersFlags>),
58 Priority,
59 RstStream,
60 Settings(BitFlags<SettingsFlags>),
61 PushPromise,
62 Ping(BitFlags<PingFlags>),
63 GoAway,
64 WindowUpdate,
65 Continuation(BitFlags<ContinuationFlags>),
66 Unknown(EncodedFrameType),
67}
68
69impl FrameType {
70 pub fn into_frame(self, stream_id: StreamId) -> Frame {
72 Frame {
73 frame_type: self,
74 len: 0,
75 reserved: 0,
76 stream_id,
77 }
78 }
79}
80
81#[bitflags]
83#[repr(u8)]
84#[derive(Copy, Clone, Debug, PartialEq, Eq)]
85pub enum DataFlags {
86 Padded = 0x08,
87 EndStream = 0x01,
88}
89
90#[bitflags]
92#[repr(u8)]
93#[derive(Copy, Clone, Debug, PartialEq, Eq)]
94pub enum HeadersFlags {
95 Priority = 0x20,
96 Padded = 0x08,
97 EndHeaders = 0x04,
98 EndStream = 0x01,
99}
100
101#[bitflags]
103#[repr(u8)]
104#[derive(Copy, Clone, Debug, PartialEq, Eq)]
105pub enum SettingsFlags {
106 Ack = 0x01,
107}
108
109#[bitflags]
111#[repr(u8)]
112#[derive(Copy, Clone, Debug, PartialEq, Eq)]
113pub enum PingFlags {
114 Ack = 0x01,
115}
116
117#[bitflags]
119#[repr(u8)]
120#[derive(Copy, Clone, Debug, PartialEq, Eq)]
121pub enum ContinuationFlags {
122 EndHeaders = 0x04,
123}
124
125#[derive(Debug, Clone, Copy)]
126pub struct EncodedFrameType {
127 pub ty: u8,
128 pub flags: u8,
129}
130
131impl EncodedFrameType {
132 fn parse(i: Roll) -> IResult<Roll, Self> {
133 let (i, (ty, flags)) = tuple((be_u8, be_u8))(i)?;
134 Ok((i, Self { ty, flags }))
135 }
136}
137
138impl From<(RawFrameType, u8)> for EncodedFrameType {
139 fn from((ty, flags): (RawFrameType, u8)) -> Self {
140 Self {
141 ty: ty.repr(),
142 flags,
143 }
144 }
145}
146
147impl FrameType {
148 pub(crate) fn encode(self) -> EncodedFrameType {
149 match self {
150 FrameType::Data(f) => (RawFrameType::Data, f.bits()).into(),
151 FrameType::Headers(f) => (RawFrameType::Headers, f.bits()).into(),
152 FrameType::Priority => (RawFrameType::Priority, 0).into(),
153 FrameType::RstStream => (RawFrameType::RstStream, 0).into(),
154 FrameType::Settings(f) => (RawFrameType::Settings, f.bits()).into(),
155 FrameType::PushPromise => (RawFrameType::PushPromise, 0).into(),
156 FrameType::Ping(f) => (RawFrameType::Ping, f.bits()).into(),
157 FrameType::GoAway => (RawFrameType::GoAway, 0).into(),
158 FrameType::WindowUpdate => (RawFrameType::WindowUpdate, 0).into(),
159 FrameType::Continuation(f) => (RawFrameType::Continuation, f.bits()).into(),
160 FrameType::Unknown(ft) => ft,
161 }
162 }
163
164 fn decode(ft: EncodedFrameType) -> Self {
165 match RawFrameType::from_repr(ft.ty) {
166 Some(ty) => match ty {
167 RawFrameType::Data => {
168 FrameType::Data(BitFlags::<DataFlags>::from_bits_truncate(ft.flags))
169 }
170 RawFrameType::Headers => {
171 FrameType::Headers(BitFlags::<HeadersFlags>::from_bits_truncate(ft.flags))
172 }
173 RawFrameType::Priority => FrameType::Priority,
174 RawFrameType::RstStream => FrameType::RstStream,
175 RawFrameType::Settings => {
176 FrameType::Settings(BitFlags::<SettingsFlags>::from_bits_truncate(ft.flags))
177 }
178 RawFrameType::PushPromise => FrameType::PushPromise,
179 RawFrameType::Ping => {
180 FrameType::Ping(BitFlags::<PingFlags>::from_bits_truncate(ft.flags))
181 }
182 RawFrameType::GoAway => FrameType::GoAway,
183 RawFrameType::WindowUpdate => FrameType::WindowUpdate,
184 RawFrameType::Continuation => FrameType::Continuation(
185 BitFlags::<ContinuationFlags>::from_bits_truncate(ft.flags),
186 ),
187 },
188 None => FrameType::Unknown(ft),
189 }
190 }
191}
192
193#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
194pub struct StreamId(pub u32);
195
196impl StreamId {
197 pub const CONNECTION: Self = Self(0);
199
200 pub fn is_server_initiated(&self) -> bool {
202 self.0 % 2 == 0
203 }
204}
205
206#[derive(Debug, thiserror::Error)]
207#[error("invalid stream id: {0}")]
208pub struct StreamIdOutOfRange(u32);
209
210impl TryFrom<u32> for StreamId {
211 type Error = StreamIdOutOfRange;
212
213 fn try_from(value: u32) -> Result<Self, Self::Error> {
214 if value & 0x8000_0000 != 0 {
215 Err(StreamIdOutOfRange(value))
216 } else {
217 Ok(Self(value))
218 }
219 }
220}
221
222impl fmt::Debug for StreamId {
223 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224 fmt::Debug::fmt(&self.0, f)
225 }
226}
227
228impl fmt::Display for StreamId {
229 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230 fmt::Display::fmt(&self.0, f)
231 }
232}
233
234pub struct Frame {
236 pub frame_type: FrameType,
237 pub reserved: u8,
238 pub stream_id: StreamId,
239 pub len: u32,
240}
241
242impl fmt::Debug for Frame {
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 if self.stream_id.0 == 0 {
245 write!(f, "Conn:")?;
246 } else {
247 write!(f, "#{}:", self.stream_id.0)?;
248 }
249
250 let name = match &self.frame_type {
251 FrameType::Data(_) => "Data",
252 FrameType::Headers(_) => "Headers",
253 FrameType::Priority => "Priority",
254 FrameType::RstStream => "RstStream",
255 FrameType::Settings(_) => "Settings",
256 FrameType::PushPromise => "PushPromise",
257 FrameType::Ping(_) => "Ping",
258 FrameType::GoAway => "GoAway",
259 FrameType::WindowUpdate => "WindowUpdate",
260 FrameType::Continuation(_) => "Continuation",
261 FrameType::Unknown(EncodedFrameType { ty, flags }) => {
262 return write!(f, "UnknownFrame({:#x}, {:#x})", ty, flags)
263 }
264 };
265 let mut s = f.debug_struct(name);
266
267 if self.reserved != 0 {
268 s.field("reserved", &self.reserved);
269 }
270 if self.len > 0 {
271 s.field("len", &self.len);
272 }
273
274 struct DisplayDebug<'a, D: fmt::Display>(&'a D);
276 impl<'a, D: fmt::Display> fmt::Debug for DisplayDebug<'a, D> {
277 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
278 fmt::Display::fmt(self.0, f)
279 }
280 }
281
282 match &self.frame_type {
285 FrameType::Data(flags) => {
286 if !flags.is_empty() {
287 s.field("flags", &DisplayDebug(flags));
288 }
289 }
290 FrameType::Headers(flags) => {
291 if !flags.is_empty() {
292 s.field("flags", &DisplayDebug(flags));
293 }
294 }
295 FrameType::Settings(flags) => {
296 if !flags.is_empty() {
297 s.field("flags", &DisplayDebug(flags));
298 }
299 }
300 FrameType::Ping(flags) => {
301 if !flags.is_empty() {
302 s.field("flags", &DisplayDebug(flags));
303 }
304 }
305 FrameType::Continuation(flags) => {
306 if !flags.is_empty() {
307 s.field("flags", &DisplayDebug(flags));
308 }
309 }
310 _ => {
311 }
313 }
314
315 s.finish()
316 }
317}
318
319impl Frame {
320 pub fn new(frame_type: FrameType, stream_id: StreamId) -> Self {
322 Self {
323 frame_type,
324 reserved: 0,
325 stream_id,
326 len: 0,
327 }
328 }
329
330 pub fn with_len(mut self, len: u32) -> Self {
332 self.len = len;
333 self
334 }
335
336 pub fn parse(i: Roll) -> IResult<Roll, Self> {
338 let (i, (len, frame_type, (reserved, stream_id))) = tuple((
339 be_u24,
340 EncodedFrameType::parse,
341 parse_reserved_and_stream_id,
342 ))(i)?;
343
344 let frame = Frame {
345 frame_type: FrameType::decode(frame_type),
346 reserved,
347 stream_id,
348 len,
349 };
350 Ok((i, frame))
351 }
352
353 pub fn write_into(self, mut w: impl std::io::Write) -> std::io::Result<()> {
354 use byteorder::{BigEndian, WriteBytesExt};
355 w.write_u24::<BigEndian>(self.len as _)?;
356 let ft = self.frame_type.encode();
357 w.write_u8(ft.ty)?;
358 w.write_u8(ft.flags)?;
359 w.write_all(&pack_reserved_and_stream_id(self.reserved, self.stream_id))?;
360
361 Ok(())
362 }
363
364 pub fn is_ack(self) -> bool {
366 match self.frame_type {
367 FrameType::Data(_) => false,
368 FrameType::Headers(_) => false,
369 FrameType::Priority => false,
370 FrameType::RstStream => false,
371 FrameType::Settings(flags) => flags.contains(SettingsFlags::Ack),
372 FrameType::PushPromise => false,
373 FrameType::Ping(flags) => flags.contains(PingFlags::Ack),
374 FrameType::GoAway => false,
375 FrameType::WindowUpdate => false,
376 FrameType::Continuation(_) => false,
377 FrameType::Unknown(_) => false,
378 }
379 }
380}
381
382impl IntoPiece for Frame {
383 fn into_piece(self, mut scratch: &mut RollMut) -> std::io::Result<Piece> {
384 debug_assert_eq!(scratch.len(), 0);
385 self.write_into(&mut scratch)?;
386 Ok(scratch.take_all().into())
387 }
388}
389
390pub fn parse_reserved_and_u31(i: Roll) -> IResult<Roll, (u8, u32)> {
393 fn reserved(i: (Roll, usize)) -> IResult<(Roll, usize), u8> {
394 nom::bits::streaming::take(1_usize)(i)
395 }
396
397 fn stream_id(i: (Roll, usize)) -> IResult<(Roll, usize), u32> {
398 nom::bits::streaming::take(31_usize)(i)
399 }
400
401 nom::bits::bits(tuple((reserved, stream_id)))(i)
402}
403
404fn parse_reserved_and_stream_id(i: Roll) -> IResult<Roll, (u8, StreamId)> {
405 parse_reserved_and_u31(i).map(|(i, (reserved, stream_id))| (i, (reserved, StreamId(stream_id))))
406}
407
408fn pack_reserved_and_stream_id(reserved: u8, stream_id: StreamId) -> [u8; 4] {
410 let mut bytes = stream_id.0.to_be_bytes();
411 if reserved != 0 {
412 bytes[0] |= 0b1000_0000;
413 }
414 bytes
415}
416
417#[derive(Debug)]
419pub struct PrioritySpec {
420 pub exclusive: bool,
421 pub stream_dependency: StreamId,
422 pub weight: u8,
424}
425
426impl PrioritySpec {
427 pub fn parse(i: Roll) -> IResult<Roll, Self> {
428 map(
429 tuple((parse_reserved_and_stream_id, be_u8)),
430 |((exclusive, stream_dependency), weight)| Self {
431 exclusive: exclusive != 0,
432 stream_dependency,
433 weight,
434 },
435 )(i)
436 }
437}
438
439#[derive(Clone, Copy)]
440pub struct ErrorCode(u32);
441
442impl ErrorCode {
443 pub fn as_repr(self) -> u32 {
445 self.0
446 }
447}
448
449impl fmt::Debug for ErrorCode {
450 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
451 match KnownErrorCode::from_repr(self.0) {
452 Some(e) => fmt::Debug::fmt(&e, f),
453 None => write!(f, "ErrorCode(0x{:02x})", self.0),
454 }
455 }
456}
457
458impl From<KnownErrorCode> for ErrorCode {
459 fn from(e: KnownErrorCode) -> Self {
460 Self(e as u32)
461 }
462}
463
464#[EnumRepr(type = "u32")]
465#[derive(Debug, Clone, Copy)]
466pub enum KnownErrorCode {
467 NoError = 0x00,
471
472 ProtocolError = 0x01,
475
476 InternalError = 0x02,
478
479 FlowControlError = 0x03,
481
482 SettingsTimeout = 0x04,
486
487 StreamClosed = 0x05,
489
490 FrameSizeError = 0x06,
492
493 RefusedStream = 0x07,
497
498 Cancel = 0x08,
501
502 CompressionError = 0x09,
505
506 ConnectError = 0x0a,
510
511 EnhanceYourCalm = 0x0b,
514
515 InadequateSecurity = 0x0c,
519
520 Http1_1Required = 0x0d,
522}
523
524impl TryFrom<ErrorCode> for KnownErrorCode {
525 type Error = ();
526
527 fn try_from(e: ErrorCode) -> Result<Self, Self::Error> {
528 KnownErrorCode::from_repr(e.0).ok_or(())
529 }
530}
531
532#[derive(Clone, Copy, Debug)]
534pub struct Settings {
535 pub header_table_size: u32,
541
542 pub enable_push: bool,
560
561 pub max_concurrent_streams: u32,
574
575 pub initial_window_size: u32,
585
586 pub max_frame_size: u32,
594
595 pub max_header_list_size: u32,
604}
605
606impl Default for Settings {
607 fn default() -> Self {
608 Self {
610 header_table_size: 4096,
611 enable_push: false,
612 max_concurrent_streams: 100,
613 initial_window_size: (1 << 16) - 1,
614 max_frame_size: (1 << 14),
615 max_header_list_size: 0,
616 }
617 }
618}
619
620#[EnumRepr(type = "u16")]
621#[derive(Debug, Clone, Copy)]
622enum SettingIdentifier {
623 HeaderTableSize = 0x01,
624 EnablePush = 0x02,
625 MaxConcurrentStreams = 0x03,
626 InitialWindowSize = 0x04,
627 MaxFrameSize = 0x05,
628 MaxHeaderListSize = 0x06,
629}
630
631impl Settings {
632 const MAX_INITIAL_WINDOW_SIZE: u32 = (1 << 31) - 1;
633 const MAX_FRAME_SIZE_ALLOWED_RANGE: RangeInclusive<u32> = (1 << 14)..=((1 << 24) - 1);
634
635 pub fn parse(mut i: Roll) -> IResult<Roll, Self> {
636 tracing::trace!("parsing settings frame, roll length: {}", i.len());
637 let mut settings = Self::default();
638
639 while !i.is_empty() {
640 let (rest, (id, value)) = tuple((be_u16, be_u32))(i)?;
641 tracing::trace!(%id, %value, "Got setting pair");
642 match SettingIdentifier::from_repr(id) {
643 None => {
644 }
646 Some(id) => match id {
647 SettingIdentifier::HeaderTableSize => {
648 settings.header_table_size = value;
649 }
650 SettingIdentifier::EnablePush => {
651 settings.enable_push = match value {
652 0 => false,
653 1 => true,
654 _ => {
655 return Err(nom::Err::Error(nom::error::Error::new(
656 rest,
657 nom::error::ErrorKind::Digit,
658 )));
659 }
660 }
661 }
662 SettingIdentifier::MaxConcurrentStreams => {
663 settings.max_concurrent_streams = value;
664 }
665 SettingIdentifier::InitialWindowSize => {
666 if value > Self::MAX_INITIAL_WINDOW_SIZE {
667 return Err(nom::Err::Error(nom::error::Error::new(
668 rest,
669 nom::error::ErrorKind::Digit,
670 )));
671 }
672 settings.initial_window_size = value;
673 }
674 SettingIdentifier::MaxFrameSize => {
675 if !Self::MAX_FRAME_SIZE_ALLOWED_RANGE.contains(&value) {
676 return Err(nom::Err::Error(nom::error::Error::new(
677 rest,
678 nom::error::ErrorKind::Digit,
681 )));
682 }
683 settings.max_frame_size = value;
684 }
685 SettingIdentifier::MaxHeaderListSize => {
686 settings.max_header_list_size = value;
687 }
688 },
689 }
690 i = rest;
691 }
692
693 Ok((i, settings))
694 }
695
696 pub fn pairs(&self) -> impl Iterator<Item = (u16, u32)> {
698 [
699 (
700 SettingIdentifier::HeaderTableSize as u16,
701 self.header_table_size,
702 ),
703 (
704 SettingIdentifier::EnablePush as u16,
707 self.enable_push as u32,
708 ),
709 (
710 SettingIdentifier::MaxConcurrentStreams as u16,
711 self.max_concurrent_streams,
712 ),
713 (
714 SettingIdentifier::InitialWindowSize as u16,
715 self.initial_window_size,
716 ),
717 (SettingIdentifier::MaxFrameSize as u16, self.max_frame_size),
718 (
719 SettingIdentifier::MaxHeaderListSize as u16,
720 self.max_header_list_size,
721 ),
722 ]
723 .into_iter()
724 }
725
726 pub fn write_into(self, mut w: impl std::io::Write) -> std::io::Result<()> {
729 use byteorder::{BigEndian, WriteBytesExt};
730
731 for (id, value) in self.pairs() {
732 w.write_u16::<BigEndian>(id)?;
733 w.write_u32::<BigEndian>(value)?;
734 }
735
736 Ok(())
737 }
738}
739
740impl IntoPiece for Settings {
741 fn into_piece(self, mut scratch: &mut RollMut) -> std::io::Result<Piece> {
742 debug_assert_eq!(scratch.len(), 0);
743 self.write_into(&mut scratch)?;
744 Ok(scratch.take_all().into())
745 }
746}
747
748pub struct GoAway {
750 pub last_stream_id: StreamId,
751 pub error_code: ErrorCode,
752 pub additional_debug_data: Piece,
753}
754
755impl IntoPiece for GoAway {
756 fn into_piece(self, scratch: &mut RollMut) -> std::io::Result<Piece> {
757 let roll = scratch
758 .put_to_roll(8 + self.additional_debug_data.len(), |mut slice| {
759 slice.write_u32::<BigEndian>(self.last_stream_id.0)?;
760 slice.write_u32::<BigEndian>(self.error_code.0)?;
761 slice.write_all(&self.additional_debug_data[..])?;
762
763 Ok(())
764 })
765 .unwrap();
766 Ok(roll.into())
767 }
768}
769
770impl GoAway {
771 pub fn parse(i: Roll) -> IResult<Roll, Self> {
772 let (rest, (last_stream_id, error_code)) = tuple((be_u32, be_u32))(i)?;
773
774 let i = Roll::empty();
775 Ok((
776 i,
777 Self {
778 last_stream_id: StreamId(last_stream_id),
779 error_code: ErrorCode(error_code),
780 additional_debug_data: rest.into(),
781 },
782 ))
783 }
784}
785
786pub struct RstStream {
788 pub error_code: ErrorCode,
789}
790
791impl IntoPiece for RstStream {
792 fn into_piece(self, scratch: &mut RollMut) -> std::io::Result<Piece> {
793 let roll = scratch
794 .put_to_roll(4, |mut slice| {
795 slice.write_u32::<BigEndian>(self.error_code.0)?;
796 Ok(())
797 })
798 .unwrap();
799 Ok(roll.into())
800 }
801}
802
803impl RstStream {
804 pub fn parse(i: Roll) -> IResult<Roll, Self> {
805 let (rest, error_code) = be_u32(i)?;
806 Ok((
807 rest,
808 Self {
809 error_code: ErrorCode(error_code),
810 },
811 ))
812 }
813}
814
815impl<T> IntoPiece for T
816where
817 Piece: From<T>,
818{
819 fn into_piece(self, _scratch: &mut RollMut) -> std::io::Result<Piece> {
820 Ok(self.into())
821 }
822}