diff options
author | Alex Auvolat <alex@adnab.me> | 2022-05-13 15:04:53 +0200 |
---|---|---|
committer | Alex Auvolat <alex@adnab.me> | 2022-05-13 15:04:53 +0200 |
commit | 96b11524d53b3616a28f33e2b057655be1639f6f (patch) | |
tree | 324a8a9624c5b861fb5a09b0ae0e0c07f6b9614c /src/api/error.rs | |
parent | c0fb9fd0fe553e5eda39dcb1a09f059bcd631b6c (diff) | |
download | garage-96b11524d53b3616a28f33e2b057655be1639f6f.tar.gz garage-96b11524d53b3616a28f33e2b057655be1639f6f.zip |
Error refactoring
Diffstat (limited to 'src/api/error.rs')
-rw-r--r-- | src/api/error.rs | 127 |
1 files changed, 31 insertions, 96 deletions
diff --git a/src/api/error.rs b/src/api/error.rs index 90bfccef..3cb97019 100644 --- a/src/api/error.rs +++ b/src/api/error.rs @@ -7,24 +7,17 @@ use hyper::{Body, HeaderMap, StatusCode}; use garage_model::helper::error::Error as HelperError; use garage_util::error::Error as GarageError; +use crate::common_error::CommonError; +pub use crate::common_error::{OkOrBadRequest, OkOrInternalError}; use crate::generic_server::ApiError; use crate::s3::xml as s3_xml; /// Errors of this crate #[derive(Debug, Error)] pub enum Error { - // Category: internal error - /// Error related to deeper parts of Garage - #[error(display = "Internal error: {}", _0)] - InternalError(#[error(source)] GarageError), - - /// Error related to Hyper - #[error(display = "Internal error (Hyper error): {}", _0)] - Hyper(#[error(source)] hyper::Error), - - /// Error related to HTTP - #[error(display = "Internal error (HTTP error): {}", _0)] - Http(#[error(source)] http::Error), + #[error(display = "{}", _0)] + /// Error from common error + CommonError(CommonError), // Category: cannot process /// No proper api key was used, or the signature was invalid @@ -101,10 +94,6 @@ pub enum Error { #[error(display = "Invalid HTTP range: {:?}", _0)] InvalidRange(#[error(from)] (http_range::HttpRangeParseError, u64)), - /// The client sent an invalid request - #[error(display = "Bad request: {}", _0)] - BadRequest(String), - /// The client asked for an invalid return format (invalid Accept header) #[error(display = "Not acceptable: {}", _0)] NotAcceptable(String), @@ -114,6 +103,15 @@ pub enum Error { NotImplemented(String), } +impl<T> From<T> for Error +where + CommonError: From<T>, +{ + fn from(err: T) -> Self { + Error::CommonError(CommonError::from(err)) + } +} + impl From<roxmltree::Error> for Error { fn from(err: roxmltree::Error) -> Self { Self::InvalidXml(format!("{}", err)) @@ -129,16 +127,16 @@ impl From<quick_xml::de::DeError> for Error { impl From<HelperError> for Error { fn from(err: HelperError) -> Self { match err { - HelperError::Internal(i) => Self::InternalError(i), - HelperError::BadRequest(b) => Self::BadRequest(b), - e => Self::BadRequest(format!("{}", e)), + HelperError::Internal(i) => Self::CommonError(CommonError::InternalError(i)), + HelperError::BadRequest(b) => Self::CommonError(CommonError::BadRequest(b)), + e => Self::CommonError(CommonError::BadRequest(format!("{}", e))), } } } impl From<multer::Error> for Error { fn from(err: multer::Error) -> Self { - Self::BadRequest(err.to_string()) + Self::bad_request(err) } } @@ -157,18 +155,26 @@ impl Error { Error::Forbidden(_) => "AccessDenied", Error::AuthorizationHeaderMalformed(_) => "AuthorizationHeaderMalformed", Error::NotImplemented(_) => "NotImplemented", - Error::InternalError( + Error::CommonError(CommonError::InternalError( GarageError::Timeout | GarageError::RemoteError(_) | GarageError::Quorum(_, _, _, _), - ) => "ServiceUnavailable", - Error::InternalError(_) | Error::Hyper(_) | Error::Http(_) => "InternalError", + )) => "ServiceUnavailable", + Error::CommonError( + CommonError::InternalError(_) | CommonError::Hyper(_) | CommonError::Http(_), + ) => "InternalError", _ => "InvalidRequest", } } + pub fn internal_error<M: ToString>(msg: M) -> Self { + Self::CommonError(CommonError::InternalError(GarageError::Message( + msg.to_string(), + ))) + } + pub fn bad_request<M: ToString>(msg: M) -> Self { - Self::BadRequest(msg.to_string()) + Self::CommonError(CommonError::BadRequest(msg.to_string())) } } @@ -176,19 +182,12 @@ impl ApiError for Error { /// Get the HTTP status code that best represents the meaning of the error for the client fn http_status_code(&self) -> StatusCode { match self { + Error::CommonError(c) => c.http_status_code(), Error::NoSuchKey | Error::NoSuchBucket | Error::NoSuchUpload => StatusCode::NOT_FOUND, Error::BucketNotEmpty | Error::BucketAlreadyExists => StatusCode::CONFLICT, Error::PreconditionFailed => StatusCode::PRECONDITION_FAILED, Error::Forbidden(_) => StatusCode::FORBIDDEN, Error::NotAcceptable(_) => StatusCode::NOT_ACCEPTABLE, - Error::InternalError( - GarageError::Timeout - | GarageError::RemoteError(_) - | GarageError::Quorum(_, _, _, _), - ) => StatusCode::SERVICE_UNAVAILABLE, - Error::InternalError(_) | Error::Hyper(_) | Error::Http(_) => { - StatusCode::INTERNAL_SERVER_ERROR - } Error::InvalidRange(_) => StatusCode::RANGE_NOT_SATISFIABLE, Error::NotImplemented(_) => StatusCode::NOT_IMPLEMENTED, _ => StatusCode::BAD_REQUEST, @@ -230,67 +229,3 @@ impl ApiError for Error { })) } } - -/// Trait to map error to the Bad Request error code -pub trait OkOrBadRequest { - type S; - fn ok_or_bad_request<M: AsRef<str>>(self, reason: M) -> Result<Self::S, Error>; -} - -impl<T, E> OkOrBadRequest for Result<T, E> -where - E: std::fmt::Display, -{ - type S = T; - fn ok_or_bad_request<M: AsRef<str>>(self, reason: M) -> Result<T, Error> { - match self { - Ok(x) => Ok(x), - Err(e) => Err(Error::BadRequest(format!("{}: {}", reason.as_ref(), e))), - } - } -} - -impl<T> OkOrBadRequest for Option<T> { - type S = T; - fn ok_or_bad_request<M: AsRef<str>>(self, reason: M) -> Result<T, Error> { - match self { - Some(x) => Ok(x), - None => Err(Error::BadRequest(reason.as_ref().to_string())), - } - } -} - -/// Trait to map an error to an Internal Error code -pub trait OkOrInternalError { - type S; - fn ok_or_internal_error<M: AsRef<str>>(self, reason: M) -> Result<Self::S, Error>; -} - -impl<T, E> OkOrInternalError for Result<T, E> -where - E: std::fmt::Display, -{ - type S = T; - fn ok_or_internal_error<M: AsRef<str>>(self, reason: M) -> Result<T, Error> { - match self { - Ok(x) => Ok(x), - Err(e) => Err(Error::InternalError(GarageError::Message(format!( - "{}: {}", - reason.as_ref(), - e - )))), - } - } -} - -impl<T> OkOrInternalError for Option<T> { - type S = T; - fn ok_or_internal_error<M: AsRef<str>>(self, reason: M) -> Result<T, Error> { - match self { - Some(x) => Ok(x), - None => Err(Error::InternalError(GarageError::Message( - reason.as_ref().to_string(), - ))), - } - } -} |