Skip to main content

base_web_multipart/
multipart_error.rs

1// Released under the MIT License.
2// Copyright, 2026, by Samuel Williams.
3
4use std::fmt;
5
6/// Why a multipart body could not be parsed, with the offset in the body where the parser found it, which is the same however the body was split. It never includes the body's bytes, which may be large or untrusted.
7#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
8pub struct MultipartError {
9    kind: MultipartErrorKind,
10    offset: u64,
11}
12
13/// The kind of [`MultipartError`].
14#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
15#[non_exhaustive]
16pub enum MultipartErrorKind {
17    /// The preamble is longer than its limit, at the start of the preamble, which is the start of the body.
18    PreambleSizeLimit,
19    /// A part's header section, with any padding after the boundary before it, is longer than its limit, at the start of the section; or the padding after a boundary, including the closing one, is longer than the limit by itself, at the start of the padding.
20    HeaderSizeLimit,
21    /// A part's header section has more fields than its limit, at the start of the section.
22    HeaderCountLimit,
23    /// The body has more parts than its limit, at the line break that ends the boundary line of the part beyond it.
24    PartCountLimit,
25    /// A header line is not `name: value` with a valid name and value, or does not end with CRLF, at the start of its header section.
26    InvalidField,
27    /// A header line is folded, continuing the previous line, which this parser does not accept, at the start of its header section.
28    FoldedField,
29    /// A boundary is followed by something other than optional spaces and tabs and a line break, or `--`, so it appears in content where RFC 2046 does not allow it, at the first byte after the boundary and its padding that does not begin CRLF, or `--` directly after the boundary; or a boundary follows a bare CR or LF, at that line break, after the content or preamble before it.
30    InvalidDelimiter,
31    /// The body ended before its closing boundary, at the first byte the parser had not consumed.
32    UnexpectedEnd,
33}
34
35impl MultipartError {
36    pub(crate) fn new(kind: MultipartErrorKind, offset: u64) -> Self {
37        Self { kind, offset }
38    }
39
40    /// What went wrong.
41    pub fn kind(&self) -> MultipartErrorKind {
42        self.kind
43    }
44
45    /// The offset in the body, in bytes, where the parser found the problem, as each [`MultipartErrorKind`] describes, the same however the body was split.
46    pub fn offset(&self) -> u64 {
47        self.offset
48    }
49}
50
51impl fmt::Display for MultipartError {
52    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
53        let description = match self.kind {
54            MultipartErrorKind::PreambleSizeLimit => "multipart preamble exceeds its size limit",
55            MultipartErrorKind::HeaderSizeLimit => {
56                "multipart part header section exceeds its size limit"
57            }
58            MultipartErrorKind::HeaderCountLimit => {
59                "multipart part header section exceeds its field count limit"
60            }
61            MultipartErrorKind::PartCountLimit => "multipart body exceeds its part count limit",
62            MultipartErrorKind::InvalidField => "invalid multipart part header field",
63            MultipartErrorKind::FoldedField => "folded multipart part header field",
64            MultipartErrorKind::InvalidDelimiter => "invalid multipart boundary line",
65            MultipartErrorKind::UnexpectedEnd => "multipart body ends before its closing boundary",
66        };
67        write!(formatter, "{description} at byte {}", self.offset)
68    }
69}
70
71impl std::error::Error for MultipartError {}