Skip to main content

eml_codec/text/
boundary.rs

1use nom::{
2    branch::alt,
3    bytes::complete::tag,
4    character::complete::space0,
5    combinator::{eof, opt, recognize},
6    sequence::tuple,
7    IResult,
8};
9
10use crate::text::whitespace::obs_crlf;
11
12#[derive(Debug, PartialEq)]
13pub enum Delimiter {
14    Next,
15    Last,
16}
17
18pub fn boundary<'a>(boundary: &[u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Delimiter> + '_ {
19    move |input: &[u8]| {
20        let (rest, (_, _, _, _, last, _)) = tuple((
21            opt(recognize(obs_crlf)), // XXX is this opt spec compliant??
22            tag(b"--"),
23            tag(boundary),
24            space0, // transport-padding
25            opt(tag(b"--")),
26            alt((recognize(obs_crlf), eof)), // XXX obs_crlf is not exactly spec compliant
27        ))(input)?;
28        match last {
29            Some(_) => Ok((rest, Delimiter::Last)),
30            None => Ok((rest, Delimiter::Next)),
31        }
32    }
33}
34
35#[cfg(test)]
36mod tests {
37    use super::*;
38
39    #[test]
40    fn test_boundary_next() {
41        assert_eq!(
42            boundary(b"hello")(b"\r\n--hello\r\n"),
43            Ok((&b""[..], Delimiter::Next))
44        );
45    }
46
47    #[test]
48    fn test_boundary_last() {
49        assert_eq!(
50            boundary(b"hello")(b"\r\n--hello--\r\n"),
51            Ok((&b""[..], Delimiter::Last))
52        );
53    }
54
55    #[test]
56    fn test_boundary_transport_padding() {
57        assert_eq!(
58            boundary(b"hello")(b"\n--hello  \t \n"),
59            Ok((&b""[..], Delimiter::Next))
60        );
61    }
62}