rustical_dav/header/
depth.rs

1use axum::{
2    body::Body,
3    extract::{FromRequestParts, OptionalFromRequestParts},
4    response::IntoResponse,
5};
6use rustical_xml::{ValueDeserialize, ValueSerialize, XmlError};
7use thiserror::Error;
8
9#[derive(Error, Debug)]
10#[error("Invalid Depth header")]
11pub struct InvalidDepthHeader;
12
13impl IntoResponse for InvalidDepthHeader {
14    fn into_response(self) -> axum::response::Response {
15        axum::response::Response::builder()
16            .status(axum::http::StatusCode::BAD_REQUEST)
17            .body(Body::empty())
18            .expect("this always works")
19    }
20}
21
22#[derive(Debug, Clone, PartialEq)]
23pub enum Depth {
24    Zero,
25    One,
26    Infinity,
27}
28
29impl ValueSerialize for Depth {
30    fn serialize(&self) -> String {
31        match self {
32            Depth::Zero => "0",
33            Depth::One => "1",
34            Depth::Infinity => "infinity",
35        }
36        .to_owned()
37    }
38}
39
40impl ValueDeserialize for Depth {
41    fn deserialize(val: &str) -> Result<Self, XmlError> {
42        match val {
43            "0" => Ok(Self::Zero),
44            "1" => Ok(Self::One),
45            "infinity" | "Infinity" => Ok(Self::Infinity),
46            _ => Err(XmlError::InvalidVariant(
47                "Invalid value for depth".to_owned(),
48            )),
49        }
50    }
51}
52
53impl TryFrom<&[u8]> for Depth {
54    type Error = InvalidDepthHeader;
55
56    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
57        match value {
58            b"0" => Ok(Depth::Zero),
59            b"1" => Ok(Depth::One),
60            b"Infinity" | b"infinity" => Ok(Depth::Infinity),
61            _ => Err(InvalidDepthHeader),
62        }
63    }
64}
65
66impl<S: Send + Sync> OptionalFromRequestParts<S> for Depth {
67    type Rejection = InvalidDepthHeader;
68
69    async fn from_request_parts(
70        parts: &mut axum::http::request::Parts,
71        _state: &S,
72    ) -> Result<Option<Self>, Self::Rejection> {
73        if let Some(depth_header) = parts.headers.get("Depth") {
74            Ok(Some(depth_header.as_bytes().try_into()?))
75        } else {
76            Ok(None)
77        }
78    }
79}
80
81impl<S: Send + Sync> FromRequestParts<S> for Depth {
82    type Rejection = InvalidDepthHeader;
83
84    async fn from_request_parts(
85        parts: &mut axum::http::request::Parts,
86        _state: &S,
87    ) -> Result<Self, Self::Rejection> {
88        if let Some(depth_header) = parts.headers.get("Depth") {
89            depth_header.as_bytes().try_into()
90        } else {
91            Ok(Self::Zero)
92        }
93    }
94}