Sun, 19 Jan 2020 09:01:39 +0100
add handler for http expect header
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2019 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "testutils.h" #include "../webdav/requestparser.h" #include "../webdav/webdav.h" #include "../webdav/multistatus.h" #include "../webdav/operation.h" #include "vfs.h" #include "webdav.h" static int webdav_is_initialized = 0; /* ----------------------------- Test Backends --------------------------*/ static int backend2_init_called = 0; static int backend2_propfind_do_count = 0; static int backend2_propfind_finish_called = 0; // backend2 static int backend2_propfind_init( WebdavPropfindRequest *propfind, const char *path, WebdavPList **outPList) { backend2_init_called = 1; return 0; } static int backend2_propfind_do( WebdavPropfindRequest *propfind, WebdavResponse *response, VFS_DIR parent, WebdavResource *resource, struct stat *s) { backend2_propfind_do_count++; return 0; } static int backend2_propfind_finish(WebdavPropfindRequest *propfind) { backend2_propfind_finish_called = 1; return 0; } static WebdavBackend backend2 = { backend2_propfind_init, backend2_propfind_do, backend2_propfind_finish, 0, NULL }; // backend1 static int backend1_init_called = 0; static int backend1_propfind_do_count = 0; static int backend1_propfind_finish_called = 0; static int backend1_propfind_init( WebdavPropfindRequest *propfind, const char *path, WebdavPList **outPList) { backend1_init_called = 1; WebdavPList *plist = *outPList; WebdavProperty *p = plist->property; if(!strcmp(p->name, "displayname")) { plist->next->prev = NULL; *outPList = plist->next; // remove first item from plist } else { return 1; } return 0; } static int backend1_propfind_do( WebdavPropfindRequest *propfind, WebdavResponse *response, VFS_DIR parent, WebdavResource *resource, struct stat *s) { backend1_propfind_do_count++; return 0; } static int backend1_propfind_finish(WebdavPropfindRequest *propfind) { backend1_propfind_finish_called = 1; return 0; } WebdavBackend backend1 = { backend1_propfind_init, backend1_propfind_do, backend1_propfind_finish, 0, &backend2 }; static void reset_backends(void) { backend1_init_called = 0; backend1_propfind_do_count = 0; backend1_propfind_finish_called = 0; backend2_init_called = 0; backend2_propfind_do_count = 0; backend2_propfind_finish_called = 0; } /* ----------------------------------------------------------------------*/ static int test_init( Session **out_sn, Request **out_rq, 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", "/"); int error = 0; WebdavPropfindRequest *propfind = propfind_parse( sn, rq, xml, strlen(xml), &error); if(error) { return 1; } if(!propfind || !propfind->properties) { return 1; } *out_sn = sn; *out_rq = rq; *out_propfind = propfind; return 0; } static WebdavOperation* test_propfind_op( Session **out_sn, Request **out_rq, const char *xml) { WebdavPropfindRequest *propfind; if(test_init(out_sn, out_rq, &propfind, xml)) { return NULL; } Multistatus *ms = multistatus_response(*out_sn, *out_rq); if(!ms) { return NULL; } // WebdavResponse is the public interface used by Backends // for adding resources to the response WebdavResponse *response = (WebdavResponse*)ms; UcxList *requests = NULL; // Initialize all Webdav Backends if(webdav_propfind_init(&backend1, propfind, "/", &requests)) { return NULL; } return webdav_operation_create( (*out_sn), (*out_rq), &backend1, requests, response); } UCX_TEST(test_webdav_plist_add) { Session *sn = testutil_session(); UCX_TEST_BEGIN; WebdavPList *begin = NULL; WebdavPList *end = NULL; WebdavProperty p1, p2, p3; ZERO(&p1, sizeof(WebdavProperty)); ZERO(&p2, sizeof(WebdavProperty)); ZERO(&p3, sizeof(WebdavProperty)); int r; r = webdav_plist_add(sn->pool, &begin, &end, &p1); UCX_TEST_ASSERT(r == 0, "add 1 failed"); UCX_TEST_ASSERT(begin && end, "ptrs are NULL"); UCX_TEST_ASSERT(begin == end, "begin != end"); UCX_TEST_ASSERT(begin->prev == NULL, "begin->prev not NULL"); UCX_TEST_ASSERT(begin->next == NULL, "begin->next not NULL"); r = webdav_plist_add(sn->pool, &begin, &end, &p2); UCX_TEST_ASSERT(r == 0, "add 2 failed"); UCX_TEST_ASSERT(begin && end, "add2: ptrs are NULL"); UCX_TEST_ASSERT(begin->next, "begin->next is NULL"); UCX_TEST_ASSERT(begin->next == end, "begin->next != end"); UCX_TEST_ASSERT(end->prev = begin, "end->prev != begin"); UCX_TEST_ASSERT(begin->prev == NULL, "add2: begin->prev not NULL"); UCX_TEST_ASSERT(end->next == NULL, "add2: end->next not NULL"); r = webdav_plist_add(sn->pool, &begin, &end, &p3); UCX_TEST_ASSERT(r == 0, "add 3 failed"); UCX_TEST_ASSERT(begin && end, "add3: ptrs are NULL"); UCX_TEST_ASSERT(begin->next == end->prev, "begin->next != end->prev"); UCX_TEST_END; testutil_destroy_session(sn); } UCX_TEST(test_webdav_plist_size) { Session *sn = testutil_session(); UCX_TEST_BEGIN; WebdavPList *begin = NULL; WebdavPList *end = NULL; WebdavProperty p1, p2, p3; ZERO(&p1, sizeof(WebdavProperty)); ZERO(&p2, sizeof(WebdavProperty)); ZERO(&p3, sizeof(WebdavProperty)); int r; UCX_TEST_ASSERT(webdav_plist_size(begin) == 0, "size != 0"); r = webdav_plist_add(sn->pool, &begin, &end, &p1); UCX_TEST_ASSERT(webdav_plist_size(begin) == 1, "size != 1"); r = webdav_plist_add(sn->pool, &begin, &end, &p2); UCX_TEST_ASSERT(webdav_plist_size(begin) == 2, "size != 2"); r = webdav_plist_add(sn->pool, &begin, &end, &p3); UCX_TEST_ASSERT(webdav_plist_size(begin) == 3, "size != 3"); UCX_TEST_END; testutil_destroy_session(sn); } UCX_TEST(test_propfind_parse) { Session *sn = testutil_session(); Request *rq = testutil_request(sn->pool, "PROPFIND", "/"); UCX_TEST_BEGIN int error = 0; // // ----------------- TEST_PROPFIND1 ----------------- // test basic propfind request WebdavPropfindRequest *p1 = propfind_parse( sn, rq, TEST_PROPFIND1, strlen(TEST_PROPFIND1), &error); UCX_TEST_ASSERT(p1, "p1 is NULL"); UCX_TEST_ASSERT(p1->properties, "p1: no props"); UCX_TEST_ASSERT(!p1->allprop, "p1: allprop is TRUE"); UCX_TEST_ASSERT(!p1->propname, "p1: propname is TRUE"); UCX_TEST_ASSERT(p1->propcount == 6, "p1: wrong propcount"); // property 1: DAV:displayname WebdavPList *elm = p1->properties; UCX_TEST_ASSERT( !strcmp(elm->property->name, "displayname"), "p1: property 1 has wrong name"); UCX_TEST_ASSERT( !strcmp((char*)elm->property->namespace->href, "DAV:"), "p1: property 1 has wrong namespace"); // property 2: DAV:getcontentlength elm = elm->next; UCX_TEST_ASSERT(elm, "p1: property 2 missing"); UCX_TEST_ASSERT( !strcmp(elm->property->name, "getcontentlength"), "p1: property 2 has wrong name"); UCX_TEST_ASSERT( !strcmp((char*)elm->property->namespace->href, "DAV:"), "p1: property 2 has wrong namespace"); elm = elm->next; UCX_TEST_ASSERT(elm, "p1: property 3 missing"); elm = elm->next; UCX_TEST_ASSERT(elm, "p1: property 4 missing"); elm = elm->next; UCX_TEST_ASSERT(elm, "p1: property 5 missing"); // property 6: DAV:getetag elm = elm->next; UCX_TEST_ASSERT(elm, "p1: property 6 missing"); UCX_TEST_ASSERT( !strcmp(elm->property->name, "getetag"), "p1: property 6 has wrong name"); UCX_TEST_ASSERT( !strcmp((char*)elm->property->namespace->href, "DAV:"), "p1: property 6 has wrong namespace"); UCX_TEST_ASSERT(!elm->next, "p1: should not have property 7"); // // ----------------- TEST_PROPFIND2 ----------------- // test with multiple namespaces WebdavPropfindRequest *p2 = propfind_parse( sn, rq, TEST_PROPFIND2, strlen(TEST_PROPFIND2), &error); UCX_TEST_ASSERT(p2, "p2 is NULL"); UCX_TEST_ASSERT(p2->properties, "p2: no props"); UCX_TEST_ASSERT(!p2->allprop, "p2: allprop is TRUE"); UCX_TEST_ASSERT(!p2->propname, "p2: propname is TRUE"); // property 1: DAV:resourcetype elm = p2->properties; UCX_TEST_ASSERT( !strcmp(elm->property->name, "resourcetype"), "p2: property 1 has wrong name"); UCX_TEST_ASSERT( !strcmp((char*)elm->property->namespace->href, "DAV:"), "p2: property 1 has wrong namespace"); // property 2: X:testprop elm = elm->next; UCX_TEST_ASSERT(elm, "p2: property 2 missing"); UCX_TEST_ASSERT( !strcmp(elm->property->name, "testprop"), "p2: property 2 has wrong name"); UCX_TEST_ASSERT( !strcmp((char*)elm->property->namespace->href, "http://example.com/"), "p2: property 2 has wrong namespace"); // property 3: X:name elm = elm->next; UCX_TEST_ASSERT(elm, "p2: property 3 missing"); UCX_TEST_ASSERT( !strcmp(elm->property->name, "name"), "p2: property 3 has wrong name"); UCX_TEST_ASSERT( !strcmp((char*)elm->property->namespace->href, "http://example.com/"), "p2: property 3 has wrong namespace"); // property 4: Z:testprop elm = elm->next; UCX_TEST_ASSERT(elm, "p2: property 4 missing"); UCX_TEST_ASSERT( !strcmp(elm->property->name, "testprop"), "p2: property 4 has wrong name"); UCX_TEST_ASSERT( !strcmp((char*)elm->property->namespace->href, "testns"), "p2: property 4 has wrong namespace"); // // ----------------- TEST_PROPFIND3 ----------------- // test allprop WebdavPropfindRequest *p3 = propfind_parse(sn, rq, TEST_PROPFIND3, strlen(TEST_PROPFIND3), &error); UCX_TEST_ASSERT(p3, "p3 is NULL"); UCX_TEST_ASSERT(!p3->properties, "p2: has props"); UCX_TEST_ASSERT(p3->allprop, "p2: allprop is FALSE"); UCX_TEST_ASSERT(!p3->propname, "p2: propname is TRUE"); UCX_TEST_ASSERT(p3->propcount == 0, "p2: wrong propcount"); // // ----------------- TEST_PROPFIND4 ----------------- // test propname WebdavPropfindRequest *p4 = propfind_parse(sn, rq, TEST_PROPFIND4, strlen(TEST_PROPFIND4), &error); UCX_TEST_ASSERT(p4, "p4 is NULL"); UCX_TEST_ASSERT(!p4->properties, "p2: has props"); UCX_TEST_ASSERT(!p4->allprop, "p2: allprop is TRUE"); UCX_TEST_ASSERT(p4->propname, "p2: propname is FALSE"); // // ----------------- TEST_PROPFIND5 ----------------- // test duplicate check WebdavPropfindRequest *p5 = propfind_parse(sn, rq, TEST_PROPFIND5, strlen(TEST_PROPFIND5), &error); UCX_TEST_ASSERT(p5, "p5 is NULL"); UCX_TEST_ASSERT(p5->properties, "p5: no props"); UCX_TEST_ASSERT(!p5->allprop, "p5: allprop is TRUE"); UCX_TEST_ASSERT(!p5->propname, "p5: propname is TRUE"); UCX_TEST_ASSERT(p5->propcount == 4, "p5: wrong propcount"); // property 1: DAV:displayname elm = p5->properties; UCX_TEST_ASSERT(elm, "p5: property 1 missing"); UCX_TEST_ASSERT( !strcmp(elm->property->name, "displayname"), "p5: property 1 has wrong name"); UCX_TEST_ASSERT( !strcmp((char*)elm->property->namespace->href, "DAV:"), "p5: property 1 has wrong namespace"); elm = elm->next; UCX_TEST_ASSERT(elm, "p5: property 2 missing"); elm = elm->next; UCX_TEST_ASSERT(elm, "p5: property 3 missing"); // property 4: DAV:resourcetype elm = elm->next; UCX_TEST_ASSERT(elm, "p5: property 4 missing"); UCX_TEST_ASSERT( !strcmp(elm->property->name, "resourcetype"), "p5: property 4 has wrong name"); UCX_TEST_ASSERT( !strcmp((char*)elm->property->namespace->href, "DAV:"), "p5: property 4 has wrong namespace"); // // ----------------- TEST_PROPFIND6 ----------------- // test prop/allprop mix WebdavPropfindRequest *p6 = propfind_parse(sn, rq, TEST_PROPFIND6, strlen(TEST_PROPFIND6), &error); UCX_TEST_ASSERT(p6, "p5 is NULL"); UCX_TEST_ASSERT(!p6->properties, "p5: has props"); UCX_TEST_ASSERT(p6->allprop, "p5: allprop is FALSE"); UCX_TEST_ASSERT(!p6->propname, "p5: propname is TRUE"); UCX_TEST_ASSERT(p6->propcount == 0, "p5: wrong propcount"); UCX_TEST_END pool_destroy(sn->pool); } UCX_TEST(test_proppatch_parse) { Session *sn = testutil_session(); Request *rq = testutil_request(sn->pool, "PROPPATCH", "/"); UCX_TEST_BEGIN int error = 0; WebdavProppatchRequest *p1 = proppatch_parse(sn, rq, TEST_PROPPATCH1, strlen(TEST_PROPPATCH1), &error); UCX_TEST_ASSERT(p1->set, "p1: missing set props"); UCX_TEST_ASSERT(!p1->remove, "p1: has remove props"); UCX_TEST_ASSERT(p1->setcount == 2, "p1: wrong setcount"); UCX_TEST_ASSERT(p1->set->next, "p1: set plist broken"); UCX_TEST_ASSERT(!p1->set->next->next, "p1: set plist has no end"); UCX_TEST_ASSERT(p1->set->property, "p1: missing property ptr in plist"); UCX_TEST_ASSERT( !strcmp(p1->set->property->name, "test"), "p1: wrong property 1 name"); WebdavProppatchRequest *p2 = proppatch_parse(sn, rq, TEST_PROPPATCH2, strlen(TEST_PROPPATCH2), &error); UCX_TEST_ASSERT(p2->set, "p2: missing set props"); UCX_TEST_ASSERT(p2->remove, "p2: missing remove props"); UCX_TEST_ASSERT(p2->setcount == 4, "p2: wrong setcount"); UCX_TEST_ASSERT(p2->removecount == 1, "p2: wrong removecount"); UCX_TEST_ASSERT( !strcmp((char*)p2->set->property->namespace->href, "http://example.com/"), "p2: set property 1: wrong namespace"); UCX_TEST_ASSERT( !strcmp(p2->set->property->name, "a"), "p2: set property 1: wrong name"); WSXmlNode *p2set1 = p2->set->property->value.node; UCX_TEST_ASSERT( p2set1->type == WS_NODE_TEXT, "p2: set property 1: wrong type"); UCX_TEST_ASSERT( p2set1->content, "p2: set property 1: no text"); UCX_TEST_ASSERT( !strcmp((char*)p2set1->content, "test"), "p2: set property 1: wrong value"); WSXmlNode *p2set3 = p2->set->next->next->property->value.node; UCX_TEST_ASSERT(p2set3, "p2: set property 3 missing"); UCX_TEST_ASSERT( p2set3->type == WS_NODE_TEXT, "p2: set property 3: wrong type"); UCX_TEST_ASSERT( p2set3->next, "p2: set property 3: missing element X:name"); UCX_TEST_ASSERT( xmlHasProp(p2set3->next, BAD_CAST"test"), "p2: set property 3: missing attribute 'test'"); UCX_TEST_ASSERT( xmlHasProp(p2set3->next, BAD_CAST"abc"), "p2: set property 3: missing attribute 'abc"); xmlChar *value1 = xmlGetProp(p2set3->next, BAD_CAST"test"); UCX_TEST_ASSERT( !strcmp((char*) value1, "test1"), "p2: set property 3: wrong attribute value 1"); xmlFree(value1); xmlChar *value2 = xmlGetProp(p2set3->next, BAD_CAST"abc"); UCX_TEST_ASSERT( !strcmp((char*) value2, "def"), "p2: set property 3: wrong attribute value 2"); xmlFree(value2); UCX_TEST_ASSERT( !strcmp(p2->remove->property->name, "e"), "p2: wrong remove property"); UCX_TEST_END pool_destroy(sn->pool); } UCX_TEST(test_lock_parse) { Session *sn = testutil_session(); Request *rq = testutil_request(sn->pool, "LOCK", "/"); UCX_TEST_BEGIN int error = 0; WebdavLockRequest *l1 = lock_parse(sn, rq, TEST_LOCK1, strlen(TEST_LOCK1), &error); UCX_TEST_ASSERT(l1, "l1 is NULL"); UCX_TEST_ASSERT(l1->type == WEBDAV_LOCK_WRITE, "l1: wrong type"); UCX_TEST_ASSERT(l1->scope == WEBDAV_LOCK_SHARED, "l1: wrong scope"); UCX_TEST_ASSERT(l1->owner, "l1: owner is NULL"); UCX_TEST_ASSERT(!strcmp((char*)l1->owner->content, "User"), "l1: wrong owner"); UCX_TEST_END pool_destroy(sn->pool); } UCX_TEST(test_rqbody2buffer) { Session *sn; Request *rq; UCX_TEST_BEGIN; // // TEST 1 sn = testutil_session(); rq = testutil_request(sn->pool, "PUT", "/"); testutil_request_body(sn, rq, "Hello World!", 12); UcxBuffer *b1 = rqbody2buffer(sn, rq); UCX_TEST_ASSERT(b1->size == 12, "b1: wrong size"); UCX_TEST_ASSERT(!memcmp(b1->space,"Hello World!",12), "b1: wrong content"); ucx_buffer_free(b1); testutil_destroy_session(sn); // // TEST 2 size_t len1 = 25000; unsigned char *body1 = malloc(len1); for(int i=0;i<len1;i++) { body1[i] = i; } sn = testutil_session(); rq = testutil_request(sn->pool, "PUT", "/"); testutil_request_body(sn, rq, (char*)body1, len1); UcxBuffer *b2 = rqbody2buffer(sn, rq); UCX_TEST_ASSERT(b2->size == len1, "b2: wrong size"); UCX_TEST_ASSERT(!memcmp(b2->space, body1, len1), "b2: wrong content"); ucx_buffer_free(b2); testutil_destroy_session(sn); UCX_TEST_END; } UCX_TEST(test_webdav_plist_iterator) { Session *sn; Request *rq; WebdavPropfindRequest *propfind; UCX_TEST_BEGIN; UCX_TEST_ASSERT(!test_init(&sn, &rq, &propfind, TEST_PROPFIND1), "init failed"); WebdavPList *properties = propfind->properties; size_t count = 0; WebdavPListIterator i = webdav_plist_iterator(&properties); WebdavPList *cur; while(webdav_plist_iterator_next(&i, &cur)) { switch(i.index) { case 0: { UCX_TEST_ASSERT(!strcmp(cur->property->name, "displayname"), "wrong property 1"); break; } case 1: { UCX_TEST_ASSERT(!strcmp(cur->property->name, "getcontentlength"), "wrong property 2"); break; } case 2: { UCX_TEST_ASSERT(!strcmp(cur->property->name, "getcontenttype"), "wrong property 3"); break; } case 3: { UCX_TEST_ASSERT(!strcmp(cur->property->name, "getlastmodified"), "wrong property 4"); break; } case 4: { UCX_TEST_ASSERT(!strcmp(cur->property->name, "resourcetype"), "wrong property 5"); break; } case 5: { UCX_TEST_ASSERT(!strcmp(cur->property->name, "getetag"), "wrong property 6"); break; } } count++; } UCX_TEST_ASSERT(count == propfind->propcount, "wrong count"); UCX_TEST_END; testutil_destroy_session(sn); } UCX_TEST(test_webdav_plist_iterator_remove_current) { Session *sn; Request *rq; WebdavPropfindRequest *propfind; UCX_TEST_BEGIN; UCX_TEST_ASSERT(!test_init(&sn, &rq, &propfind, TEST_PROPFIND1), "init failed"); WebdavPList *properties1 = webdav_plist_clone(sn->pool, propfind->properties); WebdavPList *properties2 = webdav_plist_clone(sn->pool, propfind->properties); WebdavPList *properties3 = webdav_plist_clone(sn->pool, propfind->properties); WebdavPList *properties4 = webdav_plist_clone(sn->pool, propfind->properties); WebdavPListIterator i; WebdavPList *cur; // test removal of first element i = webdav_plist_iterator(&properties1); while(webdav_plist_iterator_next(&i, &cur)) { if(i.index == 0) { webdav_plist_iterator_remove_current(&i); } } UCX_TEST_ASSERT(!properties1->prev, "test1: prev not cleared"); UCX_TEST_ASSERT(!strcmp(properties1->property->name, "getcontentlength"), "test1: wrong property"); UCX_TEST_ASSERT(!strcmp(properties1->next->property->name, "getcontenttype"), "test1: wrong property 2"); UCX_TEST_ASSERT(properties1->next->prev == properties1, "test1: wrong link"); // test removal of second element i = webdav_plist_iterator(&properties2); while(webdav_plist_iterator_next(&i, &cur)) { if(i.index == 1) { webdav_plist_iterator_remove_current(&i); } } UCX_TEST_ASSERT(!strcmp(properties2->next->property->name, "getcontenttype"), "test2: wrong property"); UCX_TEST_ASSERT(properties2->next->prev == properties2, "test2: wrong link"); UCX_TEST_ASSERT(webdav_plist_size(properties2) == 5, "test2: wrong size"); // remove last element i = webdav_plist_iterator(&properties3); while(webdav_plist_iterator_next(&i, &cur)) { if(i.index == 5) { webdav_plist_iterator_remove_current(&i); } } UCX_TEST_ASSERT(webdav_plist_size(properties3) == 5, "test3: wrong size"); UCX_TEST_ASSERT(!strcmp(properties3->next->next->next->next->property->name, "resourcetype"), "test2: wrong property"); // remove all elements i = webdav_plist_iterator(&properties4); while(webdav_plist_iterator_next(&i, &cur)) { webdav_plist_iterator_remove_current(&i); switch(i.index) { case 0: { UCX_TEST_ASSERT(!strcmp(properties4->property->name, "getcontentlength"), "test4: wrong property 2"); UCX_TEST_ASSERT(properties4->prev == NULL, "test4: prev not NULL (0)"); break; } case 1: { UCX_TEST_ASSERT(!strcmp(properties4->property->name, "getcontenttype"), "test4: wrong property 3"); UCX_TEST_ASSERT(properties4->prev == NULL, "test4: prev not NULL (1)"); break; } case 2: { UCX_TEST_ASSERT(!strcmp(properties4->property->name, "getlastmodified"), "test4: wrong property 4"); UCX_TEST_ASSERT(properties4->prev == NULL, "test4: prev not NULL (2)"); break; } case 3: { UCX_TEST_ASSERT(!strcmp(properties4->property->name, "resourcetype"), "test4: wrong property 5"); UCX_TEST_ASSERT(properties4->prev == NULL, "test4: prev not NULL (3)"); break; } case 4: { UCX_TEST_ASSERT(!strcmp(properties4->property->name, "getetag"), "test4: wrong property 6"); UCX_TEST_ASSERT(properties4->prev == NULL, "test4: prev not NULL (4)"); break; } default: { UCX_TEST_ASSERT(i.index <= 5, "fail"); } } } UCX_TEST_ASSERT(properties4 == NULL, "test4: list not NULL"); UCX_TEST_END; testutil_destroy_session(sn); } UCX_TEST(test_msresponse_addproperty) { Session *sn; Request *rq; UCX_TEST_BEGIN; 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]; const char *names[] = {"a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9"}; WSNamespace ns1; ZERO(&ns1, sizeof(WSNamespace)); WSNamespace ns2; ZERO(&ns2, sizeof(WSNamespace)); ns1.prefix = (xmlChar*)"x1"; ns1.href = (xmlChar*)"http://example.com/test/"; ns2.prefix = (xmlChar*)"x2"; ns2.href = (xmlChar*)"http://example.com/test/"; WebdavProperty dp1; ZERO(&dp1, sizeof(WebdavProperty)); dp1.name = "dup"; dp1.namespace = &ns1; dp1.value.text.str = "Hello"; dp1.value.text.length = 5; dp1.vtype = WS_VALUE_TEXT; WebdavProperty dp2; ZERO(&dp2, sizeof(WebdavProperty)); dp2.name = "dup"; dp2.namespace = &ns1; dp2.value.text.str = "Hello"; dp2.value.text.length = 5; dp2.vtype = WS_VALUE_TEXT; WebdavProperty dp3; ZERO(&dp3, sizeof(WebdavProperty)); dp3.name = "dup"; dp3.namespace = &ns2; dp3.value.text.str = "Hello"; dp3.value.text.length = 5; dp3.vtype = WS_VALUE_TEXT; // init test data p1.namespace = webdav_dav_namespace(); p1.lang = NULL; p1.name = "test1"; p1.value.data = NULL; p1.vtype = 0; for(int i=0;i<8;i++) { p[i].namespace = webdav_dav_namespace(); p[i].name = names[i]; p[i].lang = NULL; p[i].value.node = NULL; p[1].vtype = 0; } UCX_TEST_ASSERT(!r->plist_begin && !r->plist_end, "plist not empty"); r->resource.addproperty((WebdavResource*)r, &p1, 200); UCX_TEST_ASSERT(r->plist_begin, "!plist_begin"); UCX_TEST_ASSERT(r->plist_begin == r->plist_end, "plist begin != end"); r->resource.addproperty((WebdavResource*)r, &p[0], 404); r->resource.addproperty((WebdavResource*)r, &p[1], 404); r->resource.addproperty((WebdavResource*)r, &p[2], 403); r->resource.addproperty((WebdavResource*)r, &p[3], 403); r->resource.addproperty((WebdavResource*)r, &p[4], 403); r->resource.addproperty((WebdavResource*)r, &p[5], 403); r->resource.addproperty((WebdavResource*)r, &p[6], 500); UCX_TEST_ASSERT(r->plist_begin == r->plist_end, "plist begin != end"); UCX_TEST_ASSERT(r->errors, "no prop errors"); UCX_TEST_ASSERT(r->errors->next, "no second error code"); UCX_TEST_ASSERT(r->errors->next->next, "no third error code"); UCX_TEST_ASSERT(!r->errors->next->next->next, "too many error codes"); UCX_TEST_ASSERT(webdav_plist_size(r->errors->begin) == 2, "404 list size != 2"); UCX_TEST_ASSERT(webdav_plist_size(r->errors->next->begin) == 4, "403 list size != 4"); UCX_TEST_ASSERT(webdav_plist_size(r->errors->next->next->begin) == 1, "500 list size != 1"); // new resource for prop duplication tests r = (MSResponse*)ms->response.addresource((WebdavResponse*)ms, "/test"); UCX_TEST_ASSERT(r, "cannot create second response"); r->resource.addproperty((WebdavResource*)r, &dp1, 200); UCX_TEST_ASSERT(r->plist_begin, "adding dp1 failed"); UCX_TEST_ASSERT(!r->plist_begin->next, "dp1: list size not 1"); r->resource.addproperty((WebdavResource*)r, &dp2, 200); UCX_TEST_ASSERT(!r->plist_begin->next, "dp1: adding dp2 should not work"); r->resource.addproperty((WebdavResource*)r, &dp2, 404); UCX_TEST_ASSERT(!r->plist_begin->next, "dp1: adding dp2 with different status should not work (1)"); if(r->errors) { UCX_TEST_ASSERT(webdav_plist_size(r->errors->begin) == 0, "dp1: error list not empty"); } r->resource.addproperty((WebdavResource*)r, &dp3, 200); UCX_TEST_ASSERT(!r->plist_begin->next, "dp1: adding dp3 should not work"); UCX_TEST_END; } UCX_TEST(test_webdav_propfind_init) { reset_backends(); Session *sn; Request *rq; WebdavPropfindRequest *propfind; UCX_TEST_BEGIN; UCX_TEST_ASSERT(!test_init(&sn, &rq, &propfind, TEST_PROPFIND1), "init failed"); UcxList *requests = NULL; int err = webdav_propfind_init(&backend1, propfind, "/", &requests); UCX_TEST_ASSERT(!err, "webdav_propfind_init failed"); UCX_TEST_ASSERT(requests, "request list is empty"); UCX_TEST_ASSERT(ucx_list_size(requests), "request list has wrong size"); WebdavPropfindRequest *p1 = requests->data; WebdavPropfindRequest *p2 = requests->next->data; // backend1 removes the first property from the plist // backend2 should have one property less UCX_TEST_ASSERT(p1 && p2, "missing requests objects"); UCX_TEST_ASSERT(p1 != p2, "request objects equal"); UCX_TEST_ASSERT(p1->properties != p2->properties, "plists equal"); UCX_TEST_ASSERT(p1->propcount == p2->propcount + 1, "first property not removed"); UCX_TEST_ASSERT(backend1_init_called == 1, "backend1 init not called"); UCX_TEST_ASSERT(backend2_init_called == 1, "backend2 init not called"); UCX_TEST_END; pool_destroy(sn->pool); } UCX_TEST(test_webdav_op_propfind_begin) { reset_backends(); Session *sn; Request *rq; UCX_TEST_BEGIN; WebdavOperation *op = test_propfind_op(&sn, &rq, TEST_PROPFIND1); UCX_TEST_ASSERT(op, "WebdavOperation not created"); int err = webdav_op_propfind_begin(op, "/", NULL, NULL); UCX_TEST_ASSERT(err == 0, "err not 0"); UCX_TEST_ASSERT(backend1_propfind_do_count == 1, "backend1 propfind_do not called"); UCX_TEST_ASSERT(backend2_propfind_do_count == 1, "backend2 propfind_do not called"); UCX_TEST_END; testutil_destroy_session(sn); } UCX_TEST(test_webdav_op_propfind_children) { reset_backends(); Session *sn; Request *rq; UCX_TEST_BEGIN; WebdavOperation *op = test_propfind_op(&sn, &rq, TEST_PROPFIND1); UCX_TEST_ASSERT(op, "WebdavOperation not created"); int err = webdav_op_propfind_begin(op, "/", NULL, NULL); UCX_TEST_ASSERT(err == 0, "propfind_begin error"); // create test vfs with some files (code from test_vfs_readdir) rq->vfs = testvfs_create(sn); VFSContext *vfs = vfs_request_context(sn, rq); UCX_TEST_ASSERT(vfs, "no vfs"); err = vfs_mkdir(vfs, "/dir"); UCX_TEST_ASSERT(err == 0, "error not 0"); // add some test file to /dir UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file1", O_CREAT), "creation of file1 failed"); UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file2", O_CREAT), "creation of file2 failed"); UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file3", O_CREAT), "creation of file3 failed"); UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file4", O_CREAT), "creation of file4 failed"); VFSDir *dir = vfs_opendir(vfs, "/dir"); UCX_TEST_ASSERT(dir, "dir not opened"); UCX_TEST_ASSERT(backend1_propfind_do_count == 1, "backend1 propfind_do not called"); 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"); UCX_TEST_ASSERT(err == 0, "webdav_op_propfind_children failed"); // 1 dir + 4 children UCX_TEST_ASSERT(backend1_propfind_do_count == 5, "backend1 propfind_do wrong count"); UCX_TEST_ASSERT(backend2_propfind_do_count == 5, "backend2 propfind_do wrong count"); UCX_TEST_END; testutil_destroy_session(sn); } UCX_TEST(test_webdav_propfind) { Session *sn = testutil_session(); Request *rq = testutil_request(sn->pool, "PROPFIND", "/"); pblock_nvinsert("path", "/", rq->vars); pblock_nvinsert("uri", "/", rq->reqpb); TestIOStream *st = testutil_iostream(2048, TRUE); sn->csd = st; testutil_request_body(sn, rq, TEST_PROPFIND1, strlen(TEST_PROPFIND1)); UCX_TEST_BEGIN; pblock *pb = pblock_create_pool(sn->pool, 4); int ret = webdav_propfind(pb, sn, rq); UCX_TEST_ASSERT(ret == REQ_PROCEED, "webdav_propfind (1) failed"); xmlDoc *doc = xmlReadMemory( st->buf->space, st->buf->size, NULL, NULL, 0); UCX_TEST_ASSERT(doc, "response is not valid xml"); //printf("\n\n%.*s\n", (int)st->buf->size, st->buf->space); UCX_TEST_END; testutil_destroy_session(sn); }