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::{FutureExt, future};
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: Box::new(path.clone()),
80            principal: principal.map(|s| s.to_string()),
81            owner: owner.map(|o| Box::new(o.clone())),
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: {token} not found at {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 && let Some(first_lock_seen) = first_lock_seen {
246        return Err(first_lock_seen.to_owned());
247    }
248
249    Ok(())
250}
251
252// See if there are locks in any path below this collection.
253fn check_locks_from_path(
254    tree: &Tree,
255    path: &DavPath,
256    principal: Option<&str>,
257    ignore_principal: bool,
258    submitted_tokens: &[&str],
259    shared_ok: bool,
260) -> Result<(), DavLock> {
261    let node_id = match lookup_node(tree, path) {
262        Some(id) => id,
263        None => return Ok(()),
264    };
265    check_locks_from_node(
266        tree,
267        node_id,
268        principal,
269        ignore_principal,
270        submitted_tokens,
271        shared_ok,
272    )
273}
274
275// See if there are locks in any nodes below this node.
276fn check_locks_from_node(
277    tree: &Tree,
278    node_id: u64,
279    principal: Option<&str>,
280    ignore_principal: bool,
281    submitted_tokens: &[&str],
282    shared_ok: bool,
283) -> Result<(), DavLock> {
284    let node_locks = match tree.get_node(node_id) {
285        Ok(n) => n,
286        Err(_) => return Ok(()),
287    };
288    for nl in node_locks {
289        if (!nl.shared || !shared_ok)
290            && (!submitted_tokens.iter().any(|t| t == &nl.token)
291                || (!ignore_principal && principal != nl.principal.as_deref()))
292        {
293            return Err(nl.to_owned());
294        }
295    }
296    if let Ok(children) = tree.get_children(node_id) {
297        for (_, node_id) in children {
298            check_locks_from_node(
299                tree,
300                node_id,
301                principal,
302                ignore_principal,
303                submitted_tokens,
304                shared_ok,
305            )?;
306        }
307    }
308    Ok(())
309}
310
311// Find or create node.
312fn get_or_create_path_node<'a>(tree: &'a mut Tree, path: &DavPath) -> &'a mut Vec<DavLock> {
313    let mut node_id = tree::ROOT_ID;
314    for seg in path_to_segs(path, false) {
315        node_id = match tree.get_child(node_id, seg) {
316            Ok(n) => n,
317            Err(_) => tree
318                .add_child(node_id, seg.to_vec(), Vec::new(), false)
319                .unwrap(),
320        };
321    }
322    tree.get_node_mut(node_id).unwrap()
323}
324
325// Find lock in path.
326fn lookup_lock(tree: &Tree, path: &DavPath, token: &str) -> Option<u64> {
327    trace!("lookup_lock: {token}");
328
329    let mut node_id = tree::ROOT_ID;
330    for seg in path_to_segs(path, true) {
331        trace!(
332            "lookup_lock: node {} seg {}",
333            node_id,
334            String::from_utf8_lossy(seg)
335        );
336        node_id = match get_child(tree, node_id, seg) {
337            Ok(n) => n,
338            Err(_) => break,
339        };
340        let node = tree.get_node(node_id).unwrap();
341        trace!("lookup_lock: locks here: {:?}", &node);
342        if node.iter().any(|n| n.token == token) {
343            return Some(node_id);
344        }
345    }
346    trace!("lookup_lock: fail");
347    None
348}
349
350// Find node ID for path.
351fn lookup_node(tree: &Tree, path: &DavPath) -> Option<u64> {
352    let mut node_id = tree::ROOT_ID;
353    for seg in path_to_segs(path, false) {
354        node_id = match tree.get_child(node_id, seg) {
355            Ok(n) => n,
356            Err(_) => return None,
357        };
358    }
359    Some(node_id)
360}
361
362// Find all locks in a path
363fn list_locks(tree: &Tree, path: &DavPath) -> Vec<DavLock> {
364    let mut locks = Vec::new();
365
366    let mut node_id = tree::ROOT_ID;
367    if let Ok(node) = tree.get_node(node_id) {
368        locks.extend_from_slice(node);
369    }
370    for seg in path_to_segs(path, false) {
371        node_id = match tree.get_child(node_id, seg) {
372            Ok(n) => n,
373            Err(_) => break,
374        };
375        if let Ok(node) = tree.get_node(node_id) {
376            locks.extend_from_slice(node);
377        }
378    }
379    locks
380}
381
382fn path_to_segs(path: &DavPath, include_root: bool) -> Vec<&[u8]> {
383    let path = path.as_bytes();
384    let mut segs: Vec<&[u8]> = path
385        .split(|&c| c == b'/')
386        .filter(|s| !s.is_empty())
387        .collect();
388    if include_root {
389        segs.insert(0, b"");
390    }
391    segs
392}
393
394fn get_child(tree: &Tree, node_id: u64, seg: &[u8]) -> FsResult<u64> {
395    if seg.is_empty() {
396        return Ok(node_id);
397    }
398    tree.get_child(node_id, seg)
399}