implement webdav_proppatch webdav

Sun, 26 Jan 2020 10:13:11 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 26 Jan 2020 10:13:11 +0100
branch
webdav
changeset 242
c337a7ac82a8
parent 241
4adad7faf452
child 243
1a29b1d8d9d8

implement webdav_proppatch

src/server/test/main.c file | annotate | diff | comparison | revisions
src/server/test/webdav.c file | annotate | diff | comparison | revisions
src/server/test/webdav.h file | annotate | diff | comparison | revisions
src/server/webdav/multistatus.c file | annotate | diff | comparison | revisions
src/server/webdav/webdav.c file | annotate | diff | comparison | revisions
src/server/webdav/webdav.h file | annotate | diff | comparison | revisions
--- a/src/server/test/main.c	Sat Jan 25 21:37:38 2020 +0100
+++ b/src/server/test/main.c	Sun Jan 26 10:13:11 2020 +0100
@@ -99,6 +99,7 @@
        
     // webdav methods
     ucx_test_register(suite, test_webdav_propfind);
+    ucx_test_register(suite, test_webdav_proppatch);
        
     // run tests
     ucx_test_run(suite, stdout);
--- a/src/server/test/webdav.c	Sat Jan 25 21:37:38 2020 +0100
+++ b/src/server/test/webdav.c	Sun Jan 26 10:13:11 2020 +0100
@@ -1076,11 +1076,12 @@
     testutil_destroy_session(sn);
 }
 
-static void init_test_webdav_propfind(
+static void init_test_webdav_method(
         Session **out_sn,
         Request **out_rq,
         TestIOStream **out_st,
         pblock **out_pb,
+        const char *method,
         const char *request_body)
 {
     Session *sn;
@@ -1089,7 +1090,7 @@
     pblock *pb;
     
     sn = testutil_session();
-    rq = testutil_request(sn->pool, "PROPFIND", "/");
+    rq = testutil_request(sn->pool, method, "/");
     
     pblock_nvinsert("path", "/", rq->vars);
     pblock_nvinsert("uri", "/", rq->reqpb);
@@ -1117,7 +1118,7 @@
     
     int ret;
     // Test 1
-    init_test_webdav_propfind(&sn, &rq, &st, &pb, TEST_PROPFIND1);
+    init_test_webdav_method(&sn, &rq, &st, &pb, "PROPFIND", TEST_PROPFIND1);
     
     ret = webdav_propfind(pb, sn, rq);
     
@@ -1134,7 +1135,7 @@
     testutil_iostream_destroy(st);
     
     // Test2
-    init_test_webdav_propfind(&sn, &rq, &st, &pb, TEST_PROPFIND2);
+    init_test_webdav_method(&sn, &rq, &st, &pb, "PROPFIND", TEST_PROPFIND2);
     
     ret = webdav_propfind(pb, sn, rq);
     
@@ -1394,3 +1395,76 @@
     UCX_TEST_END;
     testutil_destroy_session(sn);
 }
+
+#define xstreq(a, b) (!strcmp((const char*)a, (const char*)b))
+
+UCX_TEST(test_webdav_proppatch) {
+    Session *sn;
+    Request *rq; 
+    TestIOStream *st;
+    pblock *pb;
+    
+    UCX_TEST_BEGIN;
+    
+    int ret;
+    // Test 1
+    init_test_webdav_method(&sn, &rq, &st, &pb, "PROPPATCH", TEST_PROPPATCH2);
+    rq->davCollection = &backend1;
+    ret = webdav_proppatch(pb, sn, rq);
+    
+    UCX_TEST_ASSERT(ret == REQ_PROCEED, "webdav_proppatch (1) failed");
+    
+    xmlDoc *doc = xmlReadMemory(
+            st->buf->space, st->buf->size, NULL, NULL, 0);
+    UCX_TEST_ASSERT(doc, "proppatch1: response is not valid xml");
+    
+    //printf("\n\n%.*s\n", (int)st->buf->size, st->buf->space);
+    
+    xmlNode *root = xmlDocGetRootElement(doc);
+    UCX_TEST_ASSERT(root, "proppatch1: no root");
+    
+    xmlNode *nodeC = NULL;
+    xmlNode *node = root->children;
+    int depth = 1;
+    while(node) {
+        const xmlChar *name = node->name;
+        int nextNode = 1;
+        if(node->type != XML_ELEMENT_NODE) {
+            // nothing
+        } else if(depth == 1) {
+            if(xstreq(name, "response")) {
+                nextNode = 0;
+            }
+        } else if(depth == 2) {
+            if(xstreq(name, "propstat")) {
+                nextNode = 0;
+            }
+        } else if(depth == 3) {
+            if(xstreq(name, "prop")) {
+                nextNode = 0;
+            }
+        } else if(depth == 4) {
+            if(xstreq(name, "c")) {
+                nodeC = node;
+                break;
+            }
+        }
+        
+        if(nextNode) {
+            node = node->next;
+        } else {
+            node = node->children;
+            depth++;
+        }
+    }
+    
+    UCX_TEST_ASSERT(nodeC, "prop c not in response");
+    UCX_TEST_ASSERT(!nodeC->children, "properties must not have a value");
+    
+    testutil_destroy_session(sn);
+    xmlFreeDoc(doc);
+    testutil_iostream_destroy(st);
+    
+    
+    UCX_TEST_END;
+}
--- a/src/server/test/webdav.h	Sat Jan 25 21:37:38 2020 +0100
+++ b/src/server/test/webdav.h	Sun Jan 26 10:13:11 2020 +0100
@@ -62,6 +62,8 @@
 UCX_TEST(test_proppatch_msresponse);
 UCX_TEST(test_webdav_op_proppatch);
 
+UCX_TEST(test_webdav_proppatch);
+
 /* --------------------------- PROPFIND --------------------------- */
 
 #define TEST_PROPFIND1 "<?xml version=\"1.0\" encoding=\"utf-8\" ?> \
--- a/src/server/webdav/multistatus.c	Sat Jan 25 21:37:38 2020 +0100
+++ b/src/server/webdav/multistatus.c	Sun Jan 26 10:13:11 2020 +0100
@@ -187,6 +187,8 @@
     writer_puts(out, sstr(rp->resource.href));
     writer_puts(out, S("</D:href>\n"));
     
+    WSBool writeContent = ms->proppatch ? FALSE : TRUE;
+    
     if(rp->plist_begin) {
         writer_puts(out, S("  <D:propstat>\n"
                            "   <D:prop>\n"));
@@ -194,10 +196,10 @@
         PropertyOkList *p = rp->plist_begin;
         while(p) {
             writer_puts(out, S("    "));
-            if(send_property(ms, p->property, p->nsdef, TRUE, out)) {
+            if(send_property(ms, p->property, p->nsdef, writeContent, out)) {
                 return out->error;
             }
-            writer_puts(out, S("\n    "));
+            writer_puts(out, S("\n"));
             p = p->next;
         }
         
--- a/src/server/webdav/webdav.c	Sat Jan 25 21:37:38 2020 +0100
+++ b/src/server/webdav/webdav.c	Sun Jan 26 10:13:11 2020 +0100
@@ -297,6 +297,9 @@
         ret = REQ_ABORTED;
     }
     
+    // cleanup
+    xmlFreeDoc(propfind->doc);
+    
     return ret;
 }
 
@@ -363,7 +366,81 @@
 
 
 int webdav_proppatch(pblock *pb, Session *sn, Request *rq) {
-    return REQ_ABORTED;
+    char *expect = pblock_findkeyval(pb_key_expect, rq->headers);
+    if(expect) {
+        if(!strcasecmp(expect, "100-continue")) {
+            if(http_send_continue(sn)) {
+                return REQ_ABORTED;
+            }
+        }
+    }
+    
+    UcxBuffer *reqbody = rqbody2buffer(sn, rq);
+    if(!reqbody) {
+        return REQ_ABORTED;
+    }
+    
+    int error = 0;
+    WebdavProppatchRequest *proppatch = proppatch_parse(
+            sn,
+            rq,
+            reqbody->space,
+            reqbody->size,
+            &error);
+    ucx_buffer_free(reqbody);
+    if(!proppatch) {
+        switch(error) {
+            // TODO: handle all errors
+            default: return REQ_ABORTED;
+        }
+    }
+    
+    WebdavBackend *dav =  rq->davCollection ?
+                              rq->davCollection : &default_backend;
+    
+    // requested uri and path
+    char *path = pblock_findkeyval(pb_key_path, rq->vars);
+    char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
+    
+    // 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;
+    }
+    ms->proppatch = TRUE;
+    
+    // WebdavResponse is the public interface used by Backends
+    // for adding resources to the response
+    WebdavResponse *response = (WebdavResponse*)ms;
+    
+    WebdavOperation *op = webdav_create_proppatch_operation(
+            sn,
+            rq,
+            dav,
+            proppatch,
+            response);
+    
+    int ret = REQ_PROCEED;
+    
+    // Execute proppatch
+    if(webdav_op_proppatch(op, uri, path)) {
+        ret = REQ_ABORTED;
+    }
+    
+    // send response
+    if(ret == REQ_PROCEED && multistatus_send(ms, sn->csd)) {
+        ret = REQ_ABORTED;
+        // TODO: log error
+    } else {
+        // TODO: error response
+    }
+    
+    // cleanup
+    xmlFreeDoc(proppatch->doc);
+    
+    return ret;
 }
 
 int webdav_mkcol(pblock *pb, Session *sn, Request *rq) {
--- a/src/server/webdav/webdav.h	Sat Jan 25 21:37:38 2020 +0100
+++ b/src/server/webdav/webdav.h	Sun Jan 26 10:13:11 2020 +0100
@@ -69,10 +69,6 @@
         UcxList **out_req);
 
 
-
-int webdav_propfind_finish(WebdavBackend *webdav, UcxList *requests);
-
-
 int webdav_proppatch(pblock *pb, Session *sn, Request *rq);
 int webdav_mkcol(pblock *pb, Session *sn, Request *rq);
 int webdav_post(pblock *pb, Session *sn, Request *rq);

mercurial