Skip to main content

sark_http/h1/field/
value.rs

1use crate::field::{self, scan};
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq)]
4pub enum Error {
5    Empty,
6    InvalidByte,
7    Overflow,
8    InvalidOrdering,
9}
10
11#[derive(Clone, Copy, PartialEq, Eq)]
12pub(super) enum Match {
13    Taken,
14    Other,
15}
16
17pub(super) struct Parser<'a> {
18    value: &'a [u8],
19}
20
21impl<'a> Parser<'a> {
22    pub(super) const fn new(value: &'a [u8]) -> Self {
23        Self { value }
24    }
25
26    pub(super) fn skip_ows(&mut self) {
27        while let Some((b' ' | b'\t', tail)) = self.value.split_first() {
28            self.value = tail;
29        }
30    }
31
32    pub(super) fn is_done(&self) -> bool {
33        self.value.is_empty()
34    }
35
36    pub(super) fn take(&mut self, byte: u8) -> Match {
37        let Some((&first, tail)) = self.value.split_first() else {
38            return Match::Other;
39        };
40        if first != byte {
41            return Match::Other;
42        }
43        self.value = tail;
44        Match::Taken
45    }
46
47    pub(super) fn token(&mut self) -> Result<&'a [u8], Error> {
48        let (token, tail) =
49            match scan::Match::find_by(self.value, |byte| !field::Error::is_name_byte(byte)) {
50                Some(end) => (end.prefix(), end.tail()),
51                None => (self.value, &self.value[self.value.len()..]),
52            };
53        if token.is_empty() {
54            return Err(if self.is_done() {
55                Error::Empty
56            } else {
57                Error::InvalidByte
58            });
59        }
60        self.value = tail;
61        Ok(token)
62    }
63
64    pub(super) fn item(&mut self) -> Result<(), Error> {
65        let Some((b'"', tail)) = self.value.split_first() else {
66            self.token()?;
67            return Ok(());
68        };
69        let mut bytes = tail.iter();
70        while let Some(&byte) = bytes.next() {
71            match byte {
72                b'"' => {
73                    self.value = bytes.as_slice();
74                    return Ok(());
75                }
76                b'\\' => {
77                    let escaped = bytes.next().ok_or(Error::InvalidByte)?;
78                    if !matches!(escaped, b'\t' | b' ' | 0x21..=0x7e | 0x80..=0xff) {
79                        return Err(Error::InvalidByte);
80                    }
81                }
82                b'\t' | b' ' | b'!' | 0x23..=0x5b | 0x5d..=0x7e | 0x80..=0xff => {}
83                0..=8 | 10..=31 | 0x7f => return Err(Error::InvalidByte),
84            }
85        }
86        Err(Error::InvalidByte)
87    }
88}