Skip to main content

sark_http/h1/chunk/
mod.rs

1use core::{marker, mem, num, ops::ControlFlow, ptr, slice};
2
3use scan::state;
4
5mod axis;
6pub mod ban;
7mod error;
8mod limit;
9pub(in crate::h1) mod scan;
10mod size;
11mod syntax;
12pub(in crate::h1) mod trailer;
13
14pub use axis::Axis;
15pub use error::Error;
16pub use limit::Limit;
17pub use syntax::Syntax;
18
19#[derive(Clone, Copy, PartialEq, Eq)]
20#[repr(u8)]
21pub enum Boundary {
22    More,
23    End,
24}
25
26#[derive(Clone, Copy, PartialEq, Eq)]
27pub enum Fragment<'input> {
28    More(usize),
29    Data {
30        consumed: num::NonZero<usize>,
31        bytes: &'input [u8],
32        boundary: Boundary,
33    },
34    Trailer(num::NonZero<usize>),
35    Complete {
36        consumed: num::NonZero<usize>,
37        /// The trailer suffix in this input, excluding the terminating empty line.
38        /// It can start within a field when earlier input held its prefix.
39        /// Use `codec::decode::trailer` to retain complete admitted field lines.
40        bytes: &'input [u8],
41    },
42}
43
44#[derive(Clone, Copy, PartialEq, Eq)]
45enum Active {
46    Size(size::Size),
47    SizeLf(size::Size),
48    Data(num::NonZero<usize>),
49    DataCr,
50    DataLf,
51    Trailer(state::State),
52}
53
54#[derive(Clone, Copy, PartialEq, Eq)]
55pub struct Framer {
56    phase: ControlFlow<num::NonZero<u32>, Active>,
57    wire_bytes: usize,
58    body_bytes: usize,
59}
60
61impl Default for Framer {
62    fn default() -> Self {
63        Self::new()
64    }
65}
66
67impl Framer {
68    pub const fn new() -> Self {
69        Self {
70            phase: ControlFlow::Continue(Active::Size(size::Size::new())),
71            wire_bytes: 0,
72            body_bytes: 0,
73        }
74    }
75
76    pub const fn wire_bytes(&self) -> usize {
77        self.wire_bytes
78    }
79
80    pub const fn body_bytes(&self) -> usize {
81        self.body_bytes
82    }
83
84    /// Completed trailer bytes including the final CRLF. This count does not bind an input source.
85    pub fn trailer_bytes(&self) -> Option<num::NonZero<u32>> {
86        self.phase.break_value()
87    }
88
89    pub fn reset(&mut self) {
90        *self = Self::new();
91    }
92
93    pub fn scan<'input>(
94        &mut self,
95        input: &'input [u8],
96        limits: &Limit,
97    ) -> Result<Run<'input>, Error> {
98        let (next, run) = (*self).prepare::<scan::Whole>(input, limits, usize::MAX)?;
99        *self = next;
100        Ok(run)
101    }
102
103    pub fn decode<'input>(
104        self,
105        input: &'input [u8],
106        limits: &Limit,
107        data: usize,
108    ) -> Result<(Self, Fragment<'input>), Error> {
109        let (next, output) = self.prepare::<scan::Fragments>(input, limits, data)?;
110        Ok((next, output.fragment()))
111    }
112
113    pub(in crate::h1) fn prepare<'input, M: scan::Mode>(
114        self,
115        input: &'input [u8],
116        limits: &Limit,
117        data: usize,
118    ) -> Result<(Self, M::Output<'input>), Error> {
119        let ControlFlow::Continue(active) = self.phase else {
120            return Ok((self, M::finished(input)));
121        };
122        self.drive::<M>(active, input, limits, data)
123    }
124
125    fn drive<'input, M: scan::Mode>(
126        mut self,
127        mut active: Active,
128        input: &'input [u8],
129        limits: &Limit,
130        data: usize,
131    ) -> Result<(Self, M::Output<'input>), Error> {
132        let mut pos = 0usize;
133        while let Some(&byte) = input.get(pos) {
134            match active {
135                Active::Size(size) => {
136                    let offset = self.wire_bytes;
137                    let wire = Self::wire(self.wire_bytes, 1, limits)?;
138                    let (size, progress) = size.scan(byte, offset, limits.line_bytes)?;
139                    self.wire_bytes = wire;
140                    pos += 1;
141                    active = if progress == size::Progress::Complete {
142                        Active::SizeLf(size)
143                    } else {
144                        Active::Size(size)
145                    };
146                }
147                Active::SizeLf(size) => {
148                    let offset = self.wire_bytes;
149                    let wire = Self::wire(self.wire_bytes, 1, limits)?;
150                    let size = size.finish(byte, offset, limits.line_bytes)?;
151                    let (body, next) = Self::check_size(self.body_bytes, size.value(), limits)?;
152                    self.wire_bytes = wire;
153                    self.body_bytes = body;
154                    pos += 1;
155                    active = next;
156                }
157                Active::Data(left) => {
158                    let tail = &input[pos..];
159                    let Some(amount) = num::NonZero::new(left.get().min(tail.len()).min(data))
160                    else {
161                        break;
162                    };
163                    self.wire_bytes = Self::wire(self.wire_bytes, amount.get(), limits)?;
164                    let bytes = &tail[..amount.get()];
165                    let consumed = amount.saturating_add(pos);
166                    pos = consumed.get();
167                    let boundary = match num::NonZero::new(left.get() - amount.get()) {
168                        Some(left) => {
169                            active = Active::Data(left);
170                            Boundary::More
171                        }
172                        None => {
173                            active = Active::DataCr;
174                            Boundary::End
175                        }
176                    };
177                    if let Some(output) = M::data(consumed, bytes, boundary) {
178                        self.phase = ControlFlow::Continue(active);
179                        return Ok((self, output));
180                    }
181                }
182                Active::DataCr => {
183                    self.wire_bytes =
184                        Self::exact(self.wire_bytes, byte, b'\r', Syntax::DataCr, limits)?;
185                    pos += 1;
186                    active = Active::DataLf;
187                }
188                Active::DataLf => {
189                    self.wire_bytes =
190                        Self::exact(self.wire_bytes, byte, b'\n', Syntax::DataLf, limits)?;
191                    pos += 1;
192                    active = Active::Size(size::Size::default());
193                }
194                Active::Trailer(state) => {
195                    let mut trailer = trailer::Trailer::new(state, self.wire_bytes, *limits);
196                    let (progress, bytes) = trailer.scan(&input[pos..])?;
197                    match progress {
198                        trailer::Progress::More { next, consumed } => {
199                            self.wire_bytes = next.wire;
200                            self.phase = ControlFlow::Continue(Active::Trailer(next.state));
201                            trailer.cursor = next;
202                            let output = match consumed {
203                                Some(consumed) => {
204                                    M::trailer(input, consumed.saturating_add(pos), bytes, trailer)
205                                }
206                                None => M::pending(input, pos),
207                            };
208                            return Ok((self, output));
209                        }
210                        trailer::Progress::Complete {
211                            wire,
212                            consumed,
213                            trailers,
214                        } => {
215                            self.wire_bytes = wire;
216                            self.phase = ControlFlow::Break(trailers);
217                            return Ok((
218                                self,
219                                M::complete(input, consumed.saturating_add(pos), bytes),
220                            ));
221                        }
222                    }
223                }
224            }
225        }
226
227        self.phase = ControlFlow::Continue(active);
228        Ok((self, M::pending(input, pos)))
229    }
230
231    fn wire(current: usize, amount: usize, limits: &Limit) -> Result<usize, Error> {
232        let actual = current.checked_add(amount).ok_or(Error::Overflow {
233            axis: Axis::Wire,
234            value: current,
235            added: amount,
236        })?;
237        if actual > limits.wire_bytes {
238            return Err(Error::Limit {
239                axis: Axis::Wire,
240                actual,
241                maximum: limits.wire_bytes,
242            });
243        }
244        Ok(actual)
245    }
246
247    fn exact(
248        wire: usize,
249        byte: u8,
250        expected: u8,
251        syntax: Syntax,
252        limits: &Limit,
253    ) -> Result<usize, Error> {
254        let offset = wire;
255        let actual = Self::wire(wire, 1, limits)?;
256        if byte == expected {
257            Ok(actual)
258        } else {
259            Err(Error::Syntax {
260                offset,
261                syntax,
262                actual: byte,
263            })
264        }
265    }
266
267    fn check_size(current: usize, size: usize, limits: &Limit) -> Result<(usize, Active), Error> {
268        let total = current.checked_add(size).ok_or(Error::Overflow {
269            axis: Axis::Body,
270            value: current,
271            added: size,
272        })?;
273        if total > limits.body_bytes {
274            return Err(Error::Limit {
275                axis: Axis::Body,
276                actual: total,
277                maximum: limits.body_bytes,
278            });
279        }
280        let active = match num::NonZero::new(size) {
281            Some(size) => Active::Data(size),
282            None => Active::Trailer(state::State::new()),
283        };
284        Ok((total, active))
285    }
286}
287
288const _: () = {
289    assert!(mem::size_of::<Boundary>() == mem::size_of::<bool>());
290    assert!(mem::align_of::<Boundary>() == mem::align_of::<bool>());
291    assert!(mem::size_of::<Framer>() <= 6 * mem::size_of::<usize>());
292    assert!(!mem::needs_drop::<Framer>());
293};
294
295#[must_use]
296pub struct Run<'input> {
297    source: ptr::NonNull<u8>,
298    state: usize,
299    borrow: marker::PhantomData<&'input [u8]>,
300}
301
302impl<'input> Run<'input> {
303    const COMPLETE: usize = 1 << (usize::BITS - 1);
304
305    /// A scan that stopped before the input ran out, having consumed the
306    /// `scanned` bytes of `input` the scan loop read.
307    pub(in crate::h1::chunk) fn pending(input: &'input [u8], scanned: usize) -> Self {
308        Self {
309            source: ptr::NonNull::from(input).cast(),
310            state: scanned,
311            borrow: marker::PhantomData,
312        }
313    }
314
315    /// A scan that consumed the whole chunk framing: the `scanned` bytes of
316    /// `input` the scan loop read.
317    pub(in crate::h1::chunk) fn complete(input: &'input [u8], scanned: usize) -> Self {
318        Self {
319            source: ptr::NonNull::from(input).cast(),
320            state: scanned | Self::COMPLETE,
321            borrow: marker::PhantomData,
322        }
323    }
324
325    pub const fn is_complete(self) -> bool {
326        self.state & Self::COMPLETE != 0
327    }
328
329    pub const fn into_slice(self) -> &'input [u8] {
330        let len = self.state & !Self::COMPLETE;
331        // SAFETY: constructors retain the full input's provenance and borrow;
332        // the scan proves this prefix fits. Slice lengths are at most isize::MAX,
333        // so their scanned count cannot set COMPLETE.
334        unsafe { slice::from_raw_parts(self.source.as_ptr(), len) }
335    }
336}
337
338const _: () = {
339    assert!(mem::size_of::<Run<'static>>() == 2 * mem::size_of::<usize>());
340    assert!(mem::align_of::<Run<'static>>() == mem::align_of::<usize>());
341    assert!(!mem::needs_drop::<Run<'static>>());
342};