1use std::{fmt, io::Write, ops::RangeInclusive};
7
8use byteorder::{BigEndian, WriteBytesExt};
9
10pub use enumflags2;
11use enumflags2::{bitflags, BitFlags};
12
13pub use nom;
14
15use nom::{
16 combinator::map,
17 number::streaming::{be_u24, be_u32, be_u8},
18 sequence::tuple,
19 IResult,
20};
21
22use buffet::{Piece, Roll, RollMut};
23
24pub const PREFACE: &[u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
26
27pub fn preface(i: Roll) -> IResult<Roll, ()> {
28 let (i, _) = nom::bytes::streaming::tag(PREFACE)(i)?;
29 Ok((i, ()))
30}
31
32pub trait IntoPiece {
33 fn into_piece(self, scratch: &mut RollMut) -> std::io::Result<Piece>;
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum RawFrameType {
39 Data = 0x00,
40 Headers = 0x01,
41 Priority = 0x02,
42 RstStream = 0x03,
43 Settings = 0x04,
44 PushPromise = 0x05,
45 Ping = 0x06,
46 GoAway = 0x07,
47 WindowUpdate = 0x08,
48 Continuation = 0x09,
49}
50
51impl RawFrameType {
52 pub fn repr(&self) -> u8 {
53 *self as u8
54 }
55
56 pub fn from_repr(value: u8) -> Option<Self> {
57 match value {
58 0x00 => Some(RawFrameType::Data),
59 0x01 => Some(RawFrameType::Headers),
60 0x02 => Some(RawFrameType::Priority),
61 0x03 => Some(RawFrameType::RstStream),
62 0x04 => Some(RawFrameType::Settings),
63 0x05 => Some(RawFrameType::PushPromise),
64 0x06 => Some(RawFrameType::Ping),
65 0x07 => Some(RawFrameType::GoAway),
66 0x08 => Some(RawFrameType::WindowUpdate),
67 0x09 => Some(RawFrameType::Continuation),
68 _ => None,
69 }
70 }
71}
72
73#[test]
74fn test_raw_frame_type_roundtrip() {
75 let variants = [
76 RawFrameType::Data,
77 RawFrameType::Headers,
78 RawFrameType::Priority,
79 RawFrameType::RstStream,
80 RawFrameType::Settings,
81 RawFrameType::PushPromise,
82 RawFrameType::Ping,
83 RawFrameType::GoAway,
84 RawFrameType::WindowUpdate,
85 RawFrameType::Continuation,
86 ];
87
88 for &variant in &variants {
89 let repr = variant as u8;
90 let roundtripped = RawFrameType::from_repr(repr).unwrap();
91 assert_eq!(variant, roundtripped, "Failed to roundtrip {:?}", variant);
92 }
93
94 assert_eq!(RawFrameType::from_repr(0xFF), None);
96}
97
98#[derive(Debug, Clone, Copy)]
100pub enum FrameType {
101 Data(BitFlags<DataFlags>),
102 Headers(BitFlags<HeadersFlags>),
103 Priority,
104 RstStream,
105 Settings(BitFlags<SettingsFlags>),
106 PushPromise,
107 Ping(BitFlags<PingFlags>),
108 GoAway,
109 WindowUpdate,
110 Continuation(BitFlags<ContinuationFlags>),
111 Unknown(EncodedFrameType),
112}
113
114impl FrameType {
115 pub fn into_frame(self, stream_id: StreamId) -> Frame {
117 Frame {
118 frame_type: self,
119 len: 0,
120 reserved: 0,
121 stream_id,
122 }
123 }
124}
125
126#[bitflags]
128#[repr(u8)]
129#[derive(Copy, Clone, Debug, PartialEq, Eq)]
130pub enum DataFlags {
131 Padded = 0x08,
132 EndStream = 0x01,
133}
134
135#[bitflags]
137#[repr(u8)]
138#[derive(Copy, Clone, Debug, PartialEq, Eq)]
139pub enum HeadersFlags {
140 Priority = 0x20,
141 Padded = 0x08,
142 EndHeaders = 0x04,
143 EndStream = 0x01,
144}
145
146#[bitflags]
148#[repr(u8)]
149#[derive(Copy, Clone, Debug, PartialEq, Eq)]
150pub enum SettingsFlags {
151 Ack = 0x01,
152}
153
154#[bitflags]
156#[repr(u8)]
157#[derive(Copy, Clone, Debug, PartialEq, Eq)]
158pub enum PingFlags {
159 Ack = 0x01,
160}
161
162#[bitflags]
164#[repr(u8)]
165#[derive(Copy, Clone, Debug, PartialEq, Eq)]
166pub enum ContinuationFlags {
167 EndHeaders = 0x04,
168}
169
170#[derive(Debug, Clone, Copy)]
171pub struct EncodedFrameType {
172 pub ty: u8,
173 pub flags: u8,
174}
175
176impl EncodedFrameType {
177 fn parse(i: Roll) -> IResult<Roll, Self> {
178 let (i, (ty, flags)) = tuple((be_u8, be_u8))(i)?;
179 Ok((i, Self { ty, flags }))
180 }
181}
182
183impl From<(RawFrameType, u8)> for EncodedFrameType {
184 fn from((ty, flags): (RawFrameType, u8)) -> Self {
185 Self {
186 ty: ty.repr(),
187 flags,
188 }
189 }
190}
191
192impl FrameType {
193 pub(crate) fn encode(self) -> EncodedFrameType {
194 match self {
195 FrameType::Data(f) => (RawFrameType::Data, f.bits()).into(),
196 FrameType::Headers(f) => (RawFrameType::Headers, f.bits()).into(),
197 FrameType::Priority => (RawFrameType::Priority, 0).into(),
198 FrameType::RstStream => (RawFrameType::RstStream, 0).into(),
199 FrameType::Settings(f) => (RawFrameType::Settings, f.bits()).into(),
200 FrameType::PushPromise => (RawFrameType::PushPromise, 0).into(),
201 FrameType::Ping(f) => (RawFrameType::Ping, f.bits()).into(),
202 FrameType::GoAway => (RawFrameType::GoAway, 0).into(),
203 FrameType::WindowUpdate => (RawFrameType::WindowUpdate, 0).into(),
204 FrameType::Continuation(f) => (RawFrameType::Continuation, f.bits()).into(),
205 FrameType::Unknown(ft) => ft,
206 }
207 }
208
209 fn decode(ft: EncodedFrameType) -> Self {
210 match RawFrameType::from_repr(ft.ty) {
211 Some(ty) => match ty {
212 RawFrameType::Data => {
213 FrameType::Data(BitFlags::<DataFlags>::from_bits_truncate(ft.flags))
214 }
215 RawFrameType::Headers => {
216 FrameType::Headers(BitFlags::<HeadersFlags>::from_bits_truncate(ft.flags))
217 }
218 RawFrameType::Priority => FrameType::Priority,
219 RawFrameType::RstStream => FrameType::RstStream,
220 RawFrameType::Settings => {
221 FrameType::Settings(BitFlags::<SettingsFlags>::from_bits_truncate(ft.flags))
222 }
223 RawFrameType::PushPromise => FrameType::PushPromise,
224 RawFrameType::Ping => {
225 FrameType::Ping(BitFlags::<PingFlags>::from_bits_truncate(ft.flags))
226 }
227 RawFrameType::GoAway => FrameType::GoAway,
228 RawFrameType::WindowUpdate => FrameType::WindowUpdate,
229 RawFrameType::Continuation => FrameType::Continuation(
230 BitFlags::<ContinuationFlags>::from_bits_truncate(ft.flags),
231 ),
232 },
233 None => FrameType::Unknown(ft),
234 }
235 }
236}
237
238#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
239pub struct StreamId(pub u32);
240
241impl StreamId {
242 pub const CONNECTION: Self = Self(0);
244
245 pub fn is_server_initiated(&self) -> bool {
247 self.0 % 2 == 0
248 }
249}
250
251#[derive(Debug, thiserror::Error)]
252#[error("invalid stream id: {0}")]
253pub struct StreamIdOutOfRange(u32);
254
255impl TryFrom<u32> for StreamId {
256 type Error = StreamIdOutOfRange;
257
258 fn try_from(value: u32) -> Result<Self, Self::Error> {
259 if value & 0x8000_0000 != 0 {
260 Err(StreamIdOutOfRange(value))
261 } else {
262 Ok(Self(value))
263 }
264 }
265}
266
267impl fmt::Debug for StreamId {
268 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
269 fmt::Debug::fmt(&self.0, f)
270 }
271}
272
273impl fmt::Display for StreamId {
274 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
275 fmt::Display::fmt(&self.0, f)
276 }
277}
278
279#[derive(Clone, Copy)]
281pub struct Frame {
282 pub frame_type: FrameType,
283 pub reserved: u8,
284 pub stream_id: StreamId,
285 pub len: u32,
286}
287
288impl Default for Frame {
289 fn default() -> Self {
290 Self {
291 frame_type: FrameType::Unknown(EncodedFrameType {
292 ty: 0xff,
293 flags: 0xff,
294 }),
295 reserved: 0,
296 stream_id: StreamId::CONNECTION,
297 len: 0,
298 }
299 }
300}
301
302impl fmt::Debug for Frame {
303 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304 if self.stream_id.0 == 0 {
305 write!(f, "Conn:")?;
306 } else {
307 write!(f, "#{}:", self.stream_id.0)?;
308 }
309
310 let name = match &self.frame_type {
311 FrameType::Data(_) => "Data",
312 FrameType::Headers(_) => "Headers",
313 FrameType::Priority => "Priority",
314 FrameType::RstStream => "RstStream",
315 FrameType::Settings(_) => "Settings",
316 FrameType::PushPromise => "PushPromise",
317 FrameType::Ping(_) => "Ping",
318 FrameType::GoAway => "GoAway",
319 FrameType::WindowUpdate => "WindowUpdate",
320 FrameType::Continuation(_) => "Continuation",
321 FrameType::Unknown(EncodedFrameType { ty, flags }) => {
322 return write!(f, "UnknownFrame({:#x}, {:#x}, len={})", ty, flags, self.len)
323 }
324 };
325 let mut s = f.debug_struct(name);
326
327 if self.reserved != 0 {
328 s.field("reserved", &self.reserved);
329 }
330 if self.len > 0 {
331 s.field("len", &self.len);
332 }
333
334 struct DisplayDebug<'a, D: fmt::Display>(&'a D);
336 impl<'a, D: fmt::Display> fmt::Debug for DisplayDebug<'a, D> {
337 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
338 fmt::Display::fmt(self.0, f)
339 }
340 }
341
342 match &self.frame_type {
345 FrameType::Data(flags) => {
346 if !flags.is_empty() {
347 s.field("flags", &DisplayDebug(flags));
348 }
349 }
350 FrameType::Headers(flags) => {
351 if !flags.is_empty() {
352 s.field("flags", &DisplayDebug(flags));
353 }
354 }
355 FrameType::Settings(flags) => {
356 if !flags.is_empty() {
357 s.field("flags", &DisplayDebug(flags));
358 }
359 }
360 FrameType::Ping(flags) => {
361 if !flags.is_empty() {
362 s.field("flags", &DisplayDebug(flags));
363 }
364 }
365 FrameType::Continuation(flags) => {
366 if !flags.is_empty() {
367 s.field("flags", &DisplayDebug(flags));
368 }
369 }
370 _ => {
371 }
373 }
374
375 s.finish()
376 }
377}
378
379impl Frame {
380 pub fn new(frame_type: FrameType, stream_id: StreamId) -> Self {
382 Self {
383 frame_type,
384 reserved: 0,
385 stream_id,
386 len: 0,
387 }
388 }
389
390 pub fn with_len(mut self, len: u32) -> Self {
392 self.len = len;
393 self
394 }
395
396 pub fn parse(i: Roll) -> IResult<Roll, Self> {
398 let (i, (len, frame_type, (reserved, stream_id))) = tuple((
399 be_u24,
400 EncodedFrameType::parse,
401 parse_reserved_and_stream_id,
402 ))(i)?;
403
404 let frame = Frame {
405 frame_type: FrameType::decode(frame_type),
406 reserved,
407 stream_id,
408 len,
409 };
410 Ok((i, frame))
411 }
412
413 pub fn write_into(self, mut w: impl std::io::Write) -> std::io::Result<()> {
414 use byteorder::{BigEndian, WriteBytesExt};
415 w.write_u24::<BigEndian>(self.len as _)?;
416 let ft = self.frame_type.encode();
417 w.write_u8(ft.ty)?;
418 w.write_u8(ft.flags)?;
419 w.write_all(&pack_reserved_and_stream_id(self.reserved, self.stream_id))?;
420
421 Ok(())
422 }
423
424 pub fn is_ack(&self) -> bool {
426 match self.frame_type {
427 FrameType::Settings(flags) => flags.contains(SettingsFlags::Ack),
428 FrameType::Ping(flags) => flags.contains(PingFlags::Ack),
429 _ => false,
430 }
431 }
432
433 pub fn is_end_headers(&self) -> bool {
435 match self.frame_type {
436 FrameType::Headers(flags) => flags.contains(HeadersFlags::EndHeaders),
437 FrameType::Continuation(flags) => flags.contains(ContinuationFlags::EndHeaders),
438 _ => false,
439 }
440 }
441
442 pub fn is_end_stream(&self) -> bool {
444 match self.frame_type {
445 FrameType::Data(flags) => flags.contains(DataFlags::EndStream),
446 FrameType::Headers(flags) => flags.contains(HeadersFlags::EndStream),
447 _ => false,
448 }
449 }
450}
451
452impl IntoPiece for Frame {
453 fn into_piece(self, scratch: &mut RollMut) -> std::io::Result<Piece> {
457 debug_assert_eq!(scratch.len(), 0);
458 self.write_into(&mut *scratch)?;
459 Ok(scratch.take_all().into())
460 }
461}
462
463pub fn parse_bit_and_u31(i: Roll) -> IResult<Roll, (u8, u32)> {
466 let (i, x) = be_u32(i)?;
468
469 let bit = (x >> 31) as u8;
470 let val = x & 0x7FFF_FFFF;
471
472 Ok((i, (bit, val)))
473}
474
475fn parse_reserved_and_stream_id(i: Roll) -> IResult<Roll, (u8, StreamId)> {
476 parse_bit_and_u31(i).map(|(i, (reserved, stream_id))| (i, (reserved, StreamId(stream_id))))
477}
478
479pub fn pack_bit_and_u31(bit: u8, val: u32) -> [u8; 4] {
481 assert_eq!(val & 0x7FFF_FFFF, val, "val is too large: {val:x}");
483
484 assert_eq!(bit & 0x1, bit, "bit should be 0 or 1: {bit:x}");
486
487 let mut bytes = val.to_be_bytes();
489 if bit != 0 {
490 bytes[0] |= 0x80;
491 }
492
493 bytes
494}
495
496pub fn pack_reserved_and_stream_id(reserved: u8, stream_id: StreamId) -> [u8; 4] {
497 pack_bit_and_u31(reserved, stream_id.0)
498}
499
500#[test]
501fn test_pack_and_parse_bit_and_u31() {
502 buffet::bufpool::initialize_allocator().unwrap();
503
504 let test_cases = [
506 (0, 0),
507 (1, 0),
508 (0, 1),
509 (1, 1),
510 (0, 0x7FFF_FFFF),
511 (1, 0x7FFF_FFFF),
512 ];
513
514 let mut roll = RollMut::alloc().unwrap();
515 for &(bit, number) in &test_cases {
516 let packed = pack_bit_and_u31(bit, number);
517 roll.reserve_at_least(4).unwrap();
518 roll.put(&packed[..]).unwrap();
519 let (_, (parsed_bit, parsed_number)) = parse_bit_and_u31(roll.take_all()).unwrap();
520 assert_eq!(dbg!(bit), dbg!(parsed_bit));
521 assert_eq!(dbg!(number), dbg!(parsed_number));
522 }
523}
524
525#[test]
526#[should_panic(expected = "bit should be 0 or 1: 2")]
527fn test_pack_bit_and_u31_panic_not_a_bit() {
528 pack_bit_and_u31(2, 0);
529}
530
531#[test]
532#[should_panic(expected = "val is too large: 80000000")]
533fn test_pack_bit_and_u31_panic_val_too_large() {
534 pack_bit_and_u31(0, 1 << 31);
535}
536
537#[derive(Debug)]
539pub struct PrioritySpec {
540 pub exclusive: bool,
541 pub stream_dependency: StreamId,
542 pub weight: u8,
544}
545
546impl PrioritySpec {
547 pub fn parse(i: Roll) -> IResult<Roll, Self> {
548 map(
549 tuple((parse_reserved_and_stream_id, be_u8)),
550 |((exclusive, stream_dependency), weight)| Self {
551 exclusive: exclusive != 0,
552 stream_dependency,
553 weight,
554 },
555 )(i)
556 }
557}
558
559impl IntoPiece for PrioritySpec {
560 fn into_piece(self, scratch: &mut RollMut) -> std::io::Result<Piece> {
561 let roll = scratch
562 .put_to_roll(5, |mut slice| {
563 let reserved_and_stream_id =
564 pack_reserved_and_stream_id(self.exclusive as u8, self.stream_dependency);
565 slice.write_all(&reserved_and_stream_id)?;
566 slice.write_u8(self.weight)?;
567 Ok(())
568 })
569 .unwrap();
570 Ok(roll.into())
571 }
572}
573
574#[derive(Clone, Copy)]
575pub struct ErrorCode(pub u32);
576
577impl ErrorCode {
578 pub fn as_repr(self) -> u32 {
580 self.0
581 }
582}
583
584impl fmt::Debug for ErrorCode {
585 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
586 match KnownErrorCode::from_repr(self.0) {
587 Some(e) => fmt::Debug::fmt(&e, f),
588 None => write!(f, "ErrorCode(0x{:02x})", self.0),
589 }
590 }
591}
592
593impl From<KnownErrorCode> for ErrorCode {
594 fn from(e: KnownErrorCode) -> Self {
595 Self(e as u32)
596 }
597}
598
599#[derive(Debug, Clone, Copy, PartialEq, Eq)]
600pub enum KnownErrorCode {
601 NoError = 0x00,
605
606 ProtocolError = 0x01,
609
610 InternalError = 0x02,
612
613 FlowControlError = 0x03,
615
616 SettingsTimeout = 0x04,
620
621 StreamClosed = 0x05,
623
624 FrameSizeError = 0x06,
626
627 RefusedStream = 0x07,
631
632 Cancel = 0x08,
635
636 CompressionError = 0x09,
639
640 ConnectError = 0x0a,
644
645 EnhanceYourCalm = 0x0b,
648
649 InadequateSecurity = 0x0c,
653
654 Http1_1Required = 0x0d,
656}
657
658impl KnownErrorCode {
659 pub fn from_repr(value: u32) -> Option<Self> {
660 match value {
661 0x00 => Some(KnownErrorCode::NoError),
662 0x01 => Some(KnownErrorCode::ProtocolError),
663 0x02 => Some(KnownErrorCode::InternalError),
664 0x03 => Some(KnownErrorCode::FlowControlError),
665 0x04 => Some(KnownErrorCode::SettingsTimeout),
666 0x05 => Some(KnownErrorCode::StreamClosed),
667 0x06 => Some(KnownErrorCode::FrameSizeError),
668 0x07 => Some(KnownErrorCode::RefusedStream),
669 0x08 => Some(KnownErrorCode::Cancel),
670 0x09 => Some(KnownErrorCode::CompressionError),
671 0x0a => Some(KnownErrorCode::ConnectError),
672 0x0b => Some(KnownErrorCode::EnhanceYourCalm),
673 0x0c => Some(KnownErrorCode::InadequateSecurity),
674 0x0d => Some(KnownErrorCode::Http1_1Required),
675 _ => None,
676 }
677 }
678
679 pub fn repr(&self) -> u32 {
680 *self as u32
681 }
682}
683
684#[test]
685fn test_known_error_code_roundtrip() {
686 let error_codes = [
687 KnownErrorCode::NoError,
688 KnownErrorCode::ProtocolError,
689 KnownErrorCode::InternalError,
690 KnownErrorCode::FlowControlError,
691 KnownErrorCode::SettingsTimeout,
692 KnownErrorCode::StreamClosed,
693 KnownErrorCode::FrameSizeError,
694 KnownErrorCode::RefusedStream,
695 KnownErrorCode::Cancel,
696 KnownErrorCode::CompressionError,
697 KnownErrorCode::ConnectError,
698 KnownErrorCode::EnhanceYourCalm,
699 KnownErrorCode::InadequateSecurity,
700 KnownErrorCode::Http1_1Required,
701 ];
702
703 for &original in &error_codes {
704 let repr = original.repr();
705 let roundtripped = KnownErrorCode::from_repr(repr).unwrap();
706 assert_eq!(original, roundtripped, "Failed to roundtrip {:?}", original);
707 }
708
709 assert_eq!(KnownErrorCode::from_repr(0xFF), None);
711}
712
713impl TryFrom<ErrorCode> for KnownErrorCode {
714 type Error = ();
715
716 fn try_from(e: ErrorCode) -> Result<Self, Self::Error> {
717 KnownErrorCode::from_repr(e.0).ok_or(())
718 }
719}
720
721#[derive(Clone, Copy, Debug)]
723pub struct Settings {
724 pub header_table_size: u32,
730
731 pub enable_push: bool,
749
750 pub max_concurrent_streams: Option<u32>,
764
765 pub initial_window_size: u32,
775
776 pub max_frame_size: u32,
785
786 pub max_header_list_size: u32,
795}
796
797impl Default for Settings {
798 fn default() -> Self {
799 Self {
801 header_table_size: 4096,
802 enable_push: false,
803 max_concurrent_streams: Some(100),
804 initial_window_size: (1 << 16) - 1,
805 max_frame_size: (1 << 14),
806 max_header_list_size: 0,
807 }
808 }
809}
810
811impl Settings {
812 pub fn apply(&mut self, code: Setting, value: u32) -> Result<(), SettingsError> {
815 match code {
816 Setting::HeaderTableSize => {
817 self.header_table_size = value;
818 }
819 Setting::EnablePush => match value {
820 0 => self.enable_push = false,
821 1 => self.enable_push = true,
822 _ => return Err(SettingsError::InvalidEnablePushValue { actual: value }),
823 },
824 Setting::MaxConcurrentStreams => {
825 self.max_concurrent_streams = Some(value);
826 }
827 Setting::InitialWindowSize => {
828 if value > Self::MAX_INITIAL_WINDOW_SIZE {
829 return Err(SettingsError::InitialWindowSizeTooLarge { actual: value });
830 }
831 self.initial_window_size = value;
832 }
833 Setting::MaxFrameSize => {
834 if !Self::MAX_FRAME_SIZE_ALLOWED_RANGE.contains(&value) {
835 return Err(SettingsError::SettingsMaxFrameSizeInvalid { actual: value });
836 }
837 self.max_frame_size = value;
838 }
839 Setting::MaxHeaderListSize => {
840 self.max_header_list_size = value;
841 }
842 }
843
844 Ok(())
845 }
846}
847
848#[derive(thiserror::Error, Debug)]
849#[non_exhaustive]
850pub enum SettingsError {
851 #[error("ENABLE_PUSH setting is supposed to be either 0 or 1, got {actual}")]
852 InvalidEnablePushValue { actual: u32 },
853
854 #[error("bad INITIAL_WINDOW_SIZE value {actual}, should be than or equal to 2^31-1")]
855 InitialWindowSizeTooLarge { actual: u32 },
856
857 #[error(
858 "bad SETTINGS_MAX_FRAME_SIZE value {actual}, should be between 2^14 and 2^24-1 inclusive"
859 )]
860 SettingsMaxFrameSizeInvalid { actual: u32 },
861}
862
863#[derive(Debug, Clone, Copy, PartialEq, Eq)]
864pub enum Setting {
865 HeaderTableSize = 0x01,
866 EnablePush = 0x02,
867 MaxConcurrentStreams = 0x03,
868 InitialWindowSize = 0x04,
869 MaxFrameSize = 0x05,
870 MaxHeaderListSize = 0x06,
871}
872
873impl Setting {
874 pub fn repr(&self) -> u16 {
875 *self as u16
876 }
877
878 pub fn from_repr(value: u16) -> Option<Self> {
879 match value {
880 0x01 => Some(Setting::HeaderTableSize),
881 0x02 => Some(Setting::EnablePush),
882 0x03 => Some(Setting::MaxConcurrentStreams),
883 0x04 => Some(Setting::InitialWindowSize),
884 0x05 => Some(Setting::MaxFrameSize),
885 0x06 => Some(Setting::MaxHeaderListSize),
886 _ => None,
887 }
888 }
889}
890
891#[test]
892fn test_setting_roundtrip() {
893 let settings = [
894 Setting::HeaderTableSize,
895 Setting::EnablePush,
896 Setting::MaxConcurrentStreams,
897 Setting::InitialWindowSize,
898 Setting::MaxFrameSize,
899 Setting::MaxHeaderListSize,
900 ];
901
902 for &setting in &settings {
903 let repr = setting.repr();
904 let roundtripped = Setting::from_repr(repr).unwrap();
905 assert_eq!(setting, roundtripped, "Failed to roundtrip {:?}", setting);
906 }
907
908 assert_eq!(Setting::from_repr(0x07), None);
910}
911
912impl Settings {
913 pub const MAX_INITIAL_WINDOW_SIZE: u32 = (1 << 31) - 1;
914 pub const MAX_FRAME_SIZE_ALLOWED_RANGE: RangeInclusive<u32> = (1 << 14)..=((1 << 24) - 1);
915
916 pub fn parse<E>(
923 buf: &[u8],
924 mut callback: impl FnMut(Setting, u32) -> Result<(), E>,
925 ) -> Result<(), E> {
926 assert!(
927 buf.len() % 6 == 0,
928 "buffer length must be a multiple of 6 bytes"
929 );
930
931 for chunk in buf.chunks_exact(6) {
932 let id = u16::from_be_bytes([chunk[0], chunk[1]]);
933 let value = u32::from_be_bytes([chunk[2], chunk[3], chunk[4], chunk[5]]);
934 match Setting::from_repr(id) {
935 None => {}
936 Some(id) => {
937 callback(id, value)?;
938 }
939 }
940 }
941
942 Ok(())
943 }
944}
945
946pub struct SettingPairs<'a>(pub &'a [(Setting, u32)]);
947
948impl<'a> From<&'a [(Setting, u32)]> for SettingPairs<'a> {
949 fn from(value: &'a [(Setting, u32)]) -> Self {
950 Self(value)
951 }
952}
953
954impl<const N: usize> From<&'static [(Setting, u32); N]> for SettingPairs<'static> {
955 fn from(value: &'static [(Setting, u32); N]) -> Self {
956 Self(value)
957 }
958}
959
960impl<'a> IntoPiece for SettingPairs<'a> {
961 fn into_piece(self, scratch: &mut RollMut) -> std::io::Result<Piece> {
962 let roll = scratch
963 .put_to_roll(self.0.len() * 6, |mut slice| {
964 for (id, value) in self.0.iter() {
965 slice.write_u16::<BigEndian>(*id as u16)?;
966 slice.write_u32::<BigEndian>(*value)?;
967 }
968 Ok(())
969 })
970 .unwrap();
971 Ok(roll.into())
972 }
973}
974
975pub struct GoAway {
977 pub last_stream_id: StreamId,
978 pub error_code: ErrorCode,
979 pub additional_debug_data: Piece,
980}
981
982impl IntoPiece for GoAway {
983 fn into_piece(self, scratch: &mut RollMut) -> std::io::Result<Piece> {
984 let roll = scratch
985 .put_to_roll(8 + self.additional_debug_data.len(), |mut slice| {
986 slice.write_u32::<BigEndian>(self.last_stream_id.0)?;
987 slice.write_u32::<BigEndian>(self.error_code.0)?;
988 slice.write_all(&self.additional_debug_data[..])?;
989
990 Ok(())
991 })
992 .unwrap();
993 Ok(roll.into())
994 }
995}
996
997impl GoAway {
998 pub fn parse(i: Roll) -> IResult<Roll, Self> {
999 let (rest, (last_stream_id, error_code)) = tuple((be_u32, be_u32))(i)?;
1000
1001 let i = Roll::empty();
1002 Ok((
1003 i,
1004 Self {
1005 last_stream_id: StreamId(last_stream_id),
1006 error_code: ErrorCode(error_code),
1007 additional_debug_data: rest.into(),
1008 },
1009 ))
1010 }
1011}
1012
1013pub struct RstStream {
1015 pub error_code: ErrorCode,
1016}
1017
1018impl IntoPiece for RstStream {
1019 fn into_piece(self, scratch: &mut RollMut) -> std::io::Result<Piece> {
1020 let roll = scratch
1021 .put_to_roll(4, |mut slice| {
1022 slice.write_u32::<BigEndian>(self.error_code.0)?;
1023 Ok(())
1024 })
1025 .unwrap();
1026 Ok(roll.into())
1027 }
1028}
1029
1030impl RstStream {
1031 pub fn parse(i: Roll) -> IResult<Roll, Self> {
1032 let (rest, error_code) = be_u32(i)?;
1033 Ok((
1034 rest,
1035 Self {
1036 error_code: ErrorCode(error_code),
1037 },
1038 ))
1039 }
1040}
1041
1042#[derive(Debug, Clone, Copy)]
1044pub struct WindowUpdate {
1045 pub reserved: u8,
1046 pub increment: u32,
1047}
1048
1049impl IntoPiece for WindowUpdate {
1050 fn into_piece(self, scratch: &mut RollMut) -> std::io::Result<Piece> {
1051 let roll = scratch
1052 .put_to_roll(4, |mut slice| {
1053 let packed = pack_bit_and_u31(self.reserved, self.increment);
1054 slice.write_all(&packed)?;
1055 Ok(())
1056 })
1057 .unwrap();
1058 Ok(roll.into())
1059 }
1060}
1061
1062impl WindowUpdate {
1063 pub fn parse(i: Roll) -> IResult<Roll, Self> {
1064 let (rest, (reserved, increment)) = parse_bit_and_u31(i)?;
1065 Ok((
1066 rest,
1067 Self {
1068 reserved,
1069 increment,
1070 },
1071 ))
1072 }
1073}
1074
1075impl<T> IntoPiece for T
1076where
1077 Piece: From<T>,
1078{
1079 fn into_piece(self, _scratch: &mut RollMut) -> std::io::Result<Piece> {
1080 Ok(self.into())
1081 }
1082}