diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2019-12-23 13:31:48 +0100 |
---|---|---|
committer | Matthias Beyer <mail@beyermatthias.de> | 2019-12-23 13:37:03 +0100 |
commit | 8d09639921ca29f36def0777102b55a1c762748c (patch) | |
tree | 478bf4e6911870279e467cc9121ffbfd6d3785fb | |
parent | d690505c02789525ced8920e14de394b0d771c77 (diff) |
Replace own error type with failureparsing
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r-- | parser/src/body.rs | 17 | ||||
-rw-r--r-- | parser/src/error.rs | 70 | ||||
-rw-r--r-- | parser/src/header.rs | 37 | ||||
-rw-r--r-- | parser/src/lib.rs | 3 | ||||
-rw-r--r-- | parser/src/parser.rs | 26 |
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] |