From 6a094db668f3e968bf8da79a97fe9a205dfc8bfb Mon Sep 17 00:00:00 2001 From: Martin Algesten Date: Sun, 19 Dec 2021 12:43:58 +0100 Subject: [PATCH] Provide access methods for error::Transport .message() and .kind() so that the user can get the details of a transport error. This also documents the motivation for the different fields --- src/error.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/src/error.rs b/src/error.rs index a601f85..3945bab 100644 --- a/src/error.rs +++ b/src/error.rs @@ -86,8 +86,28 @@ pub enum Error { Transport(Transport), } -// Any error that is not a status code error. For instance, DNS name not found, -// connection refused, or malformed response. +impl Error { + pub fn into_transport(self) -> Option { + match self { + Error::Status(_, _) => None, + Error::Transport(t) => Some(t), + } + } + + pub fn into_response(self) -> Option { + match self { + Error::Status(_, r) => Some(r), + Error::Transport(_) => None, + } + } +} + +/// Error that is not a status code error. For instance, DNS name not found, +/// connection refused, or malformed response. +/// +/// * [`Transport::kind()`] provides a classification (same as for [`Error::kind`]). +/// * [`Transport::message()`] might vary for the same classification to give more context. +/// * [`Transport::source()`](std::error::Error::source) holds the underlying error with even more details. #[derive(Debug)] pub struct Transport { kind: ErrorKind, @@ -96,6 +116,51 @@ pub struct Transport { source: Option>, } +impl Transport { + /// The type of error that happened while processing the request. + pub fn kind(&self) -> ErrorKind { + self.kind + } + + /// Higher level error details, if there are any. + /// + /// ``` + /// use ureq::ErrorKind; + /// use std::error::Error; + /// use url::ParseError; + /// + /// let result = ureq::get("broken/url").call(); + /// let error = result.unwrap_err().into_transport().unwrap(); + /// + /// // the display trait is a combo of the underlying classifications + /// assert_eq!(error.to_string(), + /// "Bad URL: failed to parse URL: RelativeUrlWithoutBase: relative URL without a base"); + /// + /// // classification + /// assert_eq!(error.kind(), ErrorKind::InvalidUrl); + /// assert_eq!(error.kind().to_string(), "Bad URL"); + + /// // higher level message + /// assert_eq!(error.message(), Some("failed to parse URL: RelativeUrlWithoutBase")); + /// + /// // boxed underlying error + /// let source = error.source().unwrap(); + /// // downcast to original error + /// let downcast = source.downcast_ref::().unwrap(); + /// + /// assert_eq!(downcast.to_string(), "relative URL without a base"); + /// ``` + pub fn message(&self) -> Option<&str> { + self.message.as_deref() + } + + /// The url that failed. This can be interesting in cases of redirect where + /// the original url worked, but a later redirected to url fails. + pub fn url(&self) -> Option<&Url> { + self.url.as_ref() + } +} + /// Extension to [`Result`] for handling all status codes as [`Response`]. pub trait OrAnyStatus { /// Ergonomic helper for handling all status codes as [`Response`].