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