1use std::io::{Cursor, Write};
2use std::time::SystemTime;
3
4use bytes::Bytes;
5use chrono::{DateTime, SecondsFormat, Utc};
6use headers::Header;
7use http::method::InvalidMethod;
8
9use crate::DavResult;
10use crate::body::Body;
11use crate::errors::DavError;
12
13#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
15#[repr(u32)]
16pub enum DavMethod {
17 Head = 0x0001,
18 Get = 0x0002,
19 Put = 0x0004,
20 Patch = 0x0008,
21 Options = 0x0010,
22 PropFind = 0x0020,
23 PropPatch = 0x0040,
24 MkCol = 0x0080,
25 Copy = 0x0100,
26 Move = 0x0200,
27 Delete = 0x0400,
28 Lock = 0x0800,
29 Unlock = 0x1000,
30 Report = 0x2000,
31 MkCalendar = 0x4000,
32 MkAddressbook = 0x8000,
33}
34
35pub(crate) fn dav_method(m: &http::Method) -> DavResult<DavMethod> {
37 let m = match *m {
38 http::Method::HEAD => DavMethod::Head,
39 http::Method::GET => DavMethod::Get,
40 http::Method::PUT => DavMethod::Put,
41 http::Method::PATCH => DavMethod::Patch,
42 http::Method::DELETE => DavMethod::Delete,
43 http::Method::OPTIONS => DavMethod::Options,
44 _ => match m.as_str() {
45 "PROPFIND" => DavMethod::PropFind,
46 "PROPPATCH" => DavMethod::PropPatch,
47 "MKCOL" => DavMethod::MkCol,
48 "COPY" => DavMethod::Copy,
49 "MOVE" => DavMethod::Move,
50 "LOCK" => DavMethod::Lock,
51 "UNLOCK" => DavMethod::Unlock,
52 "REPORT" => DavMethod::Report,
53 "MKCALENDAR" => DavMethod::MkCalendar,
54 "MKADDRESSBOOK" => DavMethod::MkAddressbook,
55 _ => {
56 return Err(DavError::UnknownDavMethod);
57 }
58 },
59 };
60 Ok(m)
61}
62
63impl std::convert::TryFrom<&http::Method> for DavMethod {
65 type Error = InvalidMethod;
66
67 fn try_from(value: &http::Method) -> Result<Self, Self::Error> {
68 dav_method(value).map_err(|_| {
69 http::method::Method::from_bytes(b"").unwrap_err()
71 })
72 }
73}
74
75#[derive(Clone, Copy, Debug)]
79pub struct DavMethodSet(u32);
80
81impl DavMethodSet {
82 pub const HTTP_RO: DavMethodSet =
83 DavMethodSet(DavMethod::Get as u32 | DavMethod::Head as u32 | DavMethod::Options as u32);
84 pub const HTTP_RW: DavMethodSet = DavMethodSet(Self::HTTP_RO.0 | DavMethod::Put as u32);
85 pub const WEBDAV_RO: DavMethodSet = DavMethodSet(Self::HTTP_RO.0 | DavMethod::PropFind as u32);
86 pub const WEBDAV_RW: DavMethodSet = DavMethodSet(0xffffffff);
87
88 pub fn all() -> DavMethodSet {
90 DavMethodSet(0xffffffff)
91 }
92
93 pub fn none() -> DavMethodSet {
95 DavMethodSet(0)
96 }
97
98 pub fn add(&mut self, m: DavMethod) -> &Self {
100 self.0 |= m as u32;
101 self
102 }
103
104 pub fn remove(&mut self, m: DavMethod) -> &Self {
106 self.0 &= !(m as u32);
107 self
108 }
109
110 pub fn contains(&self, m: DavMethod) -> bool {
112 self.0 & (m as u32) > 0
113 }
114
115 pub fn from_vec(v: Vec<impl AsRef<str>>) -> Result<DavMethodSet, InvalidMethod> {
117 let mut m: u32 = 0;
118 for w in &v {
119 m |= match w.as_ref().to_lowercase().as_str() {
120 "head" => DavMethod::Head as u32,
121 "get" => DavMethod::Get as u32,
122 "put" => DavMethod::Put as u32,
123 "patch" => DavMethod::Patch as u32,
124 "delete" => DavMethod::Delete as u32,
125 "options" => DavMethod::Options as u32,
126 "propfind" => DavMethod::PropFind as u32,
127 "proppatch" => DavMethod::PropPatch as u32,
128 "mkcol" => DavMethod::MkCol as u32,
129 "copy" => DavMethod::Copy as u32,
130 "move" => DavMethod::Move as u32,
131 "lock" => DavMethod::Lock as u32,
132 "unlock" => DavMethod::Unlock as u32,
133 "report" => DavMethod::Report as u32,
134 "mkcalendar" => DavMethod::MkCalendar as u32,
135 "mkaddressbook" => DavMethod::MkAddressbook as u32,
136 "http-ro" => Self::HTTP_RO.0,
137 "http-rw" => Self::HTTP_RW.0,
138 "webdav-ro" => Self::WEBDAV_RO.0,
139 "webdav-rw" => Self::WEBDAV_RW.0,
140 _ => {
141 let invalid_method = http::method::Method::from_bytes(b"").unwrap_err();
143 return Err(invalid_method);
144 }
145 };
146 }
147 Ok(DavMethodSet(m))
148 }
149}
150
151pub(crate) fn dav_xml_error(body: &str) -> Body {
152 let xml = format!(
153 "{}\n{}\n{}\n{}\n",
154 r#"<?xml version="1.0" encoding="utf-8" ?>"#,
155 r#"<D:error xmlns:D="DAV:">"#,
156 body,
157 r#"</D:error>"#
158 );
159 Body::from(xml)
160}
161
162pub(crate) fn systemtime_to_httpdate(t: SystemTime) -> String {
163 let d = headers::Date::from(t);
164 let mut v = Vec::new();
165 d.encode(&mut v);
166 v[0].to_str().unwrap().to_owned()
167}
168
169pub(crate) fn systemtime_to_rfc3339_without_nanosecond(t: SystemTime) -> String {
170 DateTime::<Utc>::from(t).to_rfc3339_opts(SecondsFormat::Secs, true)
172}
173
174#[derive(Clone)]
176pub(crate) struct MemBuffer(Cursor<Vec<u8>>);
177
178impl MemBuffer {
179 pub fn new() -> MemBuffer {
180 MemBuffer(Cursor::new(Vec::new()))
181 }
182
183 pub fn take(&mut self) -> Bytes {
184 let buf = std::mem::take(self.0.get_mut());
185 self.0.set_position(0);
186 Bytes::from(buf)
187 }
188}
189
190impl Write for MemBuffer {
191 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
192 self.0.write(buf)
193 }
194
195 fn flush(&mut self) -> std::io::Result<()> {
196 Ok(())
197 }
198}
199
200#[cfg(test)]
201mod tests {
202 use super::*;
203 use std::time::UNIX_EPOCH;
204
205 #[test]
206 fn test_rfc3339_no_nanosecond() {
207 let t = UNIX_EPOCH + std::time::Duration::new(1, 5);
208 assert!(systemtime_to_rfc3339_without_nanosecond(t) == "1970-01-01T00:00:01Z");
209 }
210}