src/server/webdav/webdav.c

branch
webdav
changeset 217
8ed14d76db42
parent 216
ce2866ec97f6
child 220
2915b6c11aec
--- a/src/server/webdav/webdav.c	Mon Dec 30 16:33:20 2019 +0100
+++ b/src/server/webdav/webdav.c	Tue Dec 31 10:01:32 2019 +0100
@@ -39,6 +39,7 @@
 #include "versioning.h"
 #include "multistatus.h"
 #include "requestparser.h"
+#include "operation.h"
 
 #include "../util/pblock.h"
 #include "../util/util.h"
@@ -182,19 +183,9 @@
         }
     }
     
-    // The multistatus response object contains responses for all
-    // requested resources. At the end the Multistatus object will be
-    // serialized to xml
-    Multistatus *ms = multistatus_response(sn, rq);
-    if(!ms) {
-        return REQ_ABORTED;
-    }
-    // WebdavResponse is the public interface used by Backends
-    // for adding resources to the response
-    WebdavResponse *response = (WebdavResponse*)ms;
+    WebdavBackend *dav =  rq->davCollection ?
+                              rq->davCollection : &default_backend;
     
-    WebdavBackend *dav = 
-            rq->davCollection ? rq->davCollection : &default_backend;
     
     // requested uri path
     char *path = pblock_findkeyval(pb_key_path, rq->vars);
@@ -210,6 +201,23 @@
         return REQ_ABORTED;
     }
     
+    // The multistatus response object contains responses for all
+    // requested resources. At the end the Multistatus object will be
+    // serialized to xml
+    Multistatus *ms = multistatus_response(sn, rq);
+    if(!ms) {
+        return REQ_ABORTED;
+    }
+    // WebdavResponse is the public interface used by Backends
+    // for adding resources to the response
+    WebdavResponse *response = (WebdavResponse*)ms;
+    
+    WebdavOperation *op = webdav_operation_create(
+            sn->pool,
+            dav,
+            requestObjects,
+            response);
+    
     // some Backends can list all children by themselves, but some
     // require the VFS for this
     WSBool usevfs = (settings & WS_PROPFIND_NO_VFS) != WS_PROPFIND_NO_VFS;
@@ -234,8 +242,10 @@
         usevfs = FALSE;
     }
     
-    int ret = REQ_ABORTED;
-    if(!webdav_propfind_do(dav, requestObjects, response, NULL, path, statptr)) {
+    int ret = REQ_PROCEED;
+    
+    // create WebdavResource object for requested resource
+    if(!webdav_op_propfind_begin(op, path, NULL, statptr)) {
         // propfind for the requested resource was successful
         
         // usevfsdir is TRUE if
@@ -243,15 +253,17 @@
         //   the file is a directory
         //   depth is not 0
         // in this case we need to execute propfind_do for all children
-        if(usevfs && !propfind_children(dav, requestObjects, response, vfs, path)) {
-            ret = REQ_PROCEED;
+        if(usevfs) {
+            if(!webdav_op_propfind_children(op, vfs, path)) {
+                ret = REQ_ABORTED;
+            }
         }
     }
     
     // finish the propfind request
     // this function should cleanup all resources, therefore we execute it
     // even if a previous function failed
-    if(dav->propfind_finish(propfind)) {
+    if(webdav_op_propfind_finish(op)) {
         ret = REQ_ABORTED;
     }
     
@@ -320,176 +332,6 @@
 }
 
 
-/*
- * Executes propfind_do for each Backend
- * The list requests must contain all WebdavPropfindRequest objects
- * of all backends
- */
-int webdav_propfind_do(
-        WebdavBackend *dav,
-        UcxList *requests,
-        WebdavResponse *response,
-        VFS_DIR parent,
-        const char *path,
-        struct stat *s)
-{
-    while(dav && requests) {
-        if(dav->propfind_do(requests->data, response, parent, path, s)) {
-            return REQ_ABORTED;
-        }
-        
-        dav = dav->next;
-        requests = requests->next;
-    }
-    return REQ_PROCEED;
-}
-
-/*
- * Executes propfind_finish for each Backend
- */
-int webdav_propfind_finish(WebdavBackend *dav, UcxList *requests) {
-    int ret = REQ_PROCEED;
-    while(dav && requests) {
-        if(dav->propfind_finish(requests->data)) {
-            ret = REQ_ABORTED;
-        }
-        
-        dav = dav->next;
-        requests = requests->next;
-    }
-    return ret;
-}
-
-
-/*
- * Uses the VFS to iterate over all children of the requsted resource
- * and executes propfind for each child
- */
-int propfind_children(
-        WebdavBackend *dav,
-        UcxList *requests,
-        WebdavResponse *response,
-        VFSContext *vfs,
-        char *path)
-{
-    WebdavPropfindRequest *request = requests->data;
-    
-    UcxAllocator *a = session_get_allocator(request->sn);
-    pool_handle_t *pool = request->sn->pool;
-    UcxList *stack = ucx_list_prepend_a(a, NULL, path);
-    UcxList *stack_end = stack;
-    if(!stack) {
-        return 1;
-    }
-    
-    // reusable buffer for full child path
-    char *newpath = NULL;
-    size_t newpathlen = 0;
-    
-    int err = 0;
-    while(stack && !err) {
-        char *cur_path = stack->data;
-        size_t parent_len = strlen(cur_path);
-        if(parent_len > WEBDAV_PATH_MAX) {
-            log_ereport(LOG_FAILURE, "webdav: maximal path length exceeded");
-            err = 1;
-            break;
-        }
-        if(cur_path[parent_len-1] == '/') {
-            parent_len--;
-        }
-        size_t max_child_len = WEBDAV_PATH_MAX - parent_len;
-        
-        // when newpath is initialized with the parent path
-        // set path_buf_init to TRUE
-        WSBool path_buf_init = FALSE;
-        
-        VFS_DIR dir = vfs_opendir(vfs, path);
-        if(!dir) {
-            log_ereport(
-                    LOG_FAILURE,
-                    "webdav: propfind: cannot open directory %d",
-                    vfs->vfs_errno);
-            err = 1;
-            break;
-        }
-        
-        VFS_ENTRY f;
-        while(vfs_readdir_stat(dir, &f)) {
-            if(f.stat_errno != 0) {
-                continue;
-            }
-            
-            size_t child_len = strlen(f.name);
-            if(child_len > max_child_len) {
-                log_ereport(LOG_FAILURE, "webdav: maximal path length exceeded");
-                err = 1;
-                break;
-            }
-            size_t childpathlen = parent_len + child_len + 1; // +1 '/'
-            if(childpathlen > newpathlen) {
-                // we're gonna need a bigger boa^H^H^Hbuffer
-                if(newpath) {
-                    pool_free(pool, newpath);
-                }
-                newpath = pool_malloc(pool, childpathlen + 1);
-                if(!newpath) {
-                    err = 1;
-                    break;
-                }
-                newpathlen = childpathlen;
-                path_buf_init = FALSE;
-            }
-            // create full path string for this child
-            if(!path_buf_init) {
-                memcpy(newpath, cur_path, parent_len);
-                newpath[parent_len] = '/';
-            }
-            memcpy(newpath+parent_len+1, f.name, child_len);
-            newpath[childpathlen] = 0;
-            
-            // propfind for this child
-            if(webdav_propfind_do(dav, requests, response, dir, newpath, &f.stat)) {
-                err = 1;
-                break;
-            }
-            
-            // depth of -1 means infinity
-            if(request->depth == -1 && S_ISDIR(f.stat.st_mode)) {
-                char *pathcp = pool_malloc(pool, childpathlen + 1);
-                memcpy(pathcp, newpath, childpathlen + 1);
-                
-                // add the newpath copy to the stack
-                // stack_end is always not NULL here, because we remove
-                // the first stack element at the end of the loop
-                UcxList *newlistelm = ucx_list_append_a(a, stack_end, pathcp);
-                if(!newlistelm) {
-                    err = 1;
-                    break;
-                }
-                stack_end = newlistelm;
-            }
-        }
-        
-        vfs_closedir(dir);
-        
-        if(cur_path != path) {
-            pool_free(pool, cur_path);
-        }
-        stack = ucx_list_remove_a(a, stack, stack);
-    }
-    
-    // in case of an error, we have to free all remaining stack elements
-    UCX_FOREACH(elm, stack) {
-        char *data = elm->data;
-        if(data != path) {
-            pool_free(pool, data);
-        }
-    }
-    
-    return err;
-}
-
 int webdav_proppatch(pblock *pb, Session *sn, Request *rq) {
     return REQ_ABORTED;
 }
@@ -559,18 +401,12 @@
         WebdavPropfindRequest *request,
         WebdavResponse *response,
         VFS_DIR parent,
-        const char *path,
+        WebdavResource *resource,
         struct stat *s)
 {
     DefaultWebdavData *data = request->userdata;
     
-    // add a resource to the response
-    // usually this will lead to a <response> ... </response> tag in the
-    // multistatus response
-    WebdavResource *resource = response->addresource(response, path);
-    if(!resource) {
-        return 1;
-    }
+    // TODO: rework
     
     // add all requested vfs properties like getcontentlength ...
     if(webdav_add_vfs_properties(

mercurial