# HG changeset patch # User Olaf Wintermann # Date 1580029991 -3600 # Node ID c337a7ac82a831b8785bd7fc6270b8aa7a6f9555 # Parent 4adad7faf4521a380cae87961e4580f54a53d963 implement webdav_proppatch diff -r 4adad7faf452 -r c337a7ac82a8 src/server/test/main.c --- 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); diff -r 4adad7faf452 -r c337a7ac82a8 src/server/test/webdav.c --- 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; +} diff -r 4adad7faf452 -r c337a7ac82a8 src/server/test/webdav.h --- 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 " \ diff -r 4adad7faf452 -r c337a7ac82a8 src/server/webdav/multistatus.c --- 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("\n")); + WSBool writeContent = ms->proppatch ? FALSE : TRUE; + if(rp->plist_begin) { writer_puts(out, S(" \n" " \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; } diff -r 4adad7faf452 -r c337a7ac82a8 src/server/webdav/webdav.c --- 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) { diff -r 4adad7faf452 -r c337a7ac82a8 src/server/webdav/webdav.h --- 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);