dav_server/
fakels.rs

1//! Fake locksystem (to make Windows/macOS work).
2//!
3//! Several Webdav clients, like the ones on Windows and macOS, require just
4//! basic functionality to mount the Webdav server in read-only mode. However
5//! to be able to mount the Webdav server in read-write mode, they require the
6//! Webdav server to have Webdav class 2 compliance - that means, LOCK/UNLOCK
7//! support.
8//!
9//! In many cases, this is not actually important. A lot of the current Webdav
10//! server implementations that are used to serve a filesystem just fake it:
11//! LOCK/UNLOCK always succeed, checking for locktokens in
12//! If: headers always succeeds, and nothing is every really locked.
13//!
14//! `FakeLs` implements such a fake locksystem.
15use std::time::{Duration, SystemTime};
16
17use futures_util::{future, FutureExt};
18use uuid::Uuid;
19use xmltree::Element;
20
21use crate::davpath::DavPath;
22use crate::ls::*;
23
24/// Fake locksystem implementation.
25#[derive(Debug, Clone)]
26pub struct FakeLs {}
27
28impl FakeLs {
29    /// Create a new "fakels" locksystem.
30    pub fn new() -> Box<FakeLs> {
31        Box::new(FakeLs {})
32    }
33}
34
35fn tm_limit(d: Option<Duration>) -> Duration {
36    match d {
37        None => Duration::new(120, 0),
38        Some(d) => {
39            if d.as_secs() > 120 {
40                Duration::new(120, 0)
41            } else {
42                d
43            }
44        }
45    }
46}
47
48impl DavLockSystem for FakeLs {
49    fn lock(
50        &self,
51        path: &DavPath,
52        principal: Option<&str>,
53        owner: Option<&Element>,
54        timeout: Option<Duration>,
55        shared: bool,
56        deep: bool,
57    ) -> LsFuture<Result<DavLock, DavLock>> {
58        let timeout = tm_limit(timeout);
59        let timeout_at = SystemTime::now() + timeout;
60
61        let d = if deep { 'I' } else { '0' };
62        let s = if shared { 'S' } else { 'E' };
63        let token = format!("opaquetoken:{}/{}/{}", Uuid::new_v4().hyphenated(), d, s);
64
65        let lock = DavLock {
66            token,
67            path: path.clone(),
68            principal: principal.map(|s| s.to_string()),
69            owner: owner.cloned(),
70            timeout_at: Some(timeout_at),
71            timeout: Some(timeout),
72            shared,
73            deep,
74        };
75        debug!("lock {} created", &lock.token);
76        future::ready(Ok(lock)).boxed()
77    }
78
79    fn unlock(&self, _path: &DavPath, _token: &str) -> LsFuture<Result<(), ()>> {
80        future::ready(Ok(())).boxed()
81    }
82
83    fn refresh(
84        &self,
85        path: &DavPath,
86        token: &str,
87        timeout: Option<Duration>,
88    ) -> LsFuture<Result<DavLock, ()>> {
89        debug!("refresh lock {}", token);
90        let v: Vec<&str> = token.split('/').collect();
91        let deep = v.len() > 1 && v[1] == "I";
92        let shared = v.len() > 2 && v[2] == "S";
93
94        let timeout = tm_limit(timeout);
95        let timeout_at = SystemTime::now() + timeout;
96
97        let lock = DavLock {
98            token: token.to_string(),
99            path: path.clone(),
100            principal: None,
101            owner: None,
102            timeout_at: Some(timeout_at),
103            timeout: Some(timeout),
104            shared,
105            deep,
106        };
107        future::ready(Ok(lock)).boxed()
108    }
109
110    fn check(
111        &self,
112        _path: &DavPath,
113        _principal: Option<&str>,
114        _ignore_principal: bool,
115        _deep: bool,
116        _submitted_tokens: Vec<&str>,
117    ) -> LsFuture<Result<(), DavLock>> {
118        future::ready(Ok(())).boxed()
119    }
120
121    fn discover(&self, _path: &DavPath) -> LsFuture<Vec<DavLock>> {
122        future::ready(Vec::new()).boxed()
123    }
124
125    fn delete(&self, _path: &DavPath) -> LsFuture<Result<(), ()>> {
126        future::ready(Ok(())).boxed()
127    }
128}