1use core::fmt;
4
5use crate::quic::varint::{
6 QuicVarInt, QuicVarIntBuildError, QuicVarIntBuilder, QuicVarIntLen, QuicVarIntParseError,
7};
8
9use super::super::codepoints::Http3StreamType;
10use super::super::enums::stream::Http3UniStreamKind;
11use super::super::ids::Http3PushId;
12
13#[derive(Clone, Copy, Debug, Eq, PartialEq)]
15pub enum Http3UniStreamField {
16 StreamType,
18 PushId,
20}
21
22impl fmt::Display for Http3UniStreamField {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 match self {
25 Self::StreamType => f.write_str("stream type"),
26 Self::PushId => f.write_str("Push ID"),
27 }
28 }
29}
30
31#[derive(Clone, Copy, Debug, Eq, PartialEq)]
33pub enum Http3UniStreamParseError {
34 VarInt {
36 field: Http3UniStreamField,
38 offset: usize,
40 error: QuicVarIntParseError,
42 },
43}
44
45impl fmt::Display for Http3UniStreamParseError {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 match self {
48 Self::VarInt {
49 field,
50 offset,
51 error,
52 } => write!(
53 f,
54 "HTTP/3 unidirectional stream {field} variable-length integer at offset {offset}: {error}"
55 ),
56 }
57 }
58}
59
60impl core::error::Error for Http3UniStreamParseError {}
61
62#[derive(Clone, Copy, Debug, Eq, PartialEq)]
67pub struct Http3UniStreamHeader<'a> {
68 bytes: &'a [u8],
69 stream_type: QuicVarInt<'a>,
70 push_id: Option<QuicVarInt<'a>>,
71}
72
73impl<'a> Http3UniStreamHeader<'a> {
74 pub fn parse(bytes: &'a [u8]) -> Result<Self, Http3UniStreamParseError> {
76 let stream_type =
77 QuicVarInt::parse(bytes).map_err(|error| Http3UniStreamParseError::VarInt {
78 field: Http3UniStreamField::StreamType,
79 offset: 0,
80 error,
81 })?;
82 let stream_type_length = stream_type.byte_len();
83 let push_id = if stream_type.value() == Http3StreamType::PUSH.value() {
84 Some(
85 QuicVarInt::parse(&bytes[stream_type_length..]).map_err(|error| {
86 Http3UniStreamParseError::VarInt {
87 field: Http3UniStreamField::PushId,
88 offset: stream_type_length,
89 error,
90 }
91 })?,
92 )
93 } else {
94 None
95 };
96 let header_length = match push_id {
97 Some(push_id) => stream_type_length + push_id.byte_len(),
98 None => stream_type_length,
99 };
100 Ok(Self::from_validated(
101 &bytes[..header_length],
102 stream_type.value(),
103 stream_type.encoded_len(),
104 push_id.map(|value| (value.value(), value.encoded_len())),
105 ))
106 }
107
108 pub const fn kind(self) -> Http3UniStreamKind {
110 match self.stream_type.value() {
111 0 => Http3UniStreamKind::Control,
112 1 => match self.push_id {
113 Some(push_id) => Http3UniStreamKind::Push(Http3PushId::new(push_id.value())),
114 None => Http3UniStreamKind::Unknown(Http3StreamType::PUSH),
115 },
116 2 => Http3UniStreamKind::QpackEncoder,
117 3 => Http3UniStreamKind::QpackDecoder,
118 value => Http3UniStreamKind::Unknown(Http3StreamType::new(value)),
119 }
120 }
121
122 pub const fn stream_type(self) -> Http3StreamType {
124 Http3StreamType::new(self.stream_type.value())
125 }
126
127 pub const fn stream_type_varint(self) -> QuicVarInt<'a> {
129 self.stream_type
130 }
131
132 pub const fn push_id(self) -> Option<Http3PushId> {
134 match self.push_id {
135 Some(push_id) => Some(Http3PushId::new(push_id.value())),
136 None => None,
137 }
138 }
139
140 pub const fn push_id_varint(self) -> Option<QuicVarInt<'a>> {
142 self.push_id
143 }
144
145 pub const fn as_bytes(self) -> &'a [u8] {
147 self.bytes
148 }
149
150 pub(super) fn from_validated(
152 bytes: &'a [u8],
153 stream_type_value: u64,
154 stream_type_length: QuicVarIntLen,
155 push_id: Option<(u64, QuicVarIntLen)>,
156 ) -> Self {
157 let stream_type_length_bytes = stream_type_length.byte_len();
158 let stream_type = QuicVarInt::from_validated(
159 &bytes[..stream_type_length_bytes],
160 stream_type_value,
161 stream_type_length,
162 );
163 let push_id = push_id.map(|(value, length)| {
164 let start = stream_type_length_bytes;
165 QuicVarInt::from_validated(&bytes[start..start + length.byte_len()], value, length)
166 });
167 Self {
168 bytes,
169 stream_type,
170 push_id,
171 }
172 }
173}
174
175#[derive(Clone, Copy, Debug, Eq, PartialEq)]
177pub enum Http3UniStreamBuildError {
178 VarInt {
180 field: Http3UniStreamField,
182 error: QuicVarIntBuildError,
184 },
185 LengthOverflow {
187 first: usize,
189 second: usize,
191 },
192 BufferTooShort {
194 required: usize,
196 available: usize,
198 },
199 KnownTypeMarkedUnknown {
201 stream_type: Http3StreamType,
203 },
204}
205
206impl fmt::Display for Http3UniStreamBuildError {
207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208 match self {
209 Self::VarInt { field, error } => {
210 write!(
211 f,
212 "HTTP/3 unidirectional stream {field} variable-length integer: {error}"
213 )
214 }
215 Self::LengthOverflow { first, second } => write!(
216 f,
217 "HTTP/3 unidirectional stream header length overflows: {first} plus {second} bytes"
218 ),
219 Self::BufferTooShort {
220 required,
221 available,
222 } => write!(
223 f,
224 "HTTP/3 unidirectional stream destination is too short: need {required} bytes, have {available}"
225 ),
226 Self::KnownTypeMarkedUnknown { stream_type } => write!(
227 f,
228 "HTTP/3 known unidirectional stream type {} cannot be marked unknown",
229 stream_type.value()
230 ),
231 }
232 }
233}
234
235impl core::error::Error for Http3UniStreamBuildError {}
236
237pub struct Http3UniStreamHeaderBuilder<'output> {
239 destination: &'output mut [u8],
240 kind: Http3UniStreamKind,
241}
242
243impl<'output> Http3UniStreamHeaderBuilder<'output> {
244 pub fn new(destination: &'output mut [u8], kind: Http3UniStreamKind) -> Self {
246 Self { destination, kind }
247 }
248
249 pub fn build(self) -> Result<Http3UniStreamHeader<'output>, Http3UniStreamBuildError> {
251 let (stream_type, push_id) = stream_fields(self.kind)?;
252 let stream_type = encode_varint(stream_type.value(), Http3UniStreamField::StreamType)?;
253 let push_id = match push_id {
254 Some(push_id) => Some(encode_varint(push_id, Http3UniStreamField::PushId)?),
255 None => None,
256 };
257 let required = match push_id {
258 Some(push_id) => stream_type
259 .length
260 .byte_len()
261 .checked_add(push_id.length.byte_len())
262 .ok_or(Http3UniStreamBuildError::LengthOverflow {
263 first: stream_type.length.byte_len(),
264 second: push_id.length.byte_len(),
265 })?,
266 None => stream_type.length.byte_len(),
267 };
268 if self.destination.len() < required {
269 return Err(Http3UniStreamBuildError::BufferTooShort {
270 required,
271 available: self.destination.len(),
272 });
273 }
274
275 let bytes = &mut self.destination[..required];
276 let stream_type_length = stream_type.length.byte_len();
277 bytes[..stream_type_length].copy_from_slice(stream_type.bytes());
278 if let Some(push_id) = push_id {
279 bytes[stream_type_length..].copy_from_slice(push_id.bytes());
280 }
281 Ok(Http3UniStreamHeader::from_validated(
282 bytes,
283 stream_type.value,
284 stream_type.length,
285 push_id.map(|push_id| (push_id.value, push_id.length)),
286 ))
287 }
288}
289
290#[derive(Clone, Copy)]
291struct EncodedVarInt {
292 bytes: [u8; 8],
293 value: u64,
294 length: QuicVarIntLen,
295}
296
297impl EncodedVarInt {
298 fn bytes(&self) -> &[u8] {
299 &self.bytes[..self.length.byte_len()]
300 }
301}
302
303fn stream_fields(
304 kind: Http3UniStreamKind,
305) -> Result<(Http3StreamType, Option<u64>), Http3UniStreamBuildError> {
306 match kind {
307 Http3UniStreamKind::Control => Ok((Http3StreamType::CONTROL, None)),
308 Http3UniStreamKind::Push(push_id) => Ok((Http3StreamType::PUSH, Some(push_id.value()))),
309 Http3UniStreamKind::QpackEncoder => Ok((Http3StreamType::QPACK_ENCODER, None)),
310 Http3UniStreamKind::QpackDecoder => Ok((Http3StreamType::QPACK_DECODER, None)),
311 Http3UniStreamKind::Unknown(stream_type) => {
312 if matches!(stream_type.value(), 0..=3) {
313 Err(Http3UniStreamBuildError::KnownTypeMarkedUnknown { stream_type })
314 } else {
315 Ok((stream_type, None))
316 }
317 }
318 }
319}
320
321fn encode_varint(
322 value: u64,
323 field: Http3UniStreamField,
324) -> Result<EncodedVarInt, Http3UniStreamBuildError> {
325 let mut bytes = [0; 8];
326 let varint = QuicVarIntBuilder::new(&mut bytes, value)
327 .build()
328 .map_err(|error| Http3UniStreamBuildError::VarInt { field, error })?;
329 let length = varint.encoded_len();
330 Ok(EncodedVarInt {
331 bytes,
332 value,
333 length,
334 })
335}