webdav_handler/
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 uuid::Uuid;
18use xmltree::Element;
19
20use crate::davpath::DavPath;
21use crate::ls::*;
22
23/// Fake locksystem implementation.
24#[derive(Debug, Clone)]
25pub struct FakeLs {}
26
27impl FakeLs {
28    /// Create a new "fakels" locksystem.
29    pub fn new() -> Box<FakeLs> {
30        Box::new(FakeLs {})
31    }
32}
33
34fn tm_limit(d: Option<Duration>) -> Duration {
35    match d {
36        None => Duration::new(120, 0),
37        Some(d) => {
38            if d.as_secs() > 120 {
39                Duration::new(120, 0)
40            } else {
41                d
42            }
43        },
44    }
45}
46
47impl DavLockSystem for FakeLs {
48    fn lock(
49        &self,
50        path: &DavPath,
51        principal: Option<&str>,
52        owner: Option<&Element>,
53        timeout: Option<Duration>,
54        shared: bool,
55        deep: bool,
56    ) -> Result<DavLock, DavLock>
57    {
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().to_hyphenated(), d, s);
64
65        let lock = DavLock {
66            token:      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:     shared,
73            deep:       deep,
74        };
75        debug!("lock {} created", &lock.token);
76        Ok(lock)
77    }
78
79    fn unlock(&self, _path: &DavPath, _token: &str) -> Result<(), ()> {
80        Ok(())
81    }
82
83    fn refresh(&self, path: &DavPath, token: &str, timeout: Option<Duration>) -> Result<DavLock, ()> {
84        debug!("refresh lock {}", token);
85        let v: Vec<&str> = token.split('/').collect();
86        let deep = v.len() > 1 && v[1] == "I";
87        let shared = v.len() > 2 && v[2] == "S";
88
89        let timeout = tm_limit(timeout);
90        let timeout_at = SystemTime::now() + timeout;
91
92        let lock = DavLock {
93            token:      token.to_string(),
94            path:       path.clone(),
95            principal:  None,
96            owner:      None,
97            timeout_at: Some(timeout_at),
98            timeout:    Some(timeout),
99            shared:     shared,
100            deep:       deep,
101        };
102        Ok(lock)
103    }
104
105    fn check(
106        &self,
107        _path: &DavPath,
108        _principal: Option<&str>,
109        _ignore_principal: bool,
110        _deep: bool,
111        _submitted_tokens: Vec<&str>,
112    ) -> Result<(), DavLock>
113    {
114        Ok(())
115    }
116
117    fn discover(&self, _path: &DavPath) -> Vec<DavLock> {
118        Vec::new()
119    }
120
121    fn delete(&self, _path: &DavPath) -> Result<(), ()> {
122        Ok(())
123    }
124}