summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2019-12-23 13:31:48 +0100
committerMatthias Beyer <mail@beyermatthias.de>2019-12-23 13:37:03 +0100
commit8d09639921ca29f36def0777102b55a1c762748c (patch)
tree478bf4e6911870279e467cc9121ffbfd6d3785fb
parentd690505c02789525ced8920e14de394b0d771c77 (diff)
Replace own error type with failureparsing
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r--parser/src/body.rs17
-rw-r--r--parser/src/error.rs70
-rw-r--r--parser/src/header.rs37
-rw-r--r--parser/src/lib.rs3
-rw-r--r--parser/src/parser.rs26
5 files changed, 33 insertions, 120 deletions
diff --git a/parser/src/body.rs b/parser/src/body.rs
index 4a7fc36..1c86273 100644
--- a/parser/src/body.rs
+++ b/parser/src/body.rs
@@ -1,5 +1,5 @@
+use failure::Fallible as Result;
use charset::{decode_ascii, Charset};
-use crate::error::MailParseError;
use crate::parser::ParsedContentType;
/// Represents the body of an email (or mail subpart)
@@ -50,7 +50,7 @@ impl<'a> Body<'a> {
/// Struct that holds the encoded body representation of the message (or message subpart).
pub struct EncodedBody<'a> {
- decoder: fn(&[u8]) -> Result<Vec<u8>, MailParseError>,
+ decoder: fn(&[u8]) -> Result<Vec<u8>>,
ctype: &'a ParsedContentType,
body: &'a [u8],
}
@@ -67,7 +67,7 @@ impl<'a> EncodedBody<'a> {
}
/// Get the decoded body of the message (or message subpart).
- pub fn get_decoded(&self) -> Result<Vec<u8>, MailParseError> {
+ pub fn get_decoded(&self) -> Result<Vec<u8>> {
(self.decoder)(self.body)
}
@@ -77,7 +77,7 @@ impl<'a> EncodedBody<'a> {
/// (or "us-ascii" if the charset was missing or not recognized).
/// This operation returns a valid result only if the decoded body
/// has a text format.
- pub fn get_decoded_as_string(&self) -> Result<String, MailParseError> {
+ pub fn get_decoded_as_string(&self) -> Result<String> {
get_body_as_string(&self.get_decoded()?, &self.ctype)
}
}
@@ -103,7 +103,7 @@ impl<'a> TextBody<'a> {
/// This function converts the body into a Rust UTF-8 string using the charset
/// in the Content-Type
/// (or "us-ascii" if the charset was missing or not recognized).
- pub fn get_as_string(&self) -> Result<String, MailParseError> {
+ pub fn get_as_string(&self) -> Result<String> {
get_body_as_string(self.body, &self.ctype)
}
}
@@ -126,7 +126,7 @@ impl<'a> BinaryBody<'a> {
}
}
-fn decode_base64(body: &[u8]) -> Result<Vec<u8>, MailParseError> {
+fn decode_base64(body: &[u8]) -> Result<Vec<u8>> {
let cleaned = body
.iter()
.filter(|c| !c.is_ascii_whitespace())
@@ -135,14 +135,14 @@ fn decode_base64(body: &[u8]) -> Result<Vec<u8>, MailParseError> {
Ok(base64::decode(&cleaned)?)
}
-fn decode_quoted_printable(body: &[u8]) -> Result<Vec<u8>, MailParseError> {
+fn decode_quoted_printable(body: &[u8]) -> Result<Vec<u8>> {
Ok(quoted_printable::decode(
body,
quoted_printable::ParseMode::Robust,
)?)
}
-fn get_body_as_string(body: &[u8], ctype: &ParsedContentType) -> Result<String, MailParseError> {
+fn get_body_as_string(body: &[u8], ctype: &ParsedContentType) -> Result<String> {
let cow = if let Some(charset) = Charset::for_label(ctype.charset.as_bytes()) {
let (cow, _, _) = charset.decode(body);
cow
@@ -151,3 +151,4 @@ fn get_body_as_string(body: &[u8], ctype: &ParsedContentType) -> Result<String,
};
Ok(cow.into_owned())
}
+
diff --git a/parser/src/error.rs b/parser/src/error.rs
deleted file mode 100644
index fc7a518..0000000
--- a/parser/src/error.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-use std::ops::Deref;
-
-/// An error type that represents the different kinds of errors that may be
-/// encountered during message parsing.
-#[derive(Debug)]
-pub enum MailParseError {
- /// Data that was specified as being in the quoted-printable transfer-encoding
- /// could not be successfully decoded as quoted-printable data.
- QuotedPrintableDecodeError(quoted_printable::QuotedPrintableError),
- /// Data that was specified as being in the base64 transfer-encoding could
- /// not be successfully decoded as base64 data.
- Base64DecodeError(base64::DecodeError),
- /// An error occurred when converting the raw byte data to Rust UTF-8 string
- /// format using the charset specified in the message.
- EncodingError(std::borrow::Cow<'static, str>),
- /// Some other error occurred while parsing the message; the description string
- /// provides additional details.
- Generic(&'static str),
-}
-
-impl ::std::fmt::Display for MailParseError {
- fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
- match *self {
- MailParseError::QuotedPrintableDecodeError(ref err) => {
- write!(f, "QuotedPrintable decode error: {}", err)
- }
- MailParseError::Base64DecodeError(ref err) => write!(f, "Base64 decode error: {}", err),
- MailParseError::EncodingError(ref err) => write!(f, "Encoding error: {}", err),
- MailParseError::Generic(ref description) => write!(f, "{}", description),
- }
- }
-}
-
-impl ::std::error::Error for MailParseError {
- fn description(&self) -> &str {
- match *self {
- MailParseError::QuotedPrintableDecodeError(ref err) => err.description(),
- MailParseError::Base64DecodeError(ref err) => err.description(),
- MailParseError::EncodingError(ref err) => err.deref(),
- _ => "An error occurred while attempting to parse the input",
- }
- }
-
- fn cause(&self) -> Option<&dyn ::std::error::Error> {
- match *self {
- MailParseError::QuotedPrintableDecodeError(ref err) => Some(err),
- MailParseError::Base64DecodeError(ref err) => Some(err),
- _ => None,
- }
- }
-}
-
-impl From<quoted_printable::QuotedPrintableError> for MailParseError {
- fn from(err: quoted_printable::QuotedPrintableError) -> MailParseError {
- MailParseError::QuotedPrintableDecodeError(err)
- }
-}
-
-impl From<base64::DecodeError> for MailParseError {
- fn from(err: base64::DecodeError) -> MailParseError {
- MailParseError::Base64DecodeError(err)
- }
-}
-
-impl From<std::borrow::Cow<'static, str>> for MailParseError {
- fn from(err: std::borrow::Cow<'static, str>) -> MailParseError {
- MailParseError::EncodingError(err)
- }
-}
-
diff --git a/parser/src/header.rs b/parser/src/header.rs
index 2473a2e..4c690cd 100644
--- a/parser/src/header.rs
+++ b/parser/src/header.rs
@@ -1,8 +1,8 @@
+use failure::Fallible as Result;
use charset::decode_latin1;
use charset::Charset;
use crate::util::*;
-use crate::error::*;
/// A struct that represents a single header in the message.
/// It holds slices into the raw byte array passed to parse_mail, and so the
@@ -17,7 +17,7 @@ pub struct MailHeader<'a> {
impl<'a> MailHeader<'a> {
/// Get the name of the header. Note that header names are case-insensitive.
- pub fn get_key(&self) -> Result<String, MailParseError> {
+ pub fn get_key(&self) -> Result<String> {
Ok(decode_latin1(self.key).into_owned())
}
@@ -65,7 +65,7 @@ impl<'a> MailHeader<'a> {
/// assert_eq!(parsed.get_key().unwrap(), "Subject");
/// assert_eq!(parsed.get_value().unwrap(), "\u{a1}Hola, se\u{f1}or!");
/// ```
- pub fn get_value(&self) -> Result<String, MailParseError> {
+ pub fn get_value(&self) -> Result<String> {
let mut result = String::new();
let chars = decode_latin1(self.value);
let mut lines = chars.lines();
@@ -154,11 +154,11 @@ enum HeaderParseState {
/// assert_eq!(parsed.get_key().unwrap(), "Subject");
/// assert_eq!(parsed.get_value().unwrap(), "Hello, sir, I am multiline");
/// ```
-pub fn parse_header(raw_data: &[u8]) -> Result<(MailHeader, usize), MailParseError> {
+pub fn parse_header(raw_data: &[u8]) -> Result<(MailHeader, usize)> {
let mut it = raw_data.iter();
let mut ix = 0;
let mut c = match it.next() {
- None => return Err(MailParseError::Generic("Empty string provided")),
+ None => return Err(format_err!("Empty string provided")),
Some(v) => *v,
};
@@ -171,11 +171,7 @@ pub fn parse_header(raw_data: &[u8]) -> Result<(MailHeader, usize), MailParseErr
match state {
HeaderParseState::Initial => {
if c == b' ' {
- return Err(MailParseError::Generic(
- "Header cannot start with a space; it is \
- likely an overhanging line from a \
- previous header",
- ));
+ return Err(format_err!("Header cannot start with a space; it is likely an overhanging line from a previous header"));
};
state = HeaderParseState::Key;
continue;
@@ -185,7 +181,7 @@ pub fn parse_header(raw_data: &[u8]) -> Result<(MailHeader, usize), MailParseErr
ix_key_end = Some(ix);
state = HeaderParseState::PreValue;
} else if c == b'\n' {
- return Err(MailParseError::Generic("Unexpected newline in header key"));
+ return Err(format_err!("Unexpected newline in header key"));
}
}
HeaderParseState::PreValue => {
@@ -227,9 +223,7 @@ pub fn parse_header(raw_data: &[u8]) -> Result<(MailHeader, usize), MailParseErr
ix,
)),
- None => Err(MailParseError::Generic(
- "Unable to determine end of the header key component",
- )),
+ None => Err(format_err!("Unable to determine end of the header key component")),
}
}
@@ -253,7 +247,7 @@ pub trait MailHeaderMap {
/// .unwrap().headers;
/// assert_eq!(headers.get_first_value("Subject").unwrap(), Some("Test".to_string()));
/// ```
- fn get_first_value(&self, key: &str) -> Result<Option<String>, MailParseError>;
+ fn get_first_value(&self, key: &str) -> Result<Option<String>>;
/// Look through the list of headers and return the values of all headers
/// matching the provided key. Returns an empty vector if no matching headers
@@ -272,11 +266,11 @@ pub trait MailHeaderMap {
/// assert_eq!(headers.get_all_values("Key").unwrap(),
/// vec!["Value1".to_string(), "Value2".to_string()]);
/// ```
- fn get_all_values(&self, key: &str) -> Result<Vec<String>, MailParseError>;
+ fn get_all_values(&self, key: &str) -> Result<Vec<String>>;
}
impl<'a> MailHeaderMap for [MailHeader<'a>] {
- fn get_first_value(&self, key: &str) -> Result<Option<String>, MailParseError> {
+ fn get_first_value(&self, key: &str) -> Result<Option<String>> {
for x in self {
if x.get_key()?.eq_ignore_ascii_case(key) {
return x.get_value().map(Some);
@@ -285,7 +279,7 @@ impl<'a> MailHeaderMap for [MailHeader<'a>] {
Ok(None)
}
- fn get_all_values(&self, key: &str) -> Result<Vec<String>, MailParseError> {
+ fn get_all_values(&self, key: &str) -> Result<Vec<String>> {
let mut values: Vec<String> = Vec::new();
for x in self {
if x.get_key()?.eq_ignore_ascii_case(key) {
@@ -320,7 +314,7 @@ impl<'a> MailHeaderMap for [MailHeader<'a>] {
/// assert_eq!(headers[1].get_key().unwrap(), "From");
/// assert_eq!(headers.get_first_value("To").unwrap(), Some("you@yourself.com".to_string()));
/// ```
-pub fn parse_headers(raw_data: &[u8]) -> Result<(Vec<MailHeader>, usize), MailParseError> {
+pub fn parse_headers(raw_data: &[u8]) -> Result<(Vec<MailHeader>, usize)> {
let mut headers: Vec<MailHeader> = Vec::new();
let mut ix = 0;
loop {
@@ -334,10 +328,7 @@ pub fn parse_headers(raw_data: &[u8]) -> Result<(Vec<MailHeader>, usize), MailPa
ix += 2;
break;
} else {
- return Err(MailParseError::Generic(
- "Headers were followed by an unexpected lone \
- CR character!",
- ));
+ return Err(format_err!("Headers were followed by an unexpected lone CR character!"));
}
}
let (header, ix_next) = parse_header(&raw_data[ix..])?;
diff --git a/parser/src/lib.rs b/parser/src/lib.rs
index 2c8c5a3..c4a7676 100644
--- a/parser/src/lib.rs
+++ b/parser/src/lib.rs
@@ -1,4 +1,4 @@
-extern crate failure;
+#[macro_use] extern crate failure;
extern crate mail_core;
extern crate mail_headers;
extern crate serde;
@@ -11,7 +11,6 @@ extern crate quoted_printable;
mod addrparse;
mod body;
mod dateparse;
-mod error;
mod util;
mod header;
diff --git a/parser/src/parser.rs b/parser/src/parser.rs
index 136afb6..a1cbb53 100644
--- a/parser/src/parser.rs
+++ b/parser/src/parser.rs
@@ -1,11 +1,11 @@
use std::collections::BTreeMap;
+use failure::Fallible as Result;
use charset::decode_latin1;
use charset::Charset;
use crate::body::Body;
use crate::util::*;
-use crate::error::*;
use crate::header::*;
/// A struct to hold a more structured representation of the Content-Type header.
@@ -196,13 +196,11 @@ impl<'a> ParsedMail<'a> {
/// .unwrap();
/// assert_eq!(p.get_body().unwrap(), "This is the body");
/// ```
- pub fn get_body(&self) -> Result<String, MailParseError> {
+ pub fn get_body(&self) -> Result<String> {
match self.get_body_encoded()? {
Body::Base64(body) | Body::QuotedPrintable(body) => body.get_decoded_as_string(),
Body::SevenBit(body) | Body::EightBit(body) => body.get_as_string(),
- Body::Binary(_) => Err(MailParseError::Generic(
- "Message body of type binary body cannot be parsed into a string",
- )),
+ Body::Binary(_) => Err(format_err!("Message body of type binary body cannot be parsed into a string")),
}
}
@@ -220,7 +218,7 @@ impl<'a> ParsedMail<'a> {
/// .unwrap();
/// assert_eq!(p.get_body_raw().unwrap(), b"This is the body");
/// ```
- pub fn get_body_raw(&self) -> Result<Vec<u8>, MailParseError> {
+ pub fn get_body_raw(&self) -> Result<Vec<u8>> {
match self.get_body_encoded()? {
Body::Base64(body) | Body::QuotedPrintable(body) => body.get_decoded(),
Body::SevenBit(body) | Body::EightBit(body) => Ok(Vec::<u8>::from(body.get_raw())),
@@ -267,7 +265,7 @@ impl<'a> ParsedMail<'a> {
/// }
/// }
/// ```
- pub fn get_body_encoded(&'a self) -> Result<Body<'a>, MailParseError> {
+ pub fn get_body_encoded(&'a self) -> Result<Body<'a>> {
let transfer_encoding = self
.headers
.get_first_value("Content-Transfer-Encoding")?
@@ -281,7 +279,7 @@ impl<'a> ParsedMail<'a> {
/// is used, if there are multiple. See the `parse_content_disposition`
/// method documentation for more details on the semantics of the
/// returned object.
- pub fn get_content_disposition(&self) -> Result<ParsedContentDisposition, MailParseError> {
+ pub fn get_content_disposition(&self) -> Result<ParsedContentDisposition> {
let disposition = self
.headers
.get_first_value("Content-Disposition")?
@@ -328,7 +326,7 @@ impl<'a> ParsedMail<'a> {
/// assert!(parsed.subparts[1].get_body().unwrap().starts_with("<html>"));
/// assert_eq!(dateparse(parsed.headers.get_first_value("Date").unwrap().unwrap().as_str()).unwrap(), 1475417182);
/// ```
-pub fn parse_mail(raw_data: &[u8]) -> Result<ParsedMail, MailParseError> {
+pub fn parse_mail(raw_data: &[u8]) -> Result<ParsedMail> {
let (headers, ix_body) = parse_headers(raw_data)?;
let ctype = headers
.get_first_value("Content-Type")?
@@ -655,14 +653,8 @@ mod tests {
Some("CRLF".to_string())
);
- assert_match!(
- parse_headers(b"Bad\nKey").unwrap_err(),
- MailParseError::Generic(_)
- );
- assert_match!(
- parse_headers(b"K:V\nBad\nKey").unwrap_err(),
- MailParseError::Generic(_)
- );
+ assert!(parse_headers(b"Bad\nKey").is_err());
+ assert!(parse_headers(b"K:V\nBad\nKey").is_err());
}
#[test]