dav_server/
memls.rs

1//! Simple in-memory locksystem.
2//!
3//! This implementation has state - if you create a
4//! new instance in a handler(), it will be empty every time.
5//!
6//! This means you have to create the instance once, using `MemLs::new`, store
7//! it in your handler struct, and clone() it every time you pass
8//! it to the DavHandler. As a MemLs struct is just a handle, cloning is cheap.
9use std::collections::HashMap;
10use std::sync::{Arc, Mutex};
11use std::time::{Duration, SystemTime};
12
13use futures_util::{future, FutureExt};
14use uuid::Uuid;
15use xmltree::Element;
16
17use crate::davpath::DavPath;
18use crate::fs::FsResult;
19use crate::ls::*;
20use crate::tree;
21
22type Tree = tree::Tree<Vec<u8>, Vec<DavLock>>;
23
24/// Ephemeral in-memory LockSystem.
25#[derive(Debug, Clone)]
26pub struct MemLs(Arc<Mutex<MemLsInner>>);
27
28#[derive(Debug)]
29struct MemLsInner {
30    tree: Tree,
31    #[allow(dead_code)]
32    locks: HashMap<Vec<u8>, u64>,
33}
34
35impl MemLs {
36    /// Create a new "memls" locksystem.
37    pub fn new() -> Box<MemLs> {
38        let inner = MemLsInner {
39            tree: Tree::new(Vec::new()),
40            locks: HashMap::new(),
41        };
42        Box::new(MemLs(Arc::new(Mutex::new(inner))))
43    }
44}
45
46impl DavLockSystem for MemLs {
47    fn lock(
48        &self,
49        path: &DavPath,
50        principal: Option<&str>,
51        owner: Option<&Element>,
52        timeout: Option<Duration>,
53        shared: bool,
54        deep: bool,
55    ) -> LsFuture<Result<DavLock, DavLock>> {
56        let inner = &mut *self.0.lock().unwrap();
57
58        // any locks in the path?
59        let rc = check_locks_to_path(&inner.tree, path, None, true, &Vec::new(), shared);
60        trace!("lock: check_locks_to_path: {:?}", rc);
61        if let Err(err) = rc {
62            return future::ready(Err(err)).boxed();
63        }
64
65        // if it's a deep lock we need to check if there are locks furter along the path.
66        if deep {
67            let rc = check_locks_from_path(&inner.tree, path, None, true, &Vec::new(), shared);
68            trace!("lock: check_locks_from_path: {:?}", rc);
69            if let Err(err) = rc {
70                return future::ready(Err(err)).boxed();
71            }
72        }
73
74        // create lock.
75        let node = get_or_create_path_node(&mut inner.tree, path);
76        let timeout_at = timeout.map(|d| SystemTime::now() + d);
77        let lock = DavLock {
78            token: Uuid::new_v4().urn().to_string(),
79            path: path.clone(),
80            principal: principal.map(|s| s.to_string()),
81            owner: owner.cloned(),
82            timeout_at,
83            timeout,
84            shared,
85            deep,
86        };
87        trace!("lock {} created", &lock.token);
88        let slock = lock.clone();
89        node.push(slock);
90        future::ready(Ok(lock)).boxed()
91    }
92
93    fn unlock(&self, path: &DavPath, token: &str) -> LsFuture<Result<(), ()>> {
94        let inner = &mut *self.0.lock().unwrap();
95        let node_id = match lookup_lock(&inner.tree, path, token) {
96            None => {
97                trace!("unlock: {} not found at {}", token, path);
98                return future::ready(Err(())).boxed();
99            }
100            Some(n) => n,
101        };
102        let len = {
103            let node = inner.tree.get_node_mut(node_id).unwrap();
104            let idx = node.iter().position(|n| n.token.as_str() == token).unwrap();
105            node.remove(idx);
106            node.len()
107        };
108        if len == 0 {
109            inner.tree.delete_node(node_id).ok();
110        }
111        future::ready(Ok(())).boxed()
112    }
113
114    fn refresh(
115        &self,
116        path: &DavPath,
117        token: &str,
118        timeout: Option<Duration>,
119    ) -> LsFuture<Result<DavLock, ()>> {
120        trace!("refresh lock {}", token);
121        let inner = &mut *self.0.lock().unwrap();
122        let node_id = match lookup_lock(&inner.tree, path, token) {
123            None => {
124                trace!("lock not found");
125                return future::ready(Err(())).boxed();
126            }
127            Some(n) => n,
128        };
129        let node = inner.tree.get_node_mut(node_id).unwrap();
130        let idx = node.iter().position(|n| n.token.as_str() == token).unwrap();
131        let lock = &mut node[idx];
132        let timeout_at = timeout.map(|d| SystemTime::now() + d);
133        lock.timeout = timeout;
134        lock.timeout_at = timeout_at;
135        future::ready(Ok(lock.clone())).boxed()
136    }
137
138    fn check(
139        &self,
140        path: &DavPath,
141        principal: Option<&str>,
142        ignore_principal: bool,
143        deep: bool,
144        submitted_tokens: Vec<&str>,
145    ) -> LsFuture<Result<(), DavLock>> {
146        let inner = &*self.0.lock().unwrap();
147        let _st = submitted_tokens.clone();
148        let rc = check_locks_to_path(
149            &inner.tree,
150            path,
151            principal,
152            ignore_principal,
153            &submitted_tokens,
154            false,
155        );
156        trace!("check: check_lock_to_path: {:?}: {:?}", _st, rc);
157        if let Err(err) = rc {
158            return future::ready(Err(err)).boxed();
159        }
160
161        // if it's a deep lock we need to check if there are locks furter along the path.
162        if deep {
163            let rc = check_locks_from_path(
164                &inner.tree,
165                path,
166                principal,
167                ignore_principal,
168                &submitted_tokens,
169                false,
170            );
171            trace!("check: check_locks_from_path: {:?}", rc);
172            if let Err(err) = rc {
173                return future::ready(Err(err)).boxed();
174            }
175        }
176        future::ready(Ok(())).boxed()
177    }
178
179    fn discover(&self, path: &DavPath) -> LsFuture<Vec<DavLock>> {
180        let inner = &*self.0.lock().unwrap();
181        future::ready(list_locks(&inner.tree, path)).boxed()
182    }
183
184    fn delete(&self, path: &DavPath) -> LsFuture<Result<(), ()>> {
185        let inner = &mut *self.0.lock().unwrap();
186        if let Some(node_id) = lookup_node(&inner.tree, path) {
187            inner.tree.delete_subtree(node_id).ok();
188        }
189        future::ready(Ok(())).boxed()
190    }
191}
192
193// check if there are any locks along the path.
194fn check_locks_to_path(
195    tree: &Tree,
196    path: &DavPath,
197    principal: Option<&str>,
198    ignore_principal: bool,
199    submitted_tokens: &[&str],
200    shared_ok: bool,
201) -> Result<(), DavLock> {
202    // path segments
203    let segs = path_to_segs(path, true);
204    let last_seg = segs.len() - 1;
205
206    // state
207    let mut holds_lock = false;
208    let mut first_lock_seen: Option<&DavLock> = None;
209
210    // walk over path segments starting at root.
211    let mut node_id = tree::ROOT_ID;
212    for (i, seg) in segs.into_iter().enumerate() {
213        node_id = match get_child(tree, node_id, seg) {
214            Ok(n) => n,
215            Err(_) => break,
216        };
217        let node_locks = match tree.get_node(node_id) {
218            Ok(n) => n,
219            Err(_) => break,
220        };
221
222        for nl in node_locks {
223            if i < last_seg && !nl.deep {
224                continue;
225            }
226            if submitted_tokens.iter().any(|t| &nl.token == t)
227                && (ignore_principal || principal == nl.principal.as_deref())
228            {
229                // fine, we hold this lock.
230                holds_lock = true;
231            } else {
232                // exclusive locks are fatal.
233                if !nl.shared {
234                    return Err(nl.to_owned());
235                }
236                // remember first shared lock seen.
237                if !shared_ok {
238                    first_lock_seen.get_or_insert(nl);
239                }
240            }
241        }
242    }
243
244    // return conflicting lock on error.
245    if !holds_lock {
246        if let Some(first_lock_seen) = first_lock_seen {
247            return Err(first_lock_seen.to_owned());
248        }
249    }
250
251    Ok(())
252}
253
254// See if there are locks in any path below this collection.
255fn check_locks_from_path(
256    tree: &Tree,
257    path: &DavPath,
258    principal: Option<&str>,
259    ignore_principal: bool,
260    submitted_tokens: &[&str],
261    shared_ok: bool,
262) -> Result<(), DavLock> {
263    let node_id = match lookup_node(tree, path) {
264        Some(id) => id,
265        None => return Ok(()),
266    };
267    check_locks_from_node(
268        tree,
269        node_id,
270        principal,
271        ignore_principal,
272        submitted_tokens,
273        shared_ok,
274    )
275}
276
277// See if there are locks in any nodes below this node.
278fn check_locks_from_node(
279    tree: &Tree,
280    node_id: u64,
281    principal: Option<&str>,
282    ignore_principal: bool,
283    submitted_tokens: &[&str],
284    shared_ok: bool,
285) -> Result<(), DavLock> {
286    let node_locks = match tree.get_node(node_id) {
287        Ok(n) => n,
288        Err(_) => return Ok(()),
289    };
290    for nl in node_locks {
291        if (!nl.shared || !shared_ok)
292            && (!submitted_tokens.iter().any(|t| t == &nl.token)
293                || (!ignore_principal && principal != nl.principal.as_deref()))
294        {
295            return Err(nl.to_owned());
296        }
297    }
298    if let Ok(children) = tree.get_children(node_id) {
299        for (_, node_id) in children {
300            check_locks_from_node(
301                tree,
302                node_id,
303                principal,
304                ignore_principal,
305                submitted_tokens,
306                shared_ok,
307            )?;
308        }
309    }
310    Ok(())
311}
312
313// Find or create node.
314fn get_or_create_path_node<'a>(tree: &'a mut Tree, path: &DavPath) -> &'a mut Vec<DavLock> {
315    let mut node_id = tree::ROOT_ID;
316    for seg in path_to_segs(path, false) {
317        node_id = match tree.get_child(node_id, seg) {
318            Ok(n) => n,
319            Err(_) => tree
320                .add_child(node_id, seg.to_vec(), Vec::new(), false)
321                .unwrap(),
322        };
323    }
324    tree.get_node_mut(node_id).unwrap()
325}
326
327// Find lock in path.
328fn lookup_lock(tree: &Tree, path: &DavPath, token: &str) -> Option<u64> {
329    trace!("lookup_lock: {}", token);
330
331    let mut node_id = tree::ROOT_ID;
332    for seg in path_to_segs(path, true) {
333        trace!(
334            "lookup_lock: node {} seg {}",
335            node_id,
336            String::from_utf8_lossy(seg)
337        );
338        node_id = match get_child(tree, node_id, seg) {
339            Ok(n) => n,
340            Err(_) => break,
341        };
342        let node = tree.get_node(node_id).unwrap();
343        trace!("lookup_lock: locks here: {:?}", &node);
344        if node.iter().any(|n| n.token == token) {
345            return Some(node_id);
346        }
347    }
348    trace!("lookup_lock: fail");
349    None
350}
351
352// Find node ID for path.
353fn lookup_node(tree: &Tree, path: &DavPath) -> Option<u64> {
354    let mut node_id = tree::ROOT_ID;
355    for seg in path_to_segs(path, false) {
356        node_id = match tree.get_child(node_id, seg) {
357            Ok(n) => n,
358            Err(_) => return None,
359        };
360    }
361    Some(node_id)
362}
363
364// Find all locks in a path
365fn list_locks(tree: &Tree, path: &DavPath) -> Vec<DavLock> {
366    let mut locks = Vec::new();
367
368    let mut node_id = tree::ROOT_ID;
369    if let Ok(node) = tree.get_node(node_id) {
370        locks.extend_from_slice(node);
371    }
372    for seg in path_to_segs(path, false) {
373        node_id = match tree.get_child(node_id, seg) {
374            Ok(n) => n,
375            Err(_) => break,
376        };
377        if let Ok(node) = tree.get_node(node_id) {
378            locks.extend_from_slice(node);
379        }
380    }
381    locks
382}
383
384fn path_to_segs(path: &DavPath, include_root: bool) -> Vec<&[u8]> {
385    let path = path.as_bytes();
386    let mut segs: Vec<&[u8]> = path
387        .split(|&c| c == b'/')
388        .filter(|s| !s.is_empty())
389        .collect();
390    if include_root {
391        segs.insert(0, b"");
392    }
393    segs
394}
395
396fn get_child(tree: &Tree, node_id: u64, seg: &[u8]) -> FsResult<u64> {
397    if seg.is_empty() {
398        return Ok(node_id);
399    }
400    tree.get_child(node_id, seg)
401}