1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use std::error::Error;
use std::fmt;
use std::io;

use crate::credential::CredentialsError;

use super::proto::xml::util::XmlParseError;
use super::request::{BufferedHttpResponse, HttpDispatchError};
use crate::client::SignAndDispatchError;

/// Generic error type returned by all rusoto requests.
#[derive(Debug, PartialEq)]
pub enum RusotoError<E> {
    /// A service-specific error occurred.
    Service(E),
    /// An error occurred dispatching the HTTP request
    HttpDispatch(HttpDispatchError),
    /// The endpoint sub-domain has invalid DNS name. (Only S3 service will generate this error)
    InvalidDnsName(InvalidDnsNameError),
    /// An error was encountered with AWS credentials.
    Credentials(CredentialsError),
    /// A validation error occurred.  Details from AWS are provided.
    Validation(String),
    /// An error occurred parsing the response payload.
    ParseError(String),
    /// An unknown error occurred.  The raw HTTP response is provided.
    Unknown(BufferedHttpResponse),
    /// An error occurred when attempting to run a future as blocking
    Blocking,
}

/// Result carrying a generic `RusotoError`.
pub type RusotoResult<T, E> = Result<T, RusotoError<E>>;

/// Header used by AWS on responses to identify the request
pub const AWS_REQUEST_ID_HEADER: &str = "x-amzn-requestid";

impl<E> From<XmlParseError> for RusotoError<E> {
    fn from(err: XmlParseError) -> Self {
        let XmlParseError(message) = err;
        RusotoError::ParseError(message)
    }
}

impl<E> From<serde_json::error::Error> for RusotoError<E> {
    fn from(err: serde_json::error::Error) -> Self {
        RusotoError::ParseError(err.to_string())
    }
}

impl<E> From<CredentialsError> for RusotoError<E> {
    fn from(err: CredentialsError) -> Self {
        RusotoError::Credentials(err)
    }
}

impl<E> From<HttpDispatchError> for RusotoError<E> {
    fn from(err: HttpDispatchError) -> Self {
        RusotoError::HttpDispatch(err)
    }
}

impl<E> From<SignAndDispatchError> for RusotoError<E> {
    fn from(err: SignAndDispatchError) -> Self {
        match err {
            SignAndDispatchError::Credentials(e) => Self::from(e),
            SignAndDispatchError::Dispatch(e) => Self::from(e),
        }
    }
}

impl<E> From<io::Error> for RusotoError<E> {
    fn from(err: io::Error) -> Self {
        RusotoError::HttpDispatch(HttpDispatchError::from(err))
    }
}

impl<E: Error + 'static> fmt::Display for RusotoError<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            RusotoError::Service(ref err) => write!(f, "{}", err),
            RusotoError::Validation(ref cause) => write!(f, "{}", cause),
            RusotoError::Credentials(ref err) => write!(f, "{}", err),
            RusotoError::HttpDispatch(ref dispatch_error) => write!(f, "{}", dispatch_error),
            RusotoError::InvalidDnsName(ref dns_error) => write!(f, "{}", dns_error),
            RusotoError::ParseError(ref cause) => write!(f, "{}", cause),
            RusotoError::Unknown(ref cause) => write!(
                f,
                "Request ID: {:?} Body: {}",
                cause.headers.get(AWS_REQUEST_ID_HEADER),
                cause.body_as_str()
            ),
            RusotoError::Blocking => write!(f, "Failed to run blocking future"),
        }
    }
}

impl<E: Error + 'static> Error for RusotoError<E> {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match *self {
            RusotoError::Service(ref err) => Some(err),
            RusotoError::Credentials(ref err) => Some(err),
            RusotoError::HttpDispatch(ref err) => Some(err),
            _ => None,
        }
    }
}

/// The endpoint sub-domain has invalid DNS name. (Only S3 service will generate this error)
#[derive(Clone, Debug, PartialEq)]
pub struct InvalidDnsNameError {
    message: String,
}

impl InvalidDnsNameError {
    /// Creates a new `InvalidDnsNameError` with the message.
    pub fn new(message: String) -> Self {
        Self { message }
    }
}

impl Error for InvalidDnsNameError {}

impl fmt::Display for InvalidDnsNameError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.message)
    }
}