1use http::{HeaderMap, Method, Uri};
4
5use crate::DavPath;
6use crate::event::DavOperation;
7use crate::protocol::{
8 DavProtocolError, Depth, Destination, IfHeader, destination_relative_path, parse_copy_depth,
9 parse_delete_depth, parse_if_header, parse_lock_depth, parse_move_depth, parse_overwrite,
10 parse_propfind_depth, strip_mount_prefix,
11};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum DavMethod {
16 Options,
17 Propfind,
18 Proppatch,
19 Get,
20 Head,
21 Put,
22 Mkcol,
23 Delete,
24 Copy,
25 Move,
26 Lock,
27 Unlock,
28 Report,
29 VersionControl,
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum DavBodyPolicy {
35 Empty,
37 BoundedXml,
39 Stream,
41 Unused,
43}
44
45impl DavMethod {
46 #[must_use]
48 pub fn from_method(method: &Method) -> Option<Self> {
49 Self::from_name(method.as_str())
50 }
51
52 #[must_use]
54 pub fn from_name(method: &str) -> Option<Self> {
55 match method {
56 "OPTIONS" => Some(Self::Options),
57 "PROPFIND" => Some(Self::Propfind),
58 "PROPPATCH" => Some(Self::Proppatch),
59 "GET" => Some(Self::Get),
60 "HEAD" => Some(Self::Head),
61 "PUT" => Some(Self::Put),
62 "MKCOL" => Some(Self::Mkcol),
63 "DELETE" => Some(Self::Delete),
64 "COPY" => Some(Self::Copy),
65 "MOVE" => Some(Self::Move),
66 "LOCK" => Some(Self::Lock),
67 "UNLOCK" => Some(Self::Unlock),
68 "REPORT" => Some(Self::Report),
69 "VERSION-CONTROL" => Some(Self::VersionControl),
70 _ => None,
71 }
72 }
73
74 #[must_use]
76 pub const fn operation(self) -> DavOperation {
77 match self {
78 Self::Options => DavOperation::Options,
79 Self::Propfind => DavOperation::Propfind,
80 Self::Proppatch => DavOperation::Proppatch,
81 Self::Get => DavOperation::Get,
82 Self::Head => DavOperation::Head,
83 Self::Put => DavOperation::Put,
84 Self::Mkcol => DavOperation::Mkcol,
85 Self::Delete => DavOperation::Delete,
86 Self::Copy => DavOperation::Copy,
87 Self::Move => DavOperation::Move,
88 Self::Lock => DavOperation::Lock,
89 Self::Unlock => DavOperation::Unlock,
90 Self::Report => DavOperation::Report,
91 Self::VersionControl => DavOperation::VersionControl,
92 }
93 }
94
95 #[must_use]
97 pub const fn body_policy(self) -> DavBodyPolicy {
98 match self {
99 Self::Options | Self::Mkcol | Self::Delete | Self::Copy | Self::Move | Self::Unlock => {
100 DavBodyPolicy::Empty
101 }
102 Self::Propfind | Self::Proppatch | Self::Lock | Self::Report => {
103 DavBodyPolicy::BoundedXml
104 }
105 Self::Put => DavBodyPolicy::Stream,
106 Self::Get | Self::Head | Self::VersionControl => DavBodyPolicy::Unused,
107 }
108 }
109}
110
111#[derive(Debug, Clone, PartialEq, Eq)]
113pub struct DavRequestOrigin {
114 pub scheme: String,
115 pub host: String,
116}
117
118#[derive(Debug, Clone, PartialEq, Eq)]
120pub struct DavRequestHead {
121 pub method: DavMethod,
122 pub target: DavPath,
123 pub origin: DavRequestOrigin,
124 pub depth: Option<Depth>,
125 pub overwrite: Option<bool>,
126 pub destination: Option<Destination>,
127 pub if_header: Option<IfHeader>,
128}
129
130impl DavRequestHead {
131 pub fn parse(
133 method: DavMethod,
134 uri: &Uri,
135 headers: &HeaderMap,
136 mount_path: &str,
137 origin: &DavRequestOrigin,
138 ) -> Result<Self, DavProtocolError> {
139 let relative = strip_mount_prefix(uri.path(), mount_path).ok_or_else(|| {
140 DavProtocolError::bad_request("Request target must stay under WebDAV prefix")
141 })?;
142 let target = DavPath::new(relative)
143 .map_err(|_| DavProtocolError::bad_request("Invalid request path"))?;
144
145 let depth = match method {
146 DavMethod::Propfind => Some(parse_propfind_depth(headers)?),
147 DavMethod::Copy => Some(parse_copy_depth(headers)?),
148 DavMethod::Move => Some(parse_move_depth(headers)?),
149 DavMethod::Delete => Some(parse_delete_depth(headers)?),
150 DavMethod::Lock => Some(parse_lock_depth(headers)?),
151 _ => None,
152 };
153 let (overwrite, destination) = match method {
154 DavMethod::Copy | DavMethod::Move => (
155 Some(parse_overwrite(headers)?),
156 Some(destination_relative_path(
157 headers,
158 mount_path,
159 &origin.scheme,
160 &origin.host,
161 )?),
162 ),
163 _ => (None, None),
164 };
165
166 Ok(Self {
167 method,
168 target,
169 origin: origin.clone(),
170 depth,
171 overwrite,
172 destination,
173 if_header: parse_if_header(headers)?,
174 })
175 }
176}