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