net_wire/http2/
sequence.rs1use core::fmt;
4
5use super::error::Http2ParseError;
6use super::frame::Http2Frame;
7use super::headers::{Http2Continuation, Http2Headers, Http2PushPromise};
8use super::types::Http2FrameType;
9
10const END_HEADERS: u8 = 0x04;
11
12#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
17pub struct Http2HeaderBlockSequence {
18 locked_stream_id: Option<u32>,
19}
20
21impl Http2HeaderBlockSequence {
22 pub const fn new() -> Self {
24 Self {
25 locked_stream_id: None,
26 }
27 }
28
29 pub const fn is_idle(&self) -> bool {
31 self.locked_stream_id.is_none()
32 }
33
34 pub const fn is_open(&self) -> bool {
36 self.locked_stream_id.is_some()
37 }
38
39 pub const fn locked_stream_id(&self) -> Option<u32> {
41 self.locked_stream_id
42 }
43
44 pub fn observe<'a>(
49 &mut self,
50 frame: Http2Frame<'a>,
51 ) -> Result<Option<Http2HeaderBlockFragment<'a>>, Http2HeaderBlockSequenceError> {
52 if let Some(expected_stream_id) = self.locked_stream_id {
53 return self.observe_open(frame, expected_stream_id);
54 }
55
56 match frame.frame_type() {
57 Http2FrameType::HEADERS => {
58 let headers = Http2Headers::from_frame(frame)
59 .map_err(Http2HeaderBlockSequenceError::MalformedFragment)?;
60 let end_headers = headers.frame().flags() & END_HEADERS != 0;
61 let stream_id = headers.frame().stream_id().value();
62 let fragment = Http2HeaderBlockFragment::Headers(headers);
63 if !end_headers {
64 self.locked_stream_id = Some(stream_id);
65 }
66 Ok(Some(fragment))
67 }
68 Http2FrameType::PUSH_PROMISE => {
69 let push_promise = Http2PushPromise::from_frame(frame)
70 .map_err(Http2HeaderBlockSequenceError::MalformedFragment)?;
71 let end_headers = push_promise.frame().flags() & END_HEADERS != 0;
72 let stream_id = push_promise.frame().stream_id().value();
73 let fragment = Http2HeaderBlockFragment::PushPromise(push_promise);
74 if !end_headers {
75 self.locked_stream_id = Some(stream_id);
76 }
77 Ok(Some(fragment))
78 }
79 Http2FrameType::CONTINUATION => {
80 let continuation = Http2Continuation::from_frame(frame)
81 .map_err(Http2HeaderBlockSequenceError::MalformedFragment)?;
82 Err(Http2HeaderBlockSequenceError::UnexpectedContinuation {
83 actual_stream_id: continuation.frame().stream_id().value(),
84 })
85 }
86 _ => Ok(None),
87 }
88 }
89
90 fn observe_open<'a>(
91 &mut self,
92 frame: Http2Frame<'a>,
93 expected_stream_id: u32,
94 ) -> Result<Option<Http2HeaderBlockFragment<'a>>, Http2HeaderBlockSequenceError> {
95 if frame.frame_type() != Http2FrameType::CONTINUATION {
96 return Err(Http2HeaderBlockSequenceError::InterleavedFrame {
97 expected_stream_id,
98 actual_stream_id: frame.stream_id().value(),
99 actual_frame_type: frame.frame_type(),
100 });
101 }
102
103 let continuation = Http2Continuation::from_frame(frame)
104 .map_err(Http2HeaderBlockSequenceError::MalformedFragment)?;
105 let actual_stream_id = continuation.frame().stream_id().value();
106 if actual_stream_id != expected_stream_id {
107 return Err(Http2HeaderBlockSequenceError::WrongContinuationStream {
108 expected_stream_id,
109 actual_stream_id,
110 });
111 }
112
113 let end_headers = continuation.frame().flags() & END_HEADERS != 0;
114 let fragment = Http2HeaderBlockFragment::Continuation(continuation);
115 if end_headers {
116 self.locked_stream_id = None;
117 }
118 Ok(Some(fragment))
119 }
120}
121
122#[derive(Clone, Copy, Debug, Eq, PartialEq)]
124pub enum Http2HeaderBlockFragment<'a> {
125 Headers(Http2Headers<'a>),
127 PushPromise(Http2PushPromise<'a>),
129 Continuation(Http2Continuation<'a>),
131}
132
133impl<'a> Http2HeaderBlockFragment<'a> {
134 pub const fn frame(&self) -> Http2Frame<'a> {
136 match self {
137 Self::Headers(fragment) => fragment.frame(),
138 Self::PushPromise(fragment) => fragment.frame(),
139 Self::Continuation(fragment) => fragment.frame(),
140 }
141 }
142
143 pub fn field_block_fragment(&self) -> &'a [u8] {
145 match self {
146 Self::Headers(fragment) => fragment.field_block_fragment(),
147 Self::PushPromise(fragment) => fragment.field_block_fragment(),
148 Self::Continuation(fragment) => fragment.field_block_fragment(),
149 }
150 }
151
152 pub fn is_end_headers(&self) -> bool {
154 self.frame().flags() & END_HEADERS != 0
155 }
156}
157
158#[derive(Clone, Copy, Debug, Eq, PartialEq)]
160pub enum Http2HeaderBlockSequenceError {
161 MalformedFragment(Http2ParseError),
163 UnexpectedContinuation {
165 actual_stream_id: u32,
167 },
168 WrongContinuationStream {
170 expected_stream_id: u32,
172 actual_stream_id: u32,
174 },
175 InterleavedFrame {
177 expected_stream_id: u32,
179 actual_stream_id: u32,
181 actual_frame_type: Http2FrameType,
183 },
184}
185
186impl fmt::Display for Http2HeaderBlockSequenceError {
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 match self {
189 Self::MalformedFragment(error) => {
190 write!(f, "malformed HTTP/2 header-block fragment: {error}")
191 }
192 Self::UnexpectedContinuation { actual_stream_id } => write!(
193 f,
194 "unexpected HTTP/2 CONTINUATION on stream {actual_stream_id}"
195 ),
196 Self::WrongContinuationStream {
197 expected_stream_id,
198 actual_stream_id,
199 } => write!(
200 f,
201 "HTTP/2 CONTINUATION stream mismatch: expected {expected_stream_id}, got {actual_stream_id}"
202 ),
203 Self::InterleavedFrame {
204 expected_stream_id,
205 actual_stream_id,
206 actual_frame_type,
207 } => write!(
208 f,
209 "HTTP/2 header block on stream {expected_stream_id} was interrupted by frame type {} on stream {actual_stream_id}",
210 actual_frame_type.raw()
211 ),
212 }
213 }
214}