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}