add href parameter to webdav_op_propfind_children webdav

Tue, 31 Dec 2019 16:31:29 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Tue, 31 Dec 2019 16:31:29 +0100
branch
webdav
changeset 221
ff5826fc6a6c
parent 220
2915b6c11aec
child 222
5f05e56cb8e2

add href parameter to webdav_op_propfind_children

src/server/test/webdav.c file | annotate | diff | comparison | revisions
src/server/webdav/operation.c file | annotate | diff | comparison | revisions
src/server/webdav/operation.h file | annotate | diff | comparison | revisions
src/server/webdav/webdav.c file | annotate | diff | comparison | revisions
--- a/src/server/test/webdav.c	Tue Dec 31 14:53:13 2019 +0100
+++ b/src/server/test/webdav.c	Tue Dec 31 16:31:29 2019 +0100
@@ -828,7 +828,7 @@
     UCX_TEST_ASSERT(backend2_propfind_do_count == 1, "backend1 propfind_do not called")
    
     // propfind for all children
-    err = webdav_op_propfind_children(op, vfs, "/dir");
+    err = webdav_op_propfind_children(op, vfs, "/", "/dir");
     UCX_TEST_ASSERT(err == 0, "webdav_op_propfind_children failed");
     
     // 1 dir + 4 children
--- a/src/server/webdav/operation.c	Tue Dec 31 14:53:13 2019 +0100
+++ b/src/server/webdav/operation.c	Tue Dec 31 16:31:29 2019 +0100
@@ -56,12 +56,12 @@
 
 int webdav_op_propfind_begin(
         WebdavOperation *op,
-        const char *path,
+        const char *href,
         VFS_DIR parent,
         struct stat *s)
 {
     // create WebdavResource object for requested resource
-    WebdavResource *resource = op->response->addresource(op->response, path);
+    WebdavResource *resource = op->response->addresource(op->response, href);
     if(!resource) {
         return REQ_ABORTED;
     }
@@ -89,44 +89,104 @@
     return ret;
 }
 
+typedef struct PathSearchElm {
+    char   *href;
+    char   *path;
+    size_t hreflen;
+    size_t pathlen;
+} PathSearchElm;
+
+/*
+ * concats base + / + elm
+ * if baseinit is true, only elm is copied
+ */
+static int path_buf_concat(
+        pool_handle_t *pool,
+        char **buf,
+        size_t * restrict len,
+        WSBool * restrict baseinit,
+        const char *base,
+        size_t baselen,
+        const char *elm,
+        size_t elmlen)
+{
+    if(base[baselen-1] == '/') {
+        baselen--;
+    }
+    
+    size_t newlen = baselen + elmlen + 1;
+    if(newlen > WEBDAV_PATH_MAX) {
+        log_ereport(LOG_FAILURE, "webdav: maximal path length exceeded");
+        return 1;
+    }
+    
+    // check if new path + terminator fits in the buffer
+    if(newlen + 1 > *len) {
+        *len = newlen + 128;
+        char *newbuf = pool_realloc(pool, *buf, newlen);
+        if(newbuf) {
+            log_ereport(LOG_FAILURE, "webdav: path memory allocation failed");
+            return 1;
+        }
+        *baseinit = FALSE;
+        
+        *buf = newbuf;
+    }
+    
+    // if baseinit is true, the parent is already in the buffer
+    // and we don't need to memcpy it again
+    if(!(*baseinit)) {
+        memcpy(*buf, base, baselen);
+        (*buf)[baselen] = '/';
+        *baseinit = TRUE;
+    }
+    // copy child and terminate string
+    memcpy((*buf) + baselen + 1, elm, elmlen);
+    (*buf)[newlen] = '\0';
+    
+    return 0;
+}
+
 int webdav_op_propfind_children(
         WebdavOperation *op,
         VFSContext *vfs,
-        char *path)
+        const char *href,
+        const char *path)
 {
     WebdavPropfindRequest *request = op->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);
+    
+    PathSearchElm *start_elm = pool_malloc(pool, sizeof(PathSearchElm));
+    start_elm->href = pool_strdup(pool, href);
+    start_elm->path = pool_strdup(pool, path);
+    start_elm->hreflen = strlen(href);
+    start_elm->pathlen = strlen(path);
+    
+    UcxList *stack = ucx_list_prepend_a(a, NULL, start_elm);
     UcxList *stack_end = stack;
     if(!stack) {
         return 1;
     }
     
-    // reusable buffer for full child path
-    char *newpath = NULL;
-    size_t newpathlen = 0;
+    // reusable buffer for full child path and href
+    char *newpath = pool_malloc(pool, 256);
+    size_t newpathlen = 256;
+    
+    char *newhref = pool_malloc(pool, 256);
+    size_t newhreflen = 256;
     
     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;
+        PathSearchElm *cur_elm = stack->data;
         
         // when newpath is initialized with the parent path
         // set path_buf_init to TRUE
+        WSBool href_buf_init = FALSE;
         WSBool path_buf_init = FALSE;
         
-        VFS_DIR dir = vfs_opendir(vfs, path);
+        VFS_DIR dir = vfs_opendir(vfs, cur_elm->path);
         if(!dir) {
             log_ereport(
                     LOG_FAILURE,
@@ -143,32 +203,36 @@
             }
             
             size_t child_len = strlen(f.name);
-            if(child_len > max_child_len) {
-                log_ereport(LOG_FAILURE, "webdav: maximal path length exceeded");
+            
+            // create new path and href for the child
+            if(path_buf_concat(
+                    pool,
+                    &newhref,
+                    &newhreflen,
+                    &href_buf_init,
+                    cur_elm->href,
+                    cur_elm->hreflen,
+                    f.name,
+                    child_len))
+            {
                 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;
+            if(path_buf_concat(
+                    pool,
+                    &newpath,
+                    &newpathlen,
+                    &path_buf_init,
+                    cur_elm->path,
+                    cur_elm->pathlen,
+                    f.name,
+                    child_len))
+            {
+                err = 1;
+                break;
             }
-            // 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;
+            size_t childhreflen = cur_elm->hreflen + 1 + child_len;
+            size_t childpathlen = cur_elm->pathlen + 1 + child_len;
             
             // propfind for this child
             if(webdav_op_propfind_begin(op, newpath, dir, &f.stat)) {
@@ -178,13 +242,25 @@
             
             // depth of -1 means infinity
             if(request->depth == -1 && S_ISDIR(f.stat.st_mode)) {
+                char *hrefcp = pool_malloc(pool, childhreflen + 1);
+                memcpy(hrefcp, newhref, childhreflen + 1);
+                hrefcp[childhreflen] = '\0';
+                
                 char *pathcp = pool_malloc(pool, childpathlen + 1);
                 memcpy(pathcp, newpath, childpathlen + 1);
+                pathcp[childpathlen] = '\0';
                 
-                // add the newpath copy to the stack
+                PathSearchElm *new_elm = pool_malloc(pool,
+                                            sizeof(PathSearchElm));
+                new_elm->href = hrefcp;
+                new_elm->path = pathcp;
+                new_elm->hreflen = childhreflen;
+                new_elm->pathlen = childpathlen;
+                
+                // add the new_elm 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);
+                UcxList *newlistelm = ucx_list_append_a(a, stack_end, new_elm);
                 if(!newlistelm) {
                     err = 1;
                     break;
@@ -195,9 +271,10 @@
         
         vfs_closedir(dir);
         
-        if(cur_path != path) {
-            pool_free(pool, cur_path);
-        }
+        pool_free(pool, cur_elm->path);
+        pool_free(pool, cur_elm->href);
+        pool_free(pool, cur_elm);
+        
         stack = ucx_list_remove_a(a, stack, stack);
     }
     
--- a/src/server/webdav/operation.h	Tue Dec 31 14:53:13 2019 +0100
+++ b/src/server/webdav/operation.h	Tue Dec 31 16:31:29 2019 +0100
@@ -53,14 +53,15 @@
 
 int webdav_op_propfind_begin(
         WebdavOperation *op,
-        const char *path,
+        const char *href,
         VFS_DIR parent,
         struct stat *s);
 
 int webdav_op_propfind_children(
         WebdavOperation *op,
         VFSContext *vfs,
-        char *path);
+        const char *href,
+        const char *path);
 
 int webdav_op_propfiond_close_resource(
         WebdavOperation *op,
--- a/src/server/webdav/webdav.c	Tue Dec 31 14:53:13 2019 +0100
+++ b/src/server/webdav/webdav.c	Tue Dec 31 16:31:29 2019 +0100
@@ -187,8 +187,9 @@
                               rq->davCollection : &default_backend;
     
     
-    // requested uri path
+    // requested uri and path
     char *path = pblock_findkeyval(pb_key_path, rq->vars);
+    char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
     
     // VFS settings are only taken from the first backend
     uint32_t settings = dav->settings;
@@ -254,7 +255,7 @@
         //   depth is not 0
         // in this case we need to execute propfind_do for all children
         if(usevfs) {
-            if(!webdav_op_propfind_children(op, vfs, path)) {
+            if(!webdav_op_propfind_children(op, vfs, uri, path)) {
                 ret = REQ_ABORTED;
             }
         }

mercurial