--- 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(