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