From 5e3832272b7b0b9b02ce88398e3b56ecc8f9e2a2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 27 Jul 2017 12:27:52 -0700 Subject: [PATCH] Add owned variants for each error For all fallible functions that consume `Bytes` a new `InvalidFooShared` error has been added. Eventually this extra error type can retain the input `Bytes` payload to be re-acquired on error if necessary. Closes #48 --- src/error.rs | 24 +++++++++++++++++++++++ src/header/mod.rs | 2 ++ src/header/name.rs | 20 ++++++++++++++++++-- src/header/value.rs | 25 ++++++++++++++++++++---- src/uri.rs | 46 +++++++++++++++++++++++++++++++++------------ 5 files changed, 99 insertions(+), 18 deletions(-) diff --git a/src/error.rs b/src/error.rs index de9ea87..af1b161 100644 --- a/src/error.rs +++ b/src/error.rs @@ -26,8 +26,11 @@ enum ErrorKind { StatusCode(status::InvalidStatusCode), Method(method::InvalidMethod), Uri(uri::InvalidUri), + UriShared(uri::InvalidUriBytes), HeaderName(header::InvalidHeaderName), + HeaderNameShared(header::InvalidHeaderNameBytes), HeaderValue(header::InvalidHeaderValue), + HeaderValueShared(header::InvalidHeaderValueBytes), } impl fmt::Display for Error { @@ -44,8 +47,11 @@ impl error::Error for Error { StatusCode(ref e) => e.description(), Method(ref e) => e.description(), Uri(ref e) => e.description(), + UriShared(ref e) => e.description(), HeaderName(ref e) => e.description(), + HeaderNameShared(ref e) => e.description(), HeaderValue(ref e) => e.description(), + HeaderValueShared(ref e) => e.description(), } } } @@ -68,14 +74,32 @@ impl From for Error { } } +impl From for Error { + fn from(err: uri::InvalidUriBytes) -> Error { + Error { inner: ErrorKind::UriShared(err) } + } +} + impl From for Error { fn from(err: header::InvalidHeaderName) -> Error { Error { inner: ErrorKind::HeaderName(err) } } } +impl From for Error { + fn from(err: header::InvalidHeaderNameBytes) -> Error { + Error { inner: ErrorKind::HeaderNameShared(err) } + } +} + impl From for Error { fn from(err: header::InvalidHeaderValue) -> Error { Error { inner: ErrorKind::HeaderValue(err) } } } + +impl From for Error { + fn from(err: header::InvalidHeaderValueBytes) -> Error { + Error { inner: ErrorKind::HeaderValueShared(err) } + } +} diff --git a/src/header/mod.rs b/src/header/mod.rs index 2cb8707..da73e04 100644 --- a/src/header/mod.rs +++ b/src/header/mod.rs @@ -93,10 +93,12 @@ pub use self::map::{ pub use self::name::{ HeaderName, InvalidHeaderName, + InvalidHeaderNameBytes, }; pub use self::value::{ HeaderValue, InvalidHeaderValue, + InvalidHeaderValueBytes, ToStrError, }; diff --git a/src/header/name.rs b/src/header/name.rs index 3ca8514..74ac07c 100644 --- a/src/header/name.rs +++ b/src/header/name.rs @@ -61,6 +61,10 @@ pub struct InvalidHeaderName { _priv: (), } +/// A possible error when converting a `HeaderName` from another type. +#[derive(Debug)] +pub struct InvalidHeaderNameBytes(InvalidHeaderName) ; + macro_rules! standard_headers { ( $( @@ -1558,10 +1562,10 @@ impl<'a> HttpTryFrom<&'a [u8]> for HeaderName { } impl HttpTryFrom for HeaderName { - type Error = InvalidHeaderName; + type Error = InvalidHeaderNameBytes; #[inline] fn try_from(bytes: Bytes) -> Result { - Self::from_bytes(bytes.as_ref()) + Self::from_bytes(bytes.as_ref()).map_err(InvalidHeaderNameBytes) } } @@ -1628,6 +1632,18 @@ impl Error for InvalidHeaderName { } } +impl fmt::Display for InvalidHeaderNameBytes { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl Error for InvalidHeaderNameBytes { + fn description(&self) -> &str { + self.0.description() + } +} + // ===== HdrName ===== impl<'a> HdrName<'a> { diff --git a/src/header/value.rs b/src/header/value.rs index 58d2a98..5415b60 100644 --- a/src/header/value.rs +++ b/src/header/value.rs @@ -28,6 +28,11 @@ pub struct InvalidHeaderValue { _priv: (), } +/// A possible error when converting a `HeaderValue` from a string or byte +/// slice. +#[derive(Debug)] +pub struct InvalidHeaderValueBytes(InvalidHeaderValue); + /// A possible error when converting a `HeaderValue` to a string representation. /// /// Header field values may contain opaque bytes, in which case it is not @@ -137,8 +142,8 @@ impl HeaderValue { /// This function is intended to be replaced in the future by a `TryFrom` /// implementation once the trait is stabilized in std. #[inline] - pub fn try_from_shared(src: Bytes) -> Result { - HeaderValue::try_from(src) + pub fn try_from_shared(src: Bytes) -> Result { + HeaderValue::try_from(src).map_err(InvalidHeaderValueBytes) } fn try_from + Into>(src: T) -> Result { @@ -324,11 +329,11 @@ impl<'a> HttpTryFrom<&'a [u8]> for HeaderValue { } impl HttpTryFrom for HeaderValue { - type Error = InvalidHeaderValue; + type Error = InvalidHeaderValueBytes; #[inline] fn try_from(bytes: Bytes) -> Result { - ::try_from(bytes) + HeaderValue::try_from_shared(bytes) } } @@ -369,6 +374,18 @@ impl Error for InvalidHeaderValue { } } +impl fmt::Display for InvalidHeaderValueBytes { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl Error for InvalidHeaderValueBytes { + fn description(&self) -> &str { + self.0.description() + } +} + impl fmt::Display for ToStrError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.description().fmt(f) diff --git a/src/uri.rs b/src/uri.rs index 75732e3..0d33b31 100644 --- a/src/uri.rs +++ b/src/uri.rs @@ -100,6 +100,10 @@ pub struct Parts { #[derive(Debug)] pub struct InvalidUri(ErrorKind); +/// An error resulting from a failed attempt to construct a URI. +#[derive(Debug)] +pub struct InvalidUriBytes(InvalidUri); + #[derive(Debug, Eq, PartialEq)] enum ErrorKind { InvalidUriChar, @@ -204,7 +208,7 @@ impl Uri { /// assert_eq!(uri.path(), "/foo"); /// # } /// ``` - pub fn try_from_shared(s: Bytes) -> Result { + pub fn try_from_shared(s: Bytes) -> Result { use self::ErrorKind::*; if s.len() > MAX_LEN { @@ -553,7 +557,7 @@ impl<'a> HttpTryFrom<&'a str> for Uri { } impl HttpTryFrom for Uri { - type Error = InvalidUri; + type Error = InvalidUriBytes; #[inline] fn try_from(t: Bytes) -> Result { @@ -679,10 +683,10 @@ impl Scheme { /// assert_eq!(scheme.as_str(), "http"); /// # } /// ``` - pub fn try_from_shared(s: Bytes) -> Result { + pub fn try_from_shared(s: Bytes) -> Result { use self::Scheme2::*; - match try!(Scheme2::parse_exact(&s[..])) { + match try!(Scheme2::parse_exact(&s[..]).map_err(InvalidUriBytes)) { None => Err(ErrorKind::InvalidScheme.into()), Standard(p) => Ok(Standard(p).into()), Other(_) => { @@ -892,8 +896,8 @@ impl Authority { /// assert_eq!(authority.host(), "example.com"); /// # } /// ``` - pub fn try_from_shared(s: Bytes) -> Result { - let authority_end = try!(Authority::parse(&s[..])); + pub fn try_from_shared(s: Bytes) -> Result { + let authority_end = try!(Authority::parse(&s[..]).map_err(InvalidUriBytes)); if authority_end != s.len() { return Err(ErrorKind::InvalidUriChar.into()); @@ -1031,7 +1035,7 @@ impl OriginForm { /// assert_eq!(origin_form.query(), Some("world")); /// # } /// ``` - pub fn try_from_shared(mut src: Bytes) -> Result { + pub fn try_from_shared(mut src: Bytes) -> Result { let mut query = NONE; for i in 0..src.len() { @@ -1174,7 +1178,7 @@ impl FromStr for OriginForm { type Err = InvalidUri; fn from_str(s: &str) -> Result { - OriginForm::try_from_shared(s.into()) + OriginForm::try_from_shared(s.into()).map_err(|e| e.0) } } @@ -1203,9 +1207,9 @@ impl fmt::Display for OriginForm { } } -fn parse_full(mut s: Bytes) -> Result { +fn parse_full(mut s: Bytes) -> Result { // Parse the scheme - let scheme = match try!(Scheme2::parse(&s[..])) { + let scheme = match try!(Scheme2::parse(&s[..]).map_err(InvalidUriBytes)) { Scheme2::None => Scheme2::None, Scheme2::Standard(p) => { // TODO: use truncate @@ -1228,7 +1232,7 @@ fn parse_full(mut s: Bytes) -> Result { // Find the end of the authority. The scheme will already have been // extracted. - let authority_end = try!(Authority::parse(&s[..])); + let authority_end = try!(Authority::parse(&s[..]).map_err(InvalidUriBytes)); if scheme.is_none() { if authority_end != s.len() { @@ -1284,7 +1288,7 @@ impl FromStr for Uri { #[inline] fn from_str(s: &str) -> Result { - Uri::try_from_shared(s.into()) + Uri::try_from_shared(s.into()).map_err(|e| e.0) } } @@ -1441,6 +1445,12 @@ impl From for InvalidUri { } } +impl From for InvalidUriBytes { + fn from(src: ErrorKind) -> InvalidUriBytes { + InvalidUriBytes(src.into()) + } +} + impl fmt::Display for InvalidUri { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.description().fmt(f) @@ -1461,6 +1471,18 @@ impl Error for InvalidUri { } } +impl fmt::Display for InvalidUriBytes { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl Error for InvalidUriBytes { + fn description(&self) -> &str { + self.0.description() + } +} + impl From for Scheme2 { fn from(src: Protocol) -> Self { Scheme2::Standard(src)