Skip to main content

sark_http/field/head/
headers.rs

1use core::mem;
2
3use crate::{
4    field::{
5        head::{Error, Flags, Name, parse},
6        text::Ascii,
7    },
8    h1::{
9        field,
10        head::{line::Version, request},
11    },
12};
13
14#[derive(Clone, Copy, PartialEq, Eq)]
15pub enum Known {
16    AcceptEncoding,
17    ContentLength,
18    TransferEncoding,
19    Expect,
20    Host,
21    Connection,
22    Upgrade,
23}
24
25#[derive(Clone, Copy, PartialEq, Eq)]
26pub struct Bounds {
27    tail: usize,
28    start: usize,
29    end: usize,
30}
31
32impl Bounds {
33    pub(super) const fn new(tail: usize, start: usize, end: usize) -> Self {
34        Self { tail, start, end }
35    }
36
37    pub const fn tail(self) -> usize {
38        self.tail
39    }
40
41    pub const fn start(self) -> usize {
42        self.start
43    }
44
45    pub const fn end(self) -> usize {
46        self.end
47    }
48
49    pub(super) fn value(self, raw: &[u8]) -> &[u8] {
50        // SAFETY: private parser continuations use the same immutable raw that
51        // just produced these bounds. No caller substitutes another source.
52        unsafe { raw.get_unchecked(self.start..self.end) }
53    }
54}
55
56const _: () = {
57    assert!(mem::size_of::<Bounds>() == 3 * mem::size_of::<usize>());
58    assert!(mem::size_of::<Option<Bounds>>() == 4 * mem::size_of::<usize>());
59    assert!(!mem::needs_drop::<Bounds>());
60};
61
62fn parse_connection(raw: &[u8]) -> Result<field::Connection, Error> {
63    field::Connection::default()
64        .try_push(raw)
65        .map_err(Error::Connection)
66}
67
68impl Known {
69    const PREFIX_INITIALS: u32 = {
70        let mut initials = 0;
71        let mut index = 0;
72        while index < Name::H1.len() {
73            let first = Name::H1[index].wire()[0];
74            assert!(first.is_ascii_lowercase(), "initial");
75            initials |= 1 << (first - b'a');
76            index += 1;
77        }
78        initials
79    };
80
81    pub fn from_name(name: &[u8]) -> Option<Self> {
82        Self::from_kind(Name::from_h1(name)?)
83    }
84
85    /// Recognizes a complete canonical field name and its following colon.
86    /// The exact literal match also establishes the name's token grammar.
87    pub fn from_prefix(raw: &[u8]) -> Option<(Self, usize)> {
88        let first = raw.first()?.to_ascii_lowercase();
89        let initial = 1u32.checked_shl(u32::from(first.wrapping_sub(b'a')))?;
90        if Self::PREFIX_INITIALS & initial == 0 {
91            return None;
92        }
93        for name in Name::H1 {
94            let wire = name.wire();
95            if wire.first() == Some(&first)
96                && raw.get(wire.len()) == Some(&b':')
97                && raw[..wire.len()].eq_ignore_ascii_case(wire)
98            {
99                return Self::from_kind(name).map(|known| (known, wire.len()));
100            }
101        }
102        None
103    }
104
105    fn from_kind(name: Name) -> Option<Self> {
106        match name {
107            Name::AcceptEncoding => Some(Self::AcceptEncoding),
108            Name::ContentLength => Some(Self::ContentLength),
109            Name::TransferEncoding => Some(Self::TransferEncoding),
110            Name::Expect => Some(Self::Expect),
111            Name::Host => Some(Self::Host),
112            Name::Connection => Some(Self::Connection),
113            Name::Upgrade => Some(Self::Upgrade),
114            Name::Invalid
115            | Name::Method
116            | Name::Scheme
117            | Name::Path
118            | Name::Status
119            | Name::Authority
120            | Name::Protocol
121            | Name::Te
122            | Name::KeepAlive
123            | Name::ProxyConnection
124            | Name::Regular => None,
125        }
126    }
127
128    pub fn apply(
129        self,
130        scan: &mut request::Fields,
131        flags: &mut Flags,
132        value: &[u8],
133        version: Version,
134    ) -> Result<(), Error> {
135        match self {
136            Self::AcceptEncoding => parse::ae_value(scan, flags, value),
137            Self::ContentLength => {
138                let len = Ascii::new(crate::field::Error::trim_ows(value))
139                    .parse_usize()
140                    .map_err(Error::ContentLength)?;
141                scan.message = scan.message.try_length(len).map_err(Error::Message)?;
142                Ok(())
143            }
144            Self::TransferEncoding => {
145                let parsed = field::Transfer::default()
146                    .parse(value)
147                    .map_err(Error::TransferEncoding)?;
148                scan.message = scan.message.try_append(parsed).map_err(Error::Message)?;
149                Ok(())
150            }
151            Self::Expect => {
152                scan.message = scan.message.with_expect(value);
153                Ok(())
154            }
155            Self::Host => {
156                scan.routing.authority = scan
157                    .routing
158                    .authority
159                    .try_host(value)
160                    .map_err(Error::Host)?;
161                Ok(())
162            }
163            Self::Connection => {
164                let value = parse_connection(value)?;
165                scan.routing.connection.append(value);
166                Ok(())
167            }
168            Self::Upgrade => {
169                scan.routing = scan
170                    .routing
171                    .try_upgrade(value, version)
172                    .map_err(Error::Upgrade)?;
173                Ok(())
174            }
175        }
176    }
177
178    pub fn scan_line(
179        self,
180        scan: &mut request::Fields,
181        flags: &mut Flags,
182        raw: &[u8],
183        version: Version,
184    ) -> Result<Option<Bounds>, Error> {
185        match self {
186            Self::AcceptEncoding => parse::ae_line(scan, flags, raw),
187            Self::ContentLength => parse::clen_line(scan, raw),
188            Self::TransferEncoding => parse::te_line(scan, raw),
189            Self::Expect => expect_line(scan, raw),
190            Self::Host => host_line(scan, raw),
191            Self::Connection => conn_line(scan, raw),
192            Self::Upgrade => upgrade_line(scan, raw, version),
193        }
194    }
195}
196
197fn host_line(scan: &mut request::Fields, raw: &[u8]) -> Result<Option<Bounds>, Error> {
198    let Some(bounds) = parse::trim_line(raw)? else {
199        return Ok(None);
200    };
201    scan.routing.authority = scan
202        .routing
203        .authority
204        .try_host(bounds.value(raw))
205        .map_err(Error::Host)?;
206    Ok(Some(bounds))
207}
208
209fn upgrade_line(
210    scan: &mut request::Fields,
211    raw: &[u8],
212    version: Version,
213) -> Result<Option<Bounds>, Error> {
214    let Some(bounds) = parse::trim_line(raw)? else {
215        return Ok(None);
216    };
217    scan.routing = scan
218        .routing
219        .try_upgrade(bounds.value(raw), version)
220        .map_err(Error::Upgrade)?;
221    Ok(Some(bounds))
222}
223
224fn expect_line(scan: &mut request::Fields, raw: &[u8]) -> Result<Option<Bounds>, Error> {
225    let (bounds, value) = match parse::try_token_line_lit(raw, b"100-continue") {
226        Some(bounds) => (bounds, b"100-continue".as_slice()),
227        None => {
228            let Some(bounds) = parse::trim_line(raw)? else {
229                return Ok(None);
230            };
231            (bounds, bounds.value(raw))
232        }
233    };
234    scan.message = scan.message.with_expect(value);
235    Ok(Some(bounds))
236}
237
238fn conn_line(scan: &mut request::Fields, raw: &[u8]) -> Result<Option<Bounds>, Error> {
239    let (value, bounds) = if let Some(bounds) = parse::try_token_line_lit(raw, b"keep-alive") {
240        (field::Connection::KEEP_ALIVE, bounds)
241    } else if let Some(bounds) = parse::try_token_line_lit(raw, b"close") {
242        (field::Connection::CLOSE, bounds)
243    } else {
244        let Some(bounds) = parse::trim_line(raw)? else {
245            return Ok(None);
246        };
247        let value = parse_connection(bounds.value(raw))?;
248        (value, bounds)
249    };
250    scan.routing.connection.append(value);
251    Ok(Some(bounds))
252}