1use core::fmt;
4
5use crate::quic::varint::QuicVarIntLen;
6
7use super::super::codepoints::{Http3ErrorCode, Http3StreamType};
8use super::super::enums::stream::{Http3EndpointRole, Http3UniStreamKind};
9use super::super::ids::{Http3PushId, Http3StreamId};
10use super::uni::Http3UniStreamHeader;
11
12#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14pub enum Http3CriticalUniStreamKind {
15 Control,
17 QpackEncoder,
19 QpackDecoder,
21}
22
23#[derive(Clone, Copy, Debug, Eq, PartialEq)]
29pub enum Http3PeerUniStreamEvent {
30 Control {
32 stream_id: Http3StreamId,
34 },
35 Push {
37 stream_id: Http3StreamId,
39 push_id: Http3PushId,
41 },
42 QpackEncoder {
44 stream_id: Http3StreamId,
46 },
47 QpackDecoder {
49 stream_id: Http3StreamId,
51 },
52 Unknown {
54 stream_id: Http3StreamId,
56 stream_type: Http3StreamType,
58 },
59}
60
61#[derive(Clone, Copy, Debug, Eq, PartialEq)]
66pub enum Http3PeerUniStreamError {
67 InvalidPeerUnidirectionalStream {
69 stream_id: Http3StreamId,
71 },
72 DuplicateCriticalStream {
74 kind: Http3CriticalUniStreamKind,
76 existing: Http3StreamId,
78 received: Http3StreamId,
80 },
81 ClientInitiatedPushStream {
83 stream_id: Http3StreamId,
85 push_id: Http3PushId,
87 },
88 ClosedCriticalStream {
90 kind: Http3CriticalUniStreamKind,
92 stream_id: Http3StreamId,
94 },
95}
96
97impl Http3PeerUniStreamError {
98 pub const fn error_code(self) -> Option<Http3ErrorCode> {
100 match self {
101 Self::InvalidPeerUnidirectionalStream { .. } => None,
102 Self::DuplicateCriticalStream { .. } | Self::ClientInitiatedPushStream { .. } => {
103 Some(Http3ErrorCode::STREAM_CREATION_ERROR)
104 }
105 Self::ClosedCriticalStream { .. } => Some(Http3ErrorCode::CLOSED_CRITICAL_STREAM),
106 }
107 }
108}
109
110impl fmt::Display for Http3PeerUniStreamError {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 match self {
113 Self::InvalidPeerUnidirectionalStream { stream_id } => write!(
114 f,
115 "stream ID {} is not a peer-initiated unidirectional QUIC stream",
116 stream_id.value()
117 ),
118 Self::DuplicateCriticalStream {
119 kind,
120 existing,
121 received,
122 } => write!(
123 f,
124 "HTTP/3 {kind:?} critical stream {} duplicates stream {}",
125 received.value(),
126 existing.value()
127 ),
128 Self::ClientInitiatedPushStream { stream_id, push_id } => write!(
129 f,
130 "client-initiated HTTP/3 push stream {} carries Push ID {}",
131 stream_id.value(),
132 push_id.value()
133 ),
134 Self::ClosedCriticalStream { kind, stream_id } => write!(
135 f,
136 "HTTP/3 {kind:?} critical stream {} was closed",
137 stream_id.value()
138 ),
139 }
140 }
141}
142
143impl core::error::Error for Http3PeerUniStreamError {}
144
145#[derive(Clone, Copy, Debug, Eq, PartialEq)]
151pub struct Http3PeerUniStreamState {
152 local_role: Http3EndpointRole,
153 control: Option<Http3StreamId>,
154 qpack_encoder: Option<Http3StreamId>,
155 qpack_decoder: Option<Http3StreamId>,
156}
157
158impl Http3PeerUniStreamState {
159 pub const fn new(local_role: Http3EndpointRole) -> Self {
161 Self {
162 local_role,
163 control: None,
164 qpack_encoder: None,
165 qpack_decoder: None,
166 }
167 }
168
169 pub const fn role(self) -> Http3EndpointRole {
171 self.local_role
172 }
173
174 pub const fn control_stream_id(self) -> Option<Http3StreamId> {
176 self.control
177 }
178
179 pub const fn qpack_encoder_stream_id(self) -> Option<Http3StreamId> {
181 self.qpack_encoder
182 }
183
184 pub const fn qpack_decoder_stream_id(self) -> Option<Http3StreamId> {
186 self.qpack_decoder
187 }
188
189 pub fn receive_header(
194 &mut self,
195 stream_id: Http3StreamId,
196 header: Http3UniStreamHeader<'_>,
197 ) -> Result<Http3PeerUniStreamEvent, Http3PeerUniStreamError> {
198 self.validate_peer_unidirectional_stream_id(stream_id)?;
199
200 match header.kind() {
201 Http3UniStreamKind::Control => {
202 self.receive_critical(stream_id, Http3CriticalUniStreamKind::Control)
203 }
204 Http3UniStreamKind::QpackEncoder => {
205 self.receive_critical(stream_id, Http3CriticalUniStreamKind::QpackEncoder)
206 }
207 Http3UniStreamKind::QpackDecoder => {
208 self.receive_critical(stream_id, Http3CriticalUniStreamKind::QpackDecoder)
209 }
210 Http3UniStreamKind::Push(push_id) => {
211 if self.local_role == Http3EndpointRole::Server {
212 return Err(Http3PeerUniStreamError::ClientInitiatedPushStream {
213 stream_id,
214 push_id,
215 });
216 }
217 Ok(Http3PeerUniStreamEvent::Push { stream_id, push_id })
218 }
219 Http3UniStreamKind::Unknown(stream_type) => Ok(Http3PeerUniStreamEvent::Unknown {
220 stream_id,
221 stream_type,
222 }),
223 }
224 }
225
226 pub fn receive_closed(self, stream_id: Http3StreamId) -> Result<(), Http3PeerUniStreamError> {
232 if self.control == Some(stream_id) {
233 return Err(Http3PeerUniStreamError::ClosedCriticalStream {
234 kind: Http3CriticalUniStreamKind::Control,
235 stream_id,
236 });
237 }
238 if self.qpack_encoder == Some(stream_id) {
239 return Err(Http3PeerUniStreamError::ClosedCriticalStream {
240 kind: Http3CriticalUniStreamKind::QpackEncoder,
241 stream_id,
242 });
243 }
244 if self.qpack_decoder == Some(stream_id) {
245 return Err(Http3PeerUniStreamError::ClosedCriticalStream {
246 kind: Http3CriticalUniStreamKind::QpackDecoder,
247 stream_id,
248 });
249 }
250 Ok(())
251 }
252
253 fn validate_peer_unidirectional_stream_id(
254 self,
255 stream_id: Http3StreamId,
256 ) -> Result<(), Http3PeerUniStreamError> {
257 let value = stream_id.value();
258 let expected_low_bits = match self.local_role {
259 Http3EndpointRole::Client => 0x03,
260 Http3EndpointRole::Server => 0x02,
261 };
262 if value > QuicVarIntLen::Eight.max_value() || value & 0x03 != expected_low_bits {
263 return Err(Http3PeerUniStreamError::InvalidPeerUnidirectionalStream { stream_id });
264 }
265 Ok(())
266 }
267
268 fn receive_critical(
269 &mut self,
270 stream_id: Http3StreamId,
271 kind: Http3CriticalUniStreamKind,
272 ) -> Result<Http3PeerUniStreamEvent, Http3PeerUniStreamError> {
273 let existing = match kind {
274 Http3CriticalUniStreamKind::Control => self.control,
275 Http3CriticalUniStreamKind::QpackEncoder => self.qpack_encoder,
276 Http3CriticalUniStreamKind::QpackDecoder => self.qpack_decoder,
277 };
278 if let Some(existing) = existing {
279 return Err(Http3PeerUniStreamError::DuplicateCriticalStream {
280 kind,
281 existing,
282 received: stream_id,
283 });
284 }
285
286 match kind {
287 Http3CriticalUniStreamKind::Control => {
288 self.control = Some(stream_id);
289 Ok(Http3PeerUniStreamEvent::Control { stream_id })
290 }
291 Http3CriticalUniStreamKind::QpackEncoder => {
292 self.qpack_encoder = Some(stream_id);
293 Ok(Http3PeerUniStreamEvent::QpackEncoder { stream_id })
294 }
295 Http3CriticalUniStreamKind::QpackDecoder => {
296 self.qpack_decoder = Some(stream_id);
297 Ok(Http3PeerUniStreamEvent::QpackDecoder { stream_id })
298 }
299 }
300 }
301}