1mod builder;
4
5use core::fmt;
6
7use crate::qpack::integer::{QpackInteger, QpackIntegerParseError};
8use crate::qpack::string::{QpackStringLiteral, QpackStringLiteralParseError};
9pub use builder::{
10 QpackFieldLineBuildError, QpackIndexedFieldLineBuilder, QpackIndexedPostBaseFieldLineBuilder,
11 QpackLiteralNameFieldLineBuilder, QpackLiteralNameReferenceFieldLineBuilder,
12 QpackLiteralPostBaseNameReferenceFieldLineBuilder,
13};
14pub(crate) use builder::{QpackFieldLinePlan, QpackFieldLinePlanInput, plan_field_line};
15
16#[derive(Clone, Copy, Debug, Eq, PartialEq)]
18pub enum QpackFieldLine<'a> {
19 Indexed(QpackIndexedFieldLine<'a>),
21 IndexedPostBase(QpackIndexedPostBaseFieldLine<'a>),
23 LiteralNameReference(QpackLiteralNameReferenceFieldLine<'a>),
25 LiteralPostBaseNameReference(QpackLiteralPostBaseNameReferenceFieldLine<'a>),
27 LiteralName(QpackLiteralNameFieldLine<'a>),
29}
30
31impl<'a> QpackFieldLine<'a> {
32 pub fn parse(bytes: &'a [u8]) -> Result<Self, QpackFieldLineParseError> {
34 let first = *bytes
35 .first()
36 .ok_or(QpackFieldLineParseError::DispatchIncomplete)?;
37
38 if first & 0x80 != 0 {
39 let index =
40 QpackInteger::parse(bytes, 6).map_err(QpackFieldLineParseError::IndexedIndex)?;
41 return Ok(Self::Indexed(QpackIndexedFieldLine {
42 bytes: index.as_bytes(),
43 index,
44 }));
45 }
46
47 if first & 0xc0 == 0x40 {
48 let name_index = QpackInteger::parse(bytes, 4)
49 .map_err(QpackFieldLineParseError::LiteralNameReferenceNameIndex)?;
50 let name_length = name_index.as_bytes().len();
51 let value_bytes = bytes
52 .get(name_length..)
53 .ok_or(QpackFieldLineParseError::RequiredLengthOverflow)?;
54 let value = QpackStringLiteral::parse(value_bytes, 8)
55 .map_err(QpackFieldLineParseError::LiteralNameReferenceValue)?;
56 let length = name_length
57 .checked_add(value.as_bytes().len())
58 .ok_or(QpackFieldLineParseError::RequiredLengthOverflow)?;
59 let line_bytes = bytes
60 .get(..length)
61 .ok_or(QpackFieldLineParseError::RequiredLengthOverflow)?;
62 return Ok(Self::LiteralNameReference(
63 QpackLiteralNameReferenceFieldLine {
64 bytes: line_bytes,
65 name_index,
66 value,
67 },
68 ));
69 }
70
71 if first & 0xe0 == 0x20 {
72 let name = QpackStringLiteral::parse(bytes, 4)
73 .map_err(QpackFieldLineParseError::LiteralNameName)?;
74 let name_length = name.as_bytes().len();
75 let value_bytes = bytes
76 .get(name_length..)
77 .ok_or(QpackFieldLineParseError::RequiredLengthOverflow)?;
78 let value = QpackStringLiteral::parse(value_bytes, 8)
79 .map_err(QpackFieldLineParseError::LiteralNameValue)?;
80 let length = name_length
81 .checked_add(value.as_bytes().len())
82 .ok_or(QpackFieldLineParseError::RequiredLengthOverflow)?;
83 let line_bytes = bytes
84 .get(..length)
85 .ok_or(QpackFieldLineParseError::RequiredLengthOverflow)?;
86 return Ok(Self::LiteralName(QpackLiteralNameFieldLine {
87 bytes: line_bytes,
88 name,
89 value,
90 }));
91 }
92
93 if first & 0xf0 == 0x10 {
94 let index = QpackInteger::parse(bytes, 4)
95 .map_err(QpackFieldLineParseError::IndexedPostBaseIndex)?;
96 return Ok(Self::IndexedPostBase(QpackIndexedPostBaseFieldLine {
97 bytes: index.as_bytes(),
98 index,
99 }));
100 }
101
102 let name_index = QpackInteger::parse(bytes, 3)
103 .map_err(QpackFieldLineParseError::LiteralPostBaseNameReferenceNameIndex)?;
104 let name_length = name_index.as_bytes().len();
105 let value_bytes = bytes
106 .get(name_length..)
107 .ok_or(QpackFieldLineParseError::RequiredLengthOverflow)?;
108 let value = QpackStringLiteral::parse(value_bytes, 8)
109 .map_err(QpackFieldLineParseError::LiteralPostBaseNameReferenceValue)?;
110 let length = name_length
111 .checked_add(value.as_bytes().len())
112 .ok_or(QpackFieldLineParseError::RequiredLengthOverflow)?;
113 let line_bytes = bytes
114 .get(..length)
115 .ok_or(QpackFieldLineParseError::RequiredLengthOverflow)?;
116 Ok(Self::LiteralPostBaseNameReference(
117 QpackLiteralPostBaseNameReferenceFieldLine {
118 bytes: line_bytes,
119 name_index,
120 value,
121 },
122 ))
123 }
124
125 pub const fn as_bytes(self) -> &'a [u8] {
127 match self {
128 Self::Indexed(line) => line.as_bytes(),
129 Self::IndexedPostBase(line) => line.as_bytes(),
130 Self::LiteralNameReference(line) => line.as_bytes(),
131 Self::LiteralPostBaseNameReference(line) => line.as_bytes(),
132 Self::LiteralName(line) => line.as_bytes(),
133 }
134 }
135}
136
137#[derive(Clone, Copy, Debug, Eq, PartialEq)]
139pub struct QpackIndexedFieldLine<'a> {
140 bytes: &'a [u8],
141 index: QpackInteger<'a>,
142}
143
144impl<'a> QpackIndexedFieldLine<'a> {
145 pub const fn as_bytes(self) -> &'a [u8] {
147 self.bytes
148 }
149 pub const fn is_static(self) -> bool {
151 self.bytes[0] & 0x40 != 0
152 }
153 pub const fn index(self) -> QpackInteger<'a> {
155 self.index
156 }
157}
158
159#[derive(Clone, Copy, Debug, Eq, PartialEq)]
161pub struct QpackIndexedPostBaseFieldLine<'a> {
162 bytes: &'a [u8],
163 index: QpackInteger<'a>,
164}
165
166impl<'a> QpackIndexedPostBaseFieldLine<'a> {
167 pub const fn as_bytes(self) -> &'a [u8] {
169 self.bytes
170 }
171 pub const fn index(self) -> QpackInteger<'a> {
173 self.index
174 }
175}
176
177#[derive(Clone, Copy, Debug, Eq, PartialEq)]
179pub struct QpackLiteralNameReferenceFieldLine<'a> {
180 bytes: &'a [u8],
181 name_index: QpackInteger<'a>,
182 value: QpackStringLiteral<'a>,
183}
184
185impl<'a> QpackLiteralNameReferenceFieldLine<'a> {
186 pub const fn as_bytes(self) -> &'a [u8] {
188 self.bytes
189 }
190 pub const fn is_never_indexed(self) -> bool {
192 self.bytes[0] & 0x20 != 0
193 }
194 pub const fn is_static(self) -> bool {
196 self.bytes[0] & 0x10 != 0
197 }
198 pub const fn name_index(self) -> QpackInteger<'a> {
200 self.name_index
201 }
202 pub const fn value(self) -> QpackStringLiteral<'a> {
204 self.value
205 }
206}
207
208#[derive(Clone, Copy, Debug, Eq, PartialEq)]
210pub struct QpackLiteralPostBaseNameReferenceFieldLine<'a> {
211 bytes: &'a [u8],
212 name_index: QpackInteger<'a>,
213 value: QpackStringLiteral<'a>,
214}
215
216impl<'a> QpackLiteralPostBaseNameReferenceFieldLine<'a> {
217 pub const fn as_bytes(self) -> &'a [u8] {
219 self.bytes
220 }
221 pub const fn is_never_indexed(self) -> bool {
223 self.bytes[0] & 0x08 != 0
224 }
225 pub const fn name_index(self) -> QpackInteger<'a> {
227 self.name_index
228 }
229 pub const fn value(self) -> QpackStringLiteral<'a> {
231 self.value
232 }
233}
234
235#[derive(Clone, Copy, Debug, Eq, PartialEq)]
237pub struct QpackLiteralNameFieldLine<'a> {
238 bytes: &'a [u8],
239 name: QpackStringLiteral<'a>,
240 value: QpackStringLiteral<'a>,
241}
242
243impl<'a> QpackLiteralNameFieldLine<'a> {
244 pub const fn as_bytes(self) -> &'a [u8] {
246 self.bytes
247 }
248 pub const fn is_never_indexed(self) -> bool {
250 self.bytes[0] & 0x10 != 0
251 }
252 pub const fn name(self) -> QpackStringLiteral<'a> {
254 self.name
255 }
256 pub const fn value(self) -> QpackStringLiteral<'a> {
258 self.value
259 }
260}
261
262#[derive(Clone, Copy, Debug, Eq, PartialEq)]
264pub enum QpackFieldLineParseError {
265 DispatchIncomplete,
267 IndexedIndex(#[doc = "The integer parsing error."] QpackIntegerParseError),
269 IndexedPostBaseIndex(#[doc = "The integer parsing error."] QpackIntegerParseError),
271 LiteralNameReferenceNameIndex(#[doc = "The integer parsing error."] QpackIntegerParseError),
273 LiteralNameReferenceValue(
275 #[doc = "The string-literal parsing error."] QpackStringLiteralParseError,
276 ),
277 LiteralPostBaseNameReferenceNameIndex(
279 #[doc = "The integer parsing error."] QpackIntegerParseError,
280 ),
281 LiteralPostBaseNameReferenceValue(
283 #[doc = "The string-literal parsing error."] QpackStringLiteralParseError,
284 ),
285 LiteralNameName(#[doc = "The string-literal parsing error."] QpackStringLiteralParseError),
287 LiteralNameValue(#[doc = "The string-literal parsing error."] QpackStringLiteralParseError),
289 RequiredLengthOverflow,
291}
292
293impl fmt::Display for QpackFieldLineParseError {
294 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
295 match self {
296 Self::DispatchIncomplete => formatter.write_str("QPACK field line is incomplete"),
297 Self::IndexedIndex(error) => {
298 write!(formatter, "invalid indexed field line index: {error}")
299 }
300 Self::IndexedPostBaseIndex(error) => write!(
301 formatter,
302 "invalid indexed post-base field line index: {error}"
303 ),
304 Self::LiteralNameReferenceNameIndex(error) => {
305 write!(formatter, "invalid literal name-reference index: {error}")
306 }
307 Self::LiteralNameReferenceValue(error) => {
308 write!(formatter, "invalid literal name-reference value: {error}")
309 }
310 Self::LiteralPostBaseNameReferenceNameIndex(error) => write!(
311 formatter,
312 "invalid literal post-base name-reference index: {error}"
313 ),
314 Self::LiteralPostBaseNameReferenceValue(error) => write!(
315 formatter,
316 "invalid literal post-base name-reference value: {error}"
317 ),
318 Self::LiteralNameName(error) => {
319 write!(formatter, "invalid literal field name: {error}")
320 }
321 Self::LiteralNameValue(error) => {
322 write!(formatter, "invalid literal field value: {error}")
323 }
324 Self::RequiredLengthOverflow => formatter.write_str("QPACK field line length overflow"),
325 }
326 }
327}
328
329#[derive(Clone, Copy, Debug, Eq, PartialEq)]
331pub struct QpackFieldLines<'a> {
332 bytes: &'a [u8],
333}
334
335impl<'a> QpackFieldLines<'a> {
336 pub fn parse(bytes: &'a [u8]) -> Result<Self, QpackFieldLinesParseError> {
338 let mut remaining = bytes;
339 while !remaining.is_empty() {
340 let line = match QpackFieldLine::parse(remaining) {
341 Ok(line) => line,
342 Err(error) => {
343 return Err(QpackFieldLinesParseError {
344 offset: bytes.len() - remaining.len(),
345 error,
346 });
347 }
348 };
349 remaining = &remaining[line.as_bytes().len()..];
350 }
351 Ok(Self { bytes })
352 }
353
354 pub const fn as_bytes(self) -> &'a [u8] {
356 self.bytes
357 }
358
359 pub const fn iter(self) -> QpackFieldLineIter<'a> {
361 QpackFieldLineIter::new(self.bytes)
362 }
363}
364
365#[derive(Clone, Copy, Debug, Eq, PartialEq)]
367pub struct QpackFieldLinesParseError {
368 offset: usize,
369 error: QpackFieldLineParseError,
370}
371
372impl QpackFieldLinesParseError {
373 pub const fn offset(self) -> usize {
375 self.offset
376 }
377
378 pub const fn error(self) -> QpackFieldLineParseError {
380 self.error
381 }
382}
383
384impl fmt::Display for QpackFieldLinesParseError {
385 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
386 write!(
387 formatter,
388 "QPACK field line at offset {}: {}",
389 self.offset, self.error
390 )
391 }
392}
393
394#[derive(Clone, Debug)]
396pub struct QpackFieldLineIter<'a> {
397 remaining: &'a [u8],
398 failed: bool,
399}
400
401impl<'a> QpackFieldLineIter<'a> {
402 pub const fn new(bytes: &'a [u8]) -> Self {
404 Self {
405 remaining: bytes,
406 failed: false,
407 }
408 }
409}
410
411impl<'a> Iterator for QpackFieldLineIter<'a> {
412 type Item = Result<QpackFieldLine<'a>, QpackFieldLineParseError>;
413
414 fn next(&mut self) -> Option<Self::Item> {
415 if self.failed || self.remaining.is_empty() {
416 return None;
417 }
418 match QpackFieldLine::parse(self.remaining) {
419 Ok(line) => {
420 self.remaining = &self.remaining[line.as_bytes().len()..];
421 Some(Ok(line))
422 }
423 Err(error) => {
424 self.remaining = &[];
425 self.failed = true;
426 Some(Err(error))
427 }
428 }
429 }
430}
431
432impl core::iter::FusedIterator for QpackFieldLineIter<'_> {}