move boundary to text
This commit is contained in:
parent
5df9b253ec
commit
6c8e738d43
5 changed files with 97 additions and 56 deletions
|
@ -3,12 +3,13 @@ use nom::{
|
||||||
branch::alt,
|
branch::alt,
|
||||||
bytes::complete::{tag_no_case, tag, take_while1},
|
bytes::complete::{tag_no_case, tag, take_while1},
|
||||||
character::complete::space0,
|
character::complete::space0,
|
||||||
combinator::map,
|
combinator::{not, map},
|
||||||
multi::many0,
|
multi::many0,
|
||||||
sequence::{pair, terminated, tuple},
|
sequence::{pair, preceded, terminated, tuple},
|
||||||
};
|
};
|
||||||
use crate::text::whitespace::{foldable_line, obs_crlf};
|
use crate::text::whitespace::{foldable_line, obs_crlf};
|
||||||
use crate::text::misc_token::{Unstructured, unstructured};
|
use crate::text::misc_token::{Unstructured, unstructured};
|
||||||
|
use crate::text::boundary::boundary;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum CompField<'a, T> {
|
pub enum CompField<'a, T> {
|
||||||
|
@ -38,6 +39,18 @@ pub fn header<'a, T>(fx: impl Fn(&'a [u8]) -> IResult<&[u8], T> + Copy)
|
||||||
))), obs_crlf), CompFieldList)(input)
|
))), obs_crlf), CompFieldList)(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn header_in_boundaries<'a, T>(bound: &'a [u8], fx: impl Fn(&'a [u8]) -> IResult<&[u8], T> + Copy)
|
||||||
|
-> impl Fn(&'a [u8]) -> IResult<&[u8], CompFieldList<T>>
|
||||||
|
{
|
||||||
|
move |input| map(terminated(many0(preceded(
|
||||||
|
not(boundary(bound)),
|
||||||
|
alt((
|
||||||
|
map(fx, CompField::Known),
|
||||||
|
map(opt_field, |(k,v)| CompField::Unknown(k,v)),
|
||||||
|
map(foldable_line, CompField::Bad),
|
||||||
|
)))), obs_crlf), CompFieldList)(input)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn field_name<'a>(name: &'static [u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], &'a [u8]> {
|
pub fn field_name<'a>(name: &'static [u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], &'a [u8]> {
|
||||||
move |input| {
|
move |input| {
|
||||||
terminated(
|
terminated(
|
||||||
|
|
|
@ -50,7 +50,7 @@ mod tests {
|
||||||
if let Content::Type(nt) = content {
|
if let Content::Type(nt) = content {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
nt.to_type(),
|
nt.to_type(),
|
||||||
Type::Text(TextDesc {
|
Type::Text(Text {
|
||||||
charset: EmailCharset::UTF_8,
|
charset: EmailCharset::UTF_8,
|
||||||
subtype: TextSubtype::Plain,
|
subtype: TextSubtype::Plain,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -7,51 +7,49 @@ use nom::{
|
||||||
combinator::{not, opt, recognize},
|
combinator::{not, opt, recognize},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::mime::r#type;
|
||||||
|
|
||||||
pub struct Part<'a, T> {
|
pub struct Part<'a> {
|
||||||
|
Multipart(r#type::Multipart, Vec<Part<'a>>),
|
||||||
|
Message(r#type::Message, Message, Part<'a>),
|
||||||
|
Text(r#type::Text, &'a [u8]),
|
||||||
|
Binary(&'a [u8]),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Part<'a, r#type::Text<'a>> {
|
pub fn message() -> IResult<&[u8], Part> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn multipart<'a>(ctype: Type) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Part<'a>> {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub enum PartNodeLazy<'a>{
|
|
||||||
Discrete(MIMESection<'a>, &'a [u8]),
|
|
||||||
Composite(MIMESection<'a>, &'a [u8]),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub enum PartNode<'a> {
|
|
||||||
Discrete(MIMESection<'a>, &'a [u8]),
|
|
||||||
Composite(MIMESection<'a>, Vec<PartNode<'a>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub enum Delimiter {
|
|
||||||
Next,
|
|
||||||
Last
|
|
||||||
}
|
|
||||||
|
|
||||||
const IS_LAST_BUFFER: bool = true;
|
|
||||||
const ALLOW_UTF8: bool = true;
|
|
||||||
const NO_TLD: Option<&[u8]> = None;
|
|
||||||
fn part_node_lazy(input: &[u8]) -> IResult<&[u8], PartNodeLazy> {
|
|
||||||
//let mime = header.iter().map(|e| eager::MIMEField::from(lazy::MIMEField::from(e)));
|
|
||||||
todo!();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn boundary<'a>(boundary: &'a [u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Delimiter> {
|
|
||||||
move |input: &[u8]| {
|
move |input: &[u8]| {
|
||||||
let (rest, (_, _, _, last, _)) = tuple((obs_crlf, tag(b"--"), tag(boundary), opt(tag(b"--")), opt(obs_crlf)))(input)?;
|
let (mut input_loop, _) = preamble(ctype.boundary)(input)?;
|
||||||
match last {
|
let mut parts: Vec<Part> = vec![];
|
||||||
Some(_) => Ok((rest, Delimiter::Last)),
|
loop {
|
||||||
None => Ok((rest, Delimiter::Next)),
|
let input = match boundary(ctype.boundary)(input_loop) {
|
||||||
|
Err(_) => return Ok((input_loop, parts)),
|
||||||
|
Ok((inp, Delimiter::Last)) => return Ok((inp, Part::Multipart(ctype, parts))),
|
||||||
|
Ok((inp, Delimiter::Next)) => inp,
|
||||||
|
};
|
||||||
|
|
||||||
|
// parse mime headers
|
||||||
|
header(content)(input)?;
|
||||||
|
|
||||||
|
// based on headers, parse part
|
||||||
|
|
||||||
|
let input = match part(bound)(input) {
|
||||||
|
Err(_) => return Ok((input, parts)),
|
||||||
|
Ok((inp, part)) => {
|
||||||
|
parts.push(part);
|
||||||
|
inp
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
input_loop = input;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn discrete() -> IResult<&[u8], Part> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn part<'a>(bound: &'a [u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], &'a [u8]> {
|
pub fn part<'a>(bound: &'a [u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], &'a [u8]> {
|
||||||
|
@ -105,22 +103,6 @@ pub fn multipart<'a>(bound: &'a [u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [u8],
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_boundary_next() {
|
|
||||||
assert_eq!(
|
|
||||||
boundary(b"hello")(b"\r\n--hello\r\n"),
|
|
||||||
Ok((&b""[..], Delimiter::Next))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_boundary_last() {
|
|
||||||
assert_eq!(
|
|
||||||
boundary(b"hello")(b"\r\n--hello--\r\n"),
|
|
||||||
Ok((&b""[..], Delimiter::Last))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_preamble() {
|
fn test_preamble() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
45
src/text/boundary.rs
Normal file
45
src/text/boundary.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
use nom::{
|
||||||
|
IResult,
|
||||||
|
bytes::complete::tag,
|
||||||
|
sequence::tuple,
|
||||||
|
combinator::opt,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::text::whitespace::obs_crlf;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Delimiter {
|
||||||
|
Next,
|
||||||
|
Last
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn boundary<'a>(boundary: &'a [u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Delimiter> {
|
||||||
|
move |input: &[u8]| {
|
||||||
|
let (rest, (_, _, _, last, _)) = tuple((opt(obs_crlf), tag(b"--"), tag(boundary), opt(tag(b"--")), opt(obs_crlf)))(input)?;
|
||||||
|
match last {
|
||||||
|
Some(_) => Ok((rest, Delimiter::Last)),
|
||||||
|
None => Ok((rest, Delimiter::Next)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_boundary_next() {
|
||||||
|
assert_eq!(
|
||||||
|
boundary(b"hello")(b"\r\n--hello\r\n"),
|
||||||
|
Ok((&b""[..], Delimiter::Next))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_boundary_last() {
|
||||||
|
assert_eq!(
|
||||||
|
boundary(b"hello")(b"\r\n--hello--\r\n"),
|
||||||
|
Ok((&b""[..], Delimiter::Last))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,3 +4,4 @@ pub mod misc_token;
|
||||||
pub mod quoted;
|
pub mod quoted;
|
||||||
pub mod whitespace;
|
pub mod whitespace;
|
||||||
pub mod words;
|
pub mod words;
|
||||||
|
pub mod boundary;
|
||||||
|
|
Loading…
Add table
Reference in a new issue