rescue logic
This commit is contained in:
parent
c62f803a95
commit
0e23e49199
3 changed files with 39 additions and 7 deletions
|
@ -1,10 +1,9 @@
|
||||||
use nom::{
|
use nom::{
|
||||||
IResult,
|
IResult,
|
||||||
branch::alt,
|
branch::alt,
|
||||||
bytes::complete::take_while1,
|
bytes::complete::{is_not, take_while1, take_while, tag},
|
||||||
bytes::complete::tag,
|
|
||||||
character::complete::space0,
|
character::complete::space0,
|
||||||
combinator::{map, opt},
|
combinator::{map, opt, recognize},
|
||||||
multi::{many0, many1, fold_many0, separated_list1},
|
multi::{many0, many1, fold_many0, separated_list1},
|
||||||
sequence::{terminated, preceded, pair, tuple},
|
sequence::{terminated, preceded, pair, tuple},
|
||||||
};
|
};
|
||||||
|
@ -25,7 +24,7 @@ use crate::{datetime, trace, model};
|
||||||
/// See: https://www.rfc-editor.org/rfc/rfc5322.html#section-2.2
|
/// See: https://www.rfc-editor.org/rfc/rfc5322.html#section-2.2
|
||||||
pub fn section(input: &str) -> IResult<&str, HeaderSection> {
|
pub fn section(input: &str) -> IResult<&str, HeaderSection> {
|
||||||
let (input, headers) = fold_many0(
|
let (input, headers) = fold_many0(
|
||||||
alt((header_field, unknown_field)),
|
alt((header_field, unknown_field, rescue)),
|
||||||
HeaderSection::default,
|
HeaderSection::default,
|
||||||
|mut section, head| {
|
|mut section, head| {
|
||||||
match head {
|
match head {
|
||||||
|
@ -109,6 +108,11 @@ pub fn section(input: &str) -> IResult<&str, HeaderSection> {
|
||||||
HeaderField::Optional(name, body) => {
|
HeaderField::Optional(name, body) => {
|
||||||
section.optional.insert(name, body);
|
section.optional.insert(name, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rescue
|
||||||
|
HeaderField::Rescue(x) => {
|
||||||
|
section.unparsed.push(x);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
section
|
section
|
||||||
}
|
}
|
||||||
|
@ -149,7 +153,10 @@ pub enum HeaderField<'a> {
|
||||||
ReturnPath(Option<model::MailboxRef>),
|
ReturnPath(Option<model::MailboxRef>),
|
||||||
|
|
||||||
// 3.6.8. Optional Fields
|
// 3.6.8. Optional Fields
|
||||||
Optional(&'a str, String)
|
Optional(&'a str, String),
|
||||||
|
|
||||||
|
// None
|
||||||
|
Rescue(&'a str),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse one known header field
|
/// Parse one known header field
|
||||||
|
@ -285,6 +292,21 @@ fn field_name(input: &str) -> IResult<&str, &str> {
|
||||||
)(input)
|
)(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Rescue rule
|
||||||
|
///
|
||||||
|
/// Something went wrong while parsing headers,
|
||||||
|
/// trying to fix parsing by consuming
|
||||||
|
/// one unfolded header line.
|
||||||
|
///
|
||||||
|
/// ```abnf
|
||||||
|
/// rescue = *(*any FWS) *any CRLF
|
||||||
|
fn rescue(input: &str) -> IResult<&str, HeaderField> {
|
||||||
|
map(recognize(pair(
|
||||||
|
many0(pair(is_not("\r\n"), fws)),
|
||||||
|
pair(is_not("\r\n"), perm_crlf,
|
||||||
|
))), |x| HeaderField::Rescue(x))(input)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -447,6 +469,14 @@ mod tests {
|
||||||
fn test_invalid_field_name() {
|
fn test_invalid_field_name() {
|
||||||
assert!(header_field("Unknown: unknown\r\n").is_err());
|
assert!(header_field("Unknown: unknown\r\n").is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rescue() {
|
||||||
|
assert_eq!(
|
||||||
|
rescue("Héron: élan\r\n\tnoël: test\r\n"),
|
||||||
|
Ok(("", HeaderField::Rescue("Héron: élan\r\n\tnoël: test\r\n"))),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,5 @@ pub struct HeaderSection<'a> {
|
||||||
|
|
||||||
// 3.6.8. Optional Fields
|
// 3.6.8. Optional Fields
|
||||||
pub optional: HashMap<&'a str, String>,
|
pub optional: HashMap<&'a str, String>,
|
||||||
//pub failed: HashMap<&'a str, String>,
|
pub unparsed: Vec<&'a str>,
|
||||||
//pub garbage: &'a str,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,9 @@ Subject: Re: Saying Hello
|
||||||
Comments: A simple message
|
Comments: A simple message
|
||||||
Comments: Not that complicated
|
Comments: Not that complicated
|
||||||
Keywords: hello, world
|
Keywords: hello, world
|
||||||
|
Héron: Raté
|
||||||
|
Raté raté
|
||||||
|
raté raté
|
||||||
Keywords: salut, le, monde
|
Keywords: salut, le, monde
|
||||||
Message-ID: <3456@example.net>
|
Message-ID: <3456@example.net>
|
||||||
In-Reply-To: <1234@local.machine.example>
|
In-Reply-To: <1234@local.machine.example>
|
||||||
|
|
Loading…
Reference in a new issue