minio_rsc/
error.rs

1//! Error and Result module.
2use http::{
3    header::{InvalidHeaderName, InvalidHeaderValue},
4    Error as RequestError,
5};
6use serde::Deserialize;
7use std::convert::Infallible;
8use std::result;
9
10/// A `Result` typedef to use with the [minio-rsc::error](Error) type
11pub type Result<T> = result::Result<T, Error>;
12
13/// Indicates an illegal variable was used.
14#[derive(thiserror::Error, Debug)]
15#[error("value error: {0}")]
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 From<&str> for ValueError {
25    fn from(err: &str) -> Self {
26        Self(err.to_string())
27    }
28}
29
30impl From<InvalidHeaderValue> for ValueError {
31    fn from(err: InvalidHeaderValue) -> Self {
32        return ValueError(err.to_string());
33    }
34}
35
36impl From<InvalidHeaderName> for ValueError {
37    fn from(err: InvalidHeaderName) -> Self {
38        return ValueError(err.to_string());
39    }
40}
41
42impl From<Infallible> for ValueError {
43    fn from(err: Infallible) -> Self {
44        return ValueError(err.to_string());
45    }
46}
47
48impl From<http::uri::InvalidUri> for ValueError {
49    fn from(err: http::uri::InvalidUri) -> Self {
50        return ValueError(err.to_string());
51    }
52}
53
54/// S3 service returned error response.
55#[derive(thiserror::Error, Debug, Deserialize)]
56#[serde(rename_all = "PascalCase", rename = "Error")]
57#[error("S3Error: {message}")]
58pub struct S3Error {
59    pub code: String,
60    pub message: String,
61    #[serde(default)]
62    pub resource: String,
63    pub request_id: String,
64    pub host_id: Option<String>,
65    pub bucket_name: Option<String>,
66    pub object_name: Option<String>,
67}
68
69impl TryFrom<&[u8]> for S3Error {
70    type Error = crate::xml::error::Error;
71    fn try_from(res: &[u8]) -> std::result::Result<Self, Self::Error> {
72        return Ok(crate::xml::de::from_reader(res)?);
73    }
74}
75
76impl TryFrom<&str> for S3Error {
77    type Error = crate::xml::error::Error;
78    fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
79        value.as_bytes().try_into()
80    }
81}
82
83/// InternalException - thrown to indicate internal library error.
84/// ErrorResponseException - thrown to indicate S3 service returned an error response.
85/// thrown to indicate I/O error on S3 operation.
86/// ServerException Thrown to indicate that S3 service returning HTTP server error.
87#[derive(thiserror::Error, Debug)]
88pub enum Error {
89    /// inducate an illegal variable was used.
90    #[error("{0}")]
91    ValueError(String),
92
93    /// indicate conncet to S3 service failed.
94    #[error("{0}")]
95    RequestError(#[from] RequestError),
96
97    /// indicate XML parsing error.
98    #[error("{0}")]
99    XmlError(#[from] crate::xml::error::Error),
100
101    /// indicate S3 service returned error response.
102    #[error("{0}")]
103    S3Error(#[from] S3Error),
104
105    /// indicate S3 service returned invalid or no error response.
106    #[error("{0}")]
107    HttpError(#[from] reqwest::Error),
108
109    /// indicate the http response returned is not expected by S3.
110    #[error("Unexpected HTTP responses, status: {}", .0.status())]
111    UnknownResponse(reqwest::Response),
112
113    /// Message decoding failed in `select object content`.
114    #[error("{0}")]
115    MessageDecodeError(String),
116
117    /// return an Error Message in `select_object_content`.
118    #[error("{0}")]
119    SelectObjectError(String),
120
121    /// indicate I/O error, had on S3 operation.
122    #[error("{0}")]
123    IoError(#[from] std::io::Error),
124}
125
126impl<T: Into<ValueError>> From<T> for Error {
127    fn from(err: T) -> Self {
128        Error::ValueError(err.into().0)
129    }
130}
131
132impl From<reqwest::Response> for Error {
133    fn from(err: reqwest::Response) -> Self {
134        Self::UnknownResponse(err)
135    }
136}
137
138#[cfg(test)]
139mod tests {
140    use super::S3Error;
141    use crate::xml::error::Error as XmlError;
142
143    #[test]
144    fn test_s3_error() {
145        let res = r#"<?xml version="1.0" encoding="UTF-8"?>
146        <Error>
147            <Code>NoSuchKey</Code>
148            <Message>The resource you requested does not exist</Message>
149            <Resource>/mybucket/myfoto.jpg</Resource>
150            <RequestId>4442587FB7D0A2F9</RequestId>
151        </Error>"#;
152        let result: std::result::Result<S3Error, XmlError> = res.as_bytes().try_into();
153        assert!(result.is_ok());
154        println!("{:?}", result);
155    }
156}