rustical_dav/
error.rs

1use http::StatusCode;
2use rustical_xml::XmlError;
3use thiserror::Error;
4use tracing::error;
5
6#[derive(Debug, Error)]
7pub enum Error {
8    #[error("Not found")]
9    NotFound,
10
11    #[error("Bad request: {0}")]
12    BadRequest(String),
13
14    #[error("Unauthorized")]
15    Unauthorized,
16
17    #[error("Internal server error :(")]
18    InternalError,
19
20    #[error("prop is read-only")]
21    PropReadOnly,
22
23    #[error(transparent)]
24    XmlError(#[from] rustical_xml::XmlError),
25
26    #[error(transparent)]
27    IOError(#[from] std::io::Error),
28
29    #[error("Precondition Failed")]
30    PreconditionFailed,
31
32    #[error("Forbidden")]
33    Forbidden,
34}
35
36impl Error {
37    pub fn status_code(&self) -> StatusCode {
38        match self {
39            Self::InternalError => StatusCode::INTERNAL_SERVER_ERROR,
40            Self::NotFound => StatusCode::NOT_FOUND,
41            Self::BadRequest(_) => StatusCode::BAD_REQUEST,
42            Self::Unauthorized => StatusCode::UNAUTHORIZED,
43            Self::XmlError(error) => match &error {
44                XmlError::InvalidTag(..)
45                | XmlError::MissingField(_)
46                | XmlError::UnsupportedEvent(_)
47                | XmlError::InvalidVariant(_)
48                | XmlError::InvalidFieldName(_, _)
49                | XmlError::InvalidValue(_) => StatusCode::UNPROCESSABLE_ENTITY,
50                _ => StatusCode::BAD_REQUEST,
51            },
52            Error::PropReadOnly => StatusCode::CONFLICT,
53            Error::PreconditionFailed => StatusCode::PRECONDITION_FAILED,
54            Self::IOError(_) => StatusCode::INTERNAL_SERVER_ERROR,
55            Self::Forbidden => StatusCode::FORBIDDEN,
56        }
57    }
58}
59
60impl axum::response::IntoResponse for Error {
61    fn into_response(self) -> axum::response::Response {
62        use axum::body::Body;
63
64        let mut resp = axum::response::Response::builder().status(self.status_code());
65        if matches!(&self, &Error::Unauthorized) {
66            resp.headers_mut()
67                .expect("This must always work")
68                .insert("WWW-Authenticate", "Basic".parse().unwrap());
69        }
70
71        resp.body(Body::new(self.to_string()))
72            .expect("This should always work")
73    }
74}