Skip to main content

sark_http/request/
mod.rs

1use core::{num::NonZero, ops};
2
3use crate::field::metadata::block;
4
5pub mod body;
6pub mod raw;
7pub mod span;
8
9mod bytes;
10mod id;
11mod segments;
12mod seq;
13mod source;
14
15pub use bytes::Bytes;
16pub use id::Id;
17pub use segments::Segments;
18pub use seq::Seq;
19pub use source::Source;
20use span::Span;
21
22#[derive(Clone, Copy, PartialEq, Eq)]
23#[repr(u8)]
24pub enum Form {
25    Path = 0,
26    Root = 1,
27    Asterisk = 2,
28    Authority = 3,
29    Extended = 4,
30}
31
32#[derive(Clone, Copy, Debug, PartialEq, Eq)]
33pub enum Error {
34    Span(span::Error),
35    InvalidRange,
36    OutOfBounds,
37    MissingAuthority,
38}
39
40impl From<span::Error> for Error {
41    fn from(error: span::Error) -> Self {
42        Self::Span(error)
43    }
44}
45
46#[derive(Clone, Copy, PartialEq, Eq)]
47pub struct Target {
48    packed_start_form_plus_one: NonZero<u32>,
49    len: u32,
50}
51
52const TARGET_LANE: usize = 16;
53
54fn target_lane_invalid<const N: usize>(lane: &[u8; N]) -> bool {
55    let mut invalid = false;
56    for &byte in lane {
57        invalid |= (byte <= 0x20) | (byte == 0x7f);
58    }
59    invalid
60}
61
62impl Target {
63    const FORM_BITS: u32 = 3;
64    const FORM_MASK: u32 = (1 << Self::FORM_BITS) - 1;
65
66    pub fn is_valid(bytes: &[u8]) -> bool {
67        let (blocks, tail) = bytes.as_chunks::<{ TARGET_LANE * 4 }>();
68        for block in blocks {
69            if target_lane_invalid(block) {
70                return false;
71            }
72        }
73        let (lanes, tail) = tail.as_chunks::<TARGET_LANE>();
74        for lane in lanes {
75            if target_lane_invalid(lane) {
76                return false;
77            }
78        }
79        tail.iter().all(|&byte| byte > 0x20 && byte != 0x7f)
80    }
81
82    pub const fn from_span(form: Form, span: Span) -> Result<Self, Error> {
83        let start = span.start();
84        if start >= (1usize << (u32::BITS - Self::FORM_BITS)) {
85            return Err(Error::OutOfBounds);
86        }
87        let packed = ((start as u32) << Self::FORM_BITS) | form as u32;
88        let packed = NonZero::<u32>::MIN.saturating_add(packed);
89        Ok(Self {
90            packed_start_form_plus_one: packed,
91            len: span.len() as u32,
92        })
93    }
94
95    pub const fn form(self) -> Form {
96        match (self.packed_start_form_plus_one.get() - 1) & Self::FORM_MASK {
97            0 => Form::Path,
98            1 => Form::Root,
99            2 => Form::Asterisk,
100            3 => Form::Authority,
101            4..=u32::MAX => Form::Extended,
102        }
103    }
104
105    pub const fn start(self) -> usize {
106        ((self.packed_start_form_plus_one.get() - 1) >> Self::FORM_BITS) as usize
107    }
108
109    pub const fn len(self) -> usize {
110        self.len as usize
111    }
112
113    pub const fn is_empty(self) -> bool {
114        self.len == 0
115    }
116
117    pub const fn end(self) -> usize {
118        self.start() + self.len()
119    }
120
121    pub fn get(self, input: &[u8]) -> Option<&[u8]> {
122        input.get(self.start()..self.end())
123    }
124}
125
126#[repr(C)]
127#[derive(Clone, Copy, PartialEq, Eq)]
128pub struct Layout {
129    target: Target,
130    authority: Option<Span>,
131    route: Option<Span>,
132}
133
134/// A layout validated against the immutable owner carried with it.
135pub struct Bound<O> {
136    owner: O,
137    layout: Layout,
138}
139
140impl<O: Source> Bound<O> {
141    pub fn try_bind(owner: O, layout: Layout) -> Result<Self, Error> {
142        if !layout.is_valid(owner.as_ref()) {
143            return Err(Error::InvalidRange);
144        }
145        Ok(Self { owner, layout })
146    }
147}
148
149impl<O> Bound<O> {
150    pub fn into_parts(self) -> (O, Layout) {
151        (self.owner, self.layout)
152    }
153}
154
155impl Layout {
156    /// The single checked construction path for a retained layout: the target
157    /// span is packed for `form` and the companion spans are proved to sit
158    /// inside that target before they are stored.
159    pub fn try_new(
160        form: Form,
161        target: Span,
162        peer: Option<Span>,
163        route: Option<Span>,
164    ) -> Result<Self, Error> {
165        let layout = Self::new(Target::from_span(form, target)?, peer, route);
166        if layout.is_shaped() {
167            Ok(layout)
168        } else {
169            Err(Error::InvalidRange)
170        }
171    }
172
173    /// Stores pre-packed parts without re-checking the shape they must share.
174    ///
175    /// Binding must prove the shape, ranges and bytes for the exact owner,
176    /// either with [`Self::is_valid`] or by preserving parser admission.
177    pub const fn new(target: Target, peer: Option<Span>, route: Option<Span>) -> Self {
178        Self {
179            target,
180            authority: peer,
181            route,
182        }
183    }
184
185    fn from_kept(
186        owner: &[u8],
187        path: Option<ops::Range<usize>>,
188        path_len: Option<usize>,
189        pseudo: Option<ops::Range<usize>>,
190        host: Option<ops::Range<usize>>,
191        plan: block::Plan,
192    ) -> Result<Self, Error> {
193        let [path, pseudo, host] = checked_spans(owner, path, pseudo, host)?;
194        let layout = Self::from_spans(path, path_len, pseudo, host, plan)?;
195        if layout.checked(owner).is_some() {
196            Ok(layout)
197        } else {
198            Err(Error::InvalidRange)
199        }
200    }
201
202    fn from_spans(
203        path: Option<Span>,
204        path_len: Option<usize>,
205        pseudo: Option<Span>,
206        host: Option<Span>,
207        plan: block::Plan,
208    ) -> Result<Self, Error> {
209        let selected = match plan.authority() {
210            block::Authority::None => None,
211            block::Authority::Pseudo | block::Authority::Target => pseudo,
212            block::Authority::Host => host,
213        };
214        let (target, peer, route) = match plan.form() {
215            block::Form::Path | block::Form::ExtendedConnect => {
216                let target = path.ok_or(Error::InvalidRange)?;
217                let len = path_len.ok_or(Error::InvalidRange)?;
218                let route = Span::checked(target.start(), len).map_err(Error::Span)?;
219                (target, selected, Some(route))
220            }
221            block::Form::Asterisk => (path.ok_or(Error::InvalidRange)?, selected, None),
222            block::Form::Connect => (selected.ok_or(Error::MissingAuthority)?, None, None),
223        };
224        let form = match plan.form() {
225            block::Form::Path => Form::Path,
226            block::Form::Asterisk => Form::Asterisk,
227            block::Form::Connect => Form::Authority,
228            block::Form::ExtendedConnect => Form::Extended,
229        };
230        let target = Target::from_span(form, target)?;
231        Ok(Self::new(target, peer, route))
232    }
233
234    pub const fn target(self) -> Target {
235        self.target
236    }
237
238    pub const fn authority(self) -> Option<Span> {
239        if matches!(self.target.form(), Form::Authority) {
240            Some(Span::from_target(self.target))
241        } else {
242            self.authority
243        }
244    }
245
246    pub const fn route(self) -> Option<Span> {
247        self.route
248    }
249
250    pub fn route_path(self, owner: &[u8]) -> Option<&[u8]> {
251        match self.target.form() {
252            Form::Root => Some(b"/"),
253            Form::Asterisk | Form::Authority => Some(b"*"),
254            Form::Path | Form::Extended => self.route?.get(owner),
255        }
256    }
257
258    pub fn authority_in(self, owner: &[u8]) -> Option<&[u8]> {
259        self.authority()?.get(owner)
260    }
261
262    pub const fn require(self) -> Result<Self, Error> {
263        if matches!(self.target.form(), Form::Authority) || self.authority.is_some() {
264            Ok(self)
265        } else {
266            Err(Error::MissingAuthority)
267        }
268    }
269
270    /// The owner-independent structure every retained layout shares.
271    const fn is_shaped(self) -> bool {
272        match self.target.form() {
273            Form::Path | Form::Extended => match self.route {
274                Some(route) => {
275                    route.start() >= self.target.start() && route.end() <= self.target.end()
276                }
277                None => false,
278            },
279            Form::Root => match self.route {
280                Some(route) => {
281                    route.is_empty()
282                        && route.start() >= self.target.start()
283                        && route.start() <= self.target.end()
284                }
285                None => false,
286            },
287            Form::Asterisk | Form::Authority => self.route.is_none(),
288        }
289    }
290
291    pub fn is_valid(self, owner: &[u8]) -> bool {
292        self.checked(owner).is_some_and(Target::is_valid)
293    }
294
295    fn checked(self, owner: &[u8]) -> Option<&[u8]> {
296        if !self.is_shaped() || self.authority.is_some_and(|span| span.end() > owner.len()) {
297            return None;
298        }
299        let target = self.target.get(owner)?;
300        let shaped = match self.target.form() {
301            Form::Path | Form::Extended => self.route.is_some_and(|route| {
302                route.end() == self.target.end() || owner.get(route.end()) == Some(&b'?')
303            }),
304            Form::Root => self.route.is_some_and(|route| {
305                route.start() == self.target.end() || owner.get(route.start()) == Some(&b'?')
306            }),
307            Form::Asterisk => target == b"*",
308            Form::Authority => true,
309        };
310        shaped.then_some(target)
311    }
312}
313
314fn checked_span(range: Option<ops::Range<usize>>) -> Result<Option<Span>, Error> {
315    range.map(Span::from_range).transpose().map_err(Error::Span)
316}
317
318fn checked_spans(
319    owner: &[u8],
320    path: Option<ops::Range<usize>>,
321    pseudo: Option<ops::Range<usize>>,
322    host: Option<ops::Range<usize>>,
323) -> Result<[Option<Span>; 3], Error> {
324    let path = checked_span(path)?;
325    let pseudo = checked_span(pseudo)?;
326    let host = checked_span(host)?;
327    if path.is_some_and(|span| span.end() > owner.len())
328        || pseudo.is_some_and(|span| span.end() > owner.len())
329        || host.is_some_and(|span| span.end() > owner.len())
330    {
331        return Err(Error::InvalidRange);
332    }
333    Ok([path, pseudo, host])
334}
335
336const _: () = assert!(core::mem::size_of::<Target>() == 8);
337const _: () = assert!(core::mem::size_of::<Option<Target>>() == 8);
338const _: () = assert!(core::mem::size_of::<Layout>() == 24);