Tue, 14 Jan 2020 22:05:34 +0100
add xml tree iterator
--- a/src/server/public/webdav.h Tue Jan 14 20:05:18 2020 +0100 +++ b/src/server/public/webdav.h Tue Jan 14 22:05:34 2020 +0100 @@ -75,6 +75,8 @@ #define WS_NODE_CDATA 4 #define WS_NODE_ENTITY_REF 5 +typedef int(*wsxml_func)(WSXmlNode *, void *); + /* propfind settings */ /* @@ -328,6 +330,13 @@ WebdavVFSProperties properties, struct stat *s); +int wsxml_iterator( + pool_handle_t *pool, + WSXmlNode *node, + wsxml_func begincb, + wsxml_func endcb, + void *udata); + #ifdef __cplusplus } #endif
--- a/src/server/test/webdav.c Tue Jan 14 20:05:18 2020 +0100 +++ b/src/server/test/webdav.c Tue Jan 14 22:05:34 2020 +0100 @@ -40,6 +40,8 @@ #include "vfs.h" #include "webdav.h" +static int webdav_is_initialized = 0; + /* ----------------------------- Test Backends --------------------------*/ static int backend2_init_called = 0; @@ -148,6 +150,13 @@ WebdavPropfindRequest **out_propfind, const char *xml) { + if(!webdav_is_initialized) { + if(webdav_init(NULL, NULL, NULL) != REQ_PROCEED) { + return 1; + } + webdav_is_initialized = 1; + } + Session *sn = testutil_session(); Request *rq = testutil_request(sn->pool, "PROPFIND", "/"); @@ -684,14 +693,17 @@ } UCX_TEST(test_msresponse_addproperty) { - Session *sn = testutil_session(); - Request *rq = testutil_request(sn->pool, "PROPFIND", "/"); - Multistatus *ms = multistatus_response(sn, rq); - MSResponse *r; + Session *sn; + Request *rq; UCX_TEST_BEGIN; - r = (MSResponse*)ms->response.addresource((WebdavResponse*)ms, "/"); + WebdavOperation *op = test_propfind_op(&sn, &rq, TEST_PROPFIND1); + UCX_TEST_ASSERT(op, "init failed"); + UCX_TEST_ASSERT(op->response, "no response"); + + Multistatus *ms = (Multistatus*)op->response; + MSResponse *r = (MSResponse*)ms->response.addresource((WebdavResponse*)ms, "/"); WebdavProperty p1; WebdavProperty p[16]; @@ -699,6 +711,7 @@ // init test data p1.namespace = webdav_dav_namespace(); + p1.nsdef = NULL; p1.lang = NULL; p1.name = "test1"; p1.value.data = NULL; @@ -706,6 +719,7 @@ for(int i=0;i<8;i++) { p[i].namespace = webdav_dav_namespace(); + p[i].nsdef = NULL; p[i].name = names[i]; p[i].lang = NULL; p[i].value.node = NULL;
--- a/src/server/webdav/multistatus.c Tue Jan 14 20:05:18 2020 +0100 +++ b/src/server/webdav/multistatus.c Tue Jan 14 22:05:34 2020 +0100 @@ -77,7 +77,7 @@ ZERO(res, sizeof(MSResponse)); // set href - res->resource.href = pool_strdup(response->op->sn->pool, path); + res->resource.href = pool_strdup(ms->sn->pool, path); // add resource funcs res->resource.addproperty = msresponse_addproperty;
--- a/src/server/webdav/xml.c Tue Jan 14 20:05:18 2020 +0100 +++ b/src/server/webdav/xml.c Tue Jan 14 22:05:34 2020 +0100 @@ -30,7 +30,116 @@ #include <stdlib.h> #include <string.h> + #include "xml.h" +typedef struct StackElm { + WSXmlNode *node; // list of nodes + WSXmlNode *parent; // if not NULL, call endcb after node->next is NULL + struct StackElm *next; +} StackElm; +#define STACK_PUSH(stack, elm) if(stack) { elm->next = stack; } stack = elm; +int wsxml_iterator( + pool_handle_t *pool, + WSXmlNode *node, + wsxml_func begincb, + wsxml_func endcb, + void *udata) +{ + if(!node) { + return 0; + } + + StackElm *stack = pool_malloc(pool, sizeof(StackElm)); + if(!stack) { + return 1; // OOM + } + stack->next = NULL; + stack->node = node; + stack->parent = NULL; + + int ret = 0; + int br = 0; + while(stack) { + StackElm *cur = stack; + WSXmlNode *xmlnode = cur->node; // get top stack element + stack = cur->next; // and remove it + cur->next = NULL; + + while(xmlnode) { + // element begin callback + if(begincb(xmlnode, udata)) { + br = 1; + break; // I don't like break with labels - is this wrong? + } + + if(xmlnode->children) { + // put the children on the stack + // the next stack iteration will process the children + StackElm *newelm = pool_malloc(pool, sizeof(StackElm)); + if(!newelm) { + ret = 1; + br = 1; + break; + } + newelm->next = NULL; + newelm->node = xmlnode->children; + // setting the parent will make sure endcb will be called + // for the current xmlnode after all children are processed + newelm->parent = xmlnode; + + // if xmlnode->next is not NULL, there are still nodes at + // this level, therefore we have to put these also on the + // stack + // this way, the remaining nodes are processed after all + // children of the current node are processed + if(xmlnode->next) { + // reuse current StackElm + cur->node = xmlnode->next; + STACK_PUSH(stack, cur); + cur = NULL; + } + + // now we can put the children on the stack + STACK_PUSH(stack, newelm); + // break, because we don't want to process xmlnode->next now + break; + } else { + // no children means, the end callback can be called directly + // after the begin callback (no intermediate nodes) + if(endcb(xmlnode, udata)) { + br = 1; + break; + } + } + + // continue with next node at this level + xmlnode = xmlnode->next; + } + if(br) { + break; // break because of an error + } + + if(cur) { + if(cur->parent) { + if(endcb(cur->parent, udata)) { + break; + } + } + pool_free(pool, cur); + } + } + + // free all remaining elements + StackElm *elm = stack; + while(elm) { + StackElm *next = elm->next; + pool_free(pool, elm); + elm = next; + } + + return ret; +} +