rustical_dav/header/
depth.rs1use 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}