rustfs_rsc/
error.rs

1//! Error and Result module.
2use core::fmt;
3use hyper::{
4    header::{InvalidHeaderName, InvalidHeaderValue},
5    Error as RequestError,
6};
7use serde::Deserialize;
8use std::{convert::Infallible, error::Error as StdError};
9use std::{fmt::Display, result};
10
11/// A `Result` typedef to use with the `minio-rsc::error` type
12pub type Result<T> = result::Result<T, Error>;
13
14/// inducate an illegal variable was used.
15#[derive(Debug)]
16pub struct ValueError(String);
17
18impl ValueError {
19    pub fn new<T: Into<String>>(value: T) -> Self {
20        Self(value.into())
21    }
22}
23
24impl Display for ValueError {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        write!(f, "value error: {}", self.0)
27    }
28}
29
30impl StdError for ValueError {}
31
32impl From<&str> for ValueError {
33    fn from(err: &str) -> Self {
34        Self(err.to_string())
35    }
36}
37
38impl From<InvalidHeaderValue> for ValueError {
39    fn from(err: InvalidHeaderValue) -> Self {
40        return ValueError(err.to_string());
41    }
42}
43
44impl From<InvalidHeaderName> for ValueError {
45    fn from(err: InvalidHeaderName) -> Self {
46        return ValueError(err.to_string());
47    }
48}
49
50impl From<Infallible> for ValueError {
51    fn from(err: Infallible) -> Self {
52        return ValueError(err.to_string());
53    }
54}
55
56/// XML parsing error.
57#[derive(Debug)]
58pub struct XmlError(String);
59
60impl Display for XmlError {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        write!(f, "xmlerror: {}", self.0)
63    }
64}
65
66impl StdError for XmlError {}
67
68impl From<crate::xml::error::Error> for XmlError {
69    fn from(err: crate::xml::error::Error) -> Self {
70        Self(err.to_string())
71    }
72}
73
74/// S3 service returned error response.
75///
76#[derive(Debug, Deserialize)]
77#[serde(rename_all = "PascalCase", rename="Error")]
78pub struct S3Error {
79    pub code: String,
80    pub message: String,
81    #[serde(default)]
82    pub resource: String,
83    pub request_id: String,
84    pub host_id: Option<String>,
85    pub bucket_name: Option<String>,
86    pub object_name: Option<String>,
87}
88
89impl std::fmt::Display for S3Error {
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        write!(f, "S3Error: {}", self.message)
92    }
93}
94
95impl StdError for S3Error {}
96
97impl TryFrom<&[u8]> for S3Error {
98    type Error = XmlError;
99    fn try_from(res: &[u8]) -> std::result::Result<Self, Self::Error> {
100        return Ok(crate::xml::de::from_reader(res)?);
101    }
102}
103
104impl TryFrom<&str> for S3Error {
105    type Error = XmlError;
106
107    fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
108        value.as_bytes().try_into()
109    }
110}
111
112/// InternalException - thrown to indicate internal library error.
113/// ErrorResponseException - thrown to indicate S3 service returned an error response.
114/// thrown to indicate I/O error on S3 operation.
115/// ServerException Thrown to indicate that S3 service returning HTTP server error.
116#[derive(Debug)]
117pub enum Error {
118    /// inducate an illegal variable was used.
119    ValueError(String),
120
121    /// indicate conncet to S3 service failed.
122    RequestError(RequestError),
123
124    /// indicate XML parsing error.
125    XmlError(XmlError),
126
127    /// indicate S3 service returned error response.
128    S3Error(S3Error),
129
130    /// indicate S3 service returned invalid or no error response.
131    HttpError(reqwest::Error),
132
133    /// indicate the http response returned is not expected by S3.
134    UnknownResponse(reqwest::Response),
135
136    /// Message decoding failed in `select object content`.
137    MessageDecodeError(String),
138
139    /// return an Error Message in `select_object_content`.
140    SelectObejectError(String),
141
142    /// indicate I/O error, had on S3 operation.
143    IoError(std::io::Error),
144}
145
146impl StdError for Error {
147    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
148        match self {
149            Error::RequestError(e) => e.source(),
150            Error::S3Error(e) => e.source(),
151            _ => None,
152        }
153    }
154}
155
156#[rustfmt::skip]
157impl fmt::Display for Error {
158    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159        match &self {
160            Error::ValueError(e) => write!(f, "{}", e),
161            Error::RequestError(e) => write!(f, "{}", e),
162            Error::XmlError(e) => write!(f, "{}", e),
163            Error::S3Error(e) => write!(f, "{}", e),
164            Error::HttpError(e) => write!(f, "{}", e),
165            Error::UnknownResponse(e) => write!(f, "Unexpected HTTP responses, status: {}", e.status()),
166            Error::MessageDecodeError(e)=> write!(f, "{}", e),
167            Error::SelectObejectError(e)=> write!(f, "{}", e),
168            Error::IoError(e) => write!(f, "{}", e),
169        }
170    }
171}
172
173impl From<S3Error> for Error {
174    fn from(err: S3Error) -> Self {
175        Error::S3Error(err)
176    }
177}
178
179// impl From<MinioError> for Error {
180//     fn from(err: MinioError) -> Self {
181//         Self { inner: err }
182//     }
183// }
184
185impl<T: Into<ValueError>> From<T> for Error {
186    fn from(err: T) -> Self {
187        Error::ValueError(err.into().0)
188    }
189}
190
191impl From<XmlError> for Error {
192    fn from(err: XmlError) -> Self {
193        Error::XmlError(err)
194    }
195}
196
197impl From<RequestError> for Error {
198    fn from(err: RequestError) -> Self {
199        Error::RequestError(err)
200    }
201}
202
203impl From<std::io::Error> for Error {
204    fn from(err: std::io::Error) -> Self {
205        std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "");
206        Error::IoError(err)
207    }
208}
209
210impl From<reqwest::Error> for Error {
211    fn from(err: reqwest::Error) -> Self {
212        if err.is_builder() {
213            return Self::ValueError(err.to_string());
214        }
215        Self::HttpError(err)
216    }
217}
218
219impl From<reqwest::Response> for Error {
220    fn from(err: reqwest::Response) -> Self {
221        Self::UnknownResponse(err)
222    }
223}
224
225impl From<crate::xml::error::Error> for Error {
226    fn from(err: crate::xml::error::Error) -> Self {
227        Error::XmlError(err.into())
228    }
229}
230
231#[cfg(test)]
232mod tests {
233    use super::S3Error;
234    use crate::error::XmlError;
235
236    #[test]
237    fn test_s3_error() {
238        let res = r#"<?xml version="1.0" encoding="UTF-8"?>
239        <Error>
240            <Code>NoSuchKey</Code>
241            <Message>The resource you requested does not exist</Message>
242            <Resource>/mybucket/myfoto.jpg</Resource>
243            <RequestId>4442587FB7D0A2F9</RequestId>
244        </Error>"#;
245        let result: std::result::Result<S3Error, XmlError> = res.as_bytes().try_into();
246        assert!(result.is_ok());
247        println!("{:?}", result);
248    }
249}