1use std::io::{Cursor, Write};
2use std::time::{SystemTime, UNIX_EPOCH};
3
4use bytes::Bytes;
5use headers::Header;
6use http::method::InvalidMethod;
7use time::format_description::well_known::Rfc3339;
8use time::macros::offset;
9
10use crate::DavResult;
11use crate::body::Body;
12use crate::errors::DavError;
13
14#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
16#[repr(u32)]
17pub enum DavMethod {
18 Head = 0x0001,
19 Get = 0x0002,
20 Put = 0x0004,
21 Patch = 0x0008,
22 Options = 0x0010,
23 PropFind = 0x0020,
24 PropPatch = 0x0040,
25 MkCol = 0x0080,
26 Copy = 0x0100,
27 Move = 0x0200,
28 Delete = 0x0400,
29 Lock = 0x0800,
30 Unlock = 0x1000,
31 Report = 0x2000,
32 MkCalendar = 0x4000,
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 _ => {
55 return Err(DavError::UnknownDavMethod);
56 }
57 },
58 };
59 Ok(m)
60}
61
62impl std::convert::TryFrom<&http::Method> for DavMethod {
64 type Error = InvalidMethod;
65
66 fn try_from(value: &http::Method) -> Result<Self, Self::Error> {
67 dav_method(value).map_err(|_| {
68 http::method::Method::from_bytes(b"").unwrap_err()
70 })
71 }
72}
73
74#[derive(Clone, Copy, Debug)]
78pub struct DavMethodSet(u32);
79
80impl DavMethodSet {
81 pub const HTTP_RO: DavMethodSet =
82 DavMethodSet(DavMethod::Get as u32 | DavMethod::Head as u32 | DavMethod::Options as u32);
83 pub const HTTP_RW: DavMethodSet = DavMethodSet(Self::HTTP_RO.0 | DavMethod::Put as u32);
84 pub const WEBDAV_RO: DavMethodSet = DavMethodSet(Self::HTTP_RO.0 | DavMethod::PropFind as u32);
85 pub const WEBDAV_RW: DavMethodSet = DavMethodSet(0xffffffff);
86
87 pub fn all() -> DavMethodSet {
89 DavMethodSet(0xffffffff)
90 }
91
92 pub fn none() -> DavMethodSet {
94 DavMethodSet(0)
95 }
96
97 pub fn add(&mut self, m: DavMethod) -> &Self {
99 self.0 |= m as u32;
100 self
101 }
102
103 pub fn remove(&mut self, m: DavMethod) -> &Self {
105 self.0 &= !(m as u32);
106 self
107 }
108
109 pub fn contains(&self, m: DavMethod) -> bool {
111 self.0 & (m as u32) > 0
112 }
113
114 pub fn from_vec(v: Vec<impl AsRef<str>>) -> Result<DavMethodSet, InvalidMethod> {
116 let mut m: u32 = 0;
117 for w in &v {
118 m |= match w.as_ref().to_lowercase().as_str() {
119 "head" => DavMethod::Head as u32,
120 "get" => DavMethod::Get as u32,
121 "put" => DavMethod::Put as u32,
122 "patch" => DavMethod::Patch as u32,
123 "delete" => DavMethod::Delete as u32,
124 "options" => DavMethod::Options as u32,
125 "propfind" => DavMethod::PropFind as u32,
126 "proppatch" => DavMethod::PropPatch as u32,
127 "mkcol" => DavMethod::MkCol as u32,
128 "copy" => DavMethod::Copy as u32,
129 "move" => DavMethod::Move as u32,
130 "lock" => DavMethod::Lock as u32,
131 "unlock" => DavMethod::Unlock as u32,
132 "report" => DavMethod::Report as u32,
133 "mkcalendar" => DavMethod::MkCalendar as u32,
134 "http-ro" => Self::HTTP_RO.0,
135 "http-rw" => Self::HTTP_RW.0,
136 "webdav-ro" => Self::WEBDAV_RO.0,
137 "webdav-rw" => Self::WEBDAV_RW.0,
138 _ => {
139 let invalid_method = http::method::Method::from_bytes(b"").unwrap_err();
141 return Err(invalid_method);
142 }
143 };
144 }
145 Ok(DavMethodSet(m))
146 }
147}
148
149pub(crate) fn dav_xml_error(body: &str) -> Body {
150 let xml = format!(
151 "{}\n{}\n{}\n{}\n",
152 r#"<?xml version="1.0" encoding="utf-8" ?>"#,
153 r#"<D:error xmlns:D="DAV:">"#,
154 body,
155 r#"</D:error>"#
156 );
157 Body::from(xml)
158}
159
160pub(crate) fn systemtime_to_offsetdatetime(t: SystemTime) -> time::OffsetDateTime {
161 match t.duration_since(UNIX_EPOCH) {
162 Ok(t) => {
163 let tm = time::OffsetDateTime::from_unix_timestamp(t.as_secs() as i64).unwrap();
164 tm.to_offset(offset!(UTC))
165 }
166 Err(_) => time::OffsetDateTime::UNIX_EPOCH.to_offset(offset!(UTC)),
167 }
168}
169
170pub(crate) fn systemtime_to_httpdate(t: SystemTime) -> String {
171 let d = headers::Date::from(t);
172 let mut v = Vec::new();
173 d.encode(&mut v);
174 v[0].to_str().unwrap().to_owned()
175}
176
177pub(crate) fn systemtime_to_rfc3339_without_nanosecond(t: SystemTime) -> String {
178 systemtime_to_offsetdatetime(t)
180 .replace_nanosecond(0)
181 .ok()
182 .and_then(|x| x.format(&Rfc3339).ok())
183 .unwrap_or("1970-01-01T00:00:00Z".into())
184}
185
186#[derive(Clone)]
188pub(crate) struct MemBuffer(Cursor<Vec<u8>>);
189
190impl MemBuffer {
191 pub fn new() -> MemBuffer {
192 MemBuffer(Cursor::new(Vec::new()))
193 }
194
195 pub fn take(&mut self) -> Bytes {
196 let buf = std::mem::take(self.0.get_mut());
197 self.0.set_position(0);
198 Bytes::from(buf)
199 }
200}
201
202impl Write for MemBuffer {
203 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
204 self.0.write(buf)
205 }
206
207 fn flush(&mut self) -> std::io::Result<()> {
208 Ok(())
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215 use std::time::UNIX_EPOCH;
216
217 #[test]
218 fn test_rfc3339_no_nanosecond() {
219 let t = UNIX_EPOCH + std::time::Duration::new(1, 5);
220 assert!(systemtime_to_rfc3339_without_nanosecond(t) == "1970-01-01T00:00:01Z");
221 }
222}