UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2019 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 33 #include "testutils.h" 34 35 #include "../webdav/requestparser.h" 36 #include "../webdav/webdav.h" 37 #include "../webdav/multistatus.h" 38 #include "../webdav/operation.h" 39 40 #include "vfs.h" 41 #include "webdav.h" 42 43 static int webdav_is_initialized = 0; 44 45 /* ----------------------------- Test Backends --------------------------*/ 46 47 static int backend2_init_called = 0; 48 static int backend2_propfind_do_count = 0; 49 static int backend2_propfind_finish_called = 0; 50 static int backend2_proppatch_commit = 0; 51 static int backend2_proppatch_do_count = 0; 52 static int backend2_proppatch_finish_count = 0; 53 54 // backend2 55 static int backend2_propfind_init( 56 WebdavPropfindRequest *propfind, 57 const char *path, 58 const char *href, 59 WebdavPList **outPList) 60 { 61 backend2_init_called = 1; 62 return 0; 63 } 64 65 static int backend2_propfind_do( 66 WebdavPropfindRequest *propfind, 67 WebdavResponse *response, 68 VFS_DIR parent, 69 WebdavResource *resource, 70 struct stat *s) 71 { 72 backend2_propfind_do_count++; 73 return 0; 74 } 75 76 static int backend2_propfind_finish(WebdavPropfindRequest *propfind) { 77 backend2_propfind_finish_called = 1; 78 return 0; 79 } 80 81 static int backend2_proppatch_do( 82 WebdavProppatchRequest *request, 83 WebdavResource *response, 84 VFSFile *file, 85 WebdavPList **out_set, 86 WebdavPList **out_remove) 87 { 88 backend2_proppatch_do_count++; 89 90 if(*out_remove) { 91 return 1; // backend1 should remove all remove-props 92 } 93 94 WebdavPListIterator i = webdav_plist_iterator(out_set); 95 WebdavPList *cur; 96 while(webdav_plist_iterator_next(&i, &cur)) { 97 if(!strcmp(cur->property->name, "a")) { 98 // property 'a' should already be removed by backend1 99 return 1; 100 } else if(!strcmp(cur->property->name, "abort")) { 101 return 1; // test abort 102 } 103 response->addproperty(response, cur->property, 200); 104 webdav_plist_iterator_remove_current(&i); 105 } 106 107 return 0; 108 } 109 110 static int backend2_proppatch_finish( 111 WebdavProppatchRequest *request, 112 WebdavResource *response, 113 VFSFile *file, 114 WSBool commit) 115 { 116 backend2_proppatch_finish_count++; 117 backend2_proppatch_commit = commit; 118 return 0; 119 } 120 121 static WebdavBackend backend2 = { 122 backend2_propfind_init, 123 backend2_propfind_do, 124 backend2_propfind_finish, 125 backend2_proppatch_do, 126 backend2_proppatch_finish, 127 NULL, // opt_mkcol 128 NULL, // opt_mkcol_finish 129 NULL, // opt_delete 130 NULL, // opt_delete_finish 131 0, 132 NULL, // instance 133 NULL 134 }; 135 136 // backend1 137 138 static int backend1_init_called = 0; 139 static int backend1_propfind_do_count = 0; 140 static int backend1_propfind_finish_called = 0; 141 static int backend1_proppatch_commit = 0; 142 static int backend1_proppatch_do_count = 0; 143 static int backend1_proppatch_finish_count = 0; 144 145 146 static int backend1_propfind_init( 147 WebdavPropfindRequest *propfind, 148 const char *path, 149 const char *href, 150 WebdavPList **outPList) 151 { 152 backend1_init_called = 1; 153 154 WebdavPList *plist = *outPList; 155 WebdavProperty *p = plist->property; 156 if(!strcmp(p->name, "displayname")) { 157 plist->next->prev = NULL; 158 *outPList = plist->next; // remove first item from plist 159 } else { 160 return 1; 161 } 162 163 return 0; 164 } 165 166 static int backend1_propfind_do( 167 WebdavPropfindRequest *propfind, 168 WebdavResponse *response, 169 VFS_DIR parent, 170 WebdavResource *resource, 171 struct stat *s) 172 { 173 backend1_propfind_do_count++; 174 return 0; 175 } 176 177 static int backend1_propfind_finish(WebdavPropfindRequest *propfind) { 178 backend1_propfind_finish_called = 1; 179 return 0; 180 } 181 182 static int backend1_proppatch_do( 183 WebdavProppatchRequest *request, 184 WebdavResource *response, 185 VFSFile *file, 186 WebdavPList **out_set, 187 WebdavPList **out_remove) 188 { 189 backend1_proppatch_do_count++; 190 191 // remove everything from out_remove 192 WebdavPListIterator i = webdav_plist_iterator(out_remove); 193 WebdavPList *cur; 194 while(webdav_plist_iterator_next(&i, &cur)) { 195 response->addproperty(response, cur->property, 200); 196 webdav_plist_iterator_remove_current(&i); 197 } 198 199 // remove property 'a' and fail at property 'fail' 200 i = webdav_plist_iterator(out_set); 201 while(webdav_plist_iterator_next(&i, &cur)) { 202 if(!strcmp(cur->property->name, "fail")) { 203 response->addproperty(response, cur->property, 403); 204 webdav_plist_iterator_remove_current(&i); 205 } else if(!strcmp(cur->property->name, "a")) { 206 response->addproperty(response, cur->property, 200); 207 webdav_plist_iterator_remove_current(&i); 208 } 209 } 210 211 return 0; 212 } 213 214 static int backend1_proppatch_finish( 215 WebdavProppatchRequest *request, 216 WebdavResource *response, 217 VFSFile *file, 218 WSBool commit) 219 { 220 backend1_proppatch_finish_count++; 221 backend1_proppatch_commit = commit; 222 return 0; 223 } 224 225 WebdavBackend backend1 = { 226 backend1_propfind_init, 227 backend1_propfind_do, 228 backend1_propfind_finish, 229 backend1_proppatch_do, 230 backend1_proppatch_finish, 231 NULL, // opt_mkcol 232 NULL, // opt_mkcol_finish 233 NULL, // opt_delete 234 NULL, // opt_delete_finish 235 0, 236 NULL, // instance 237 &backend2 238 }; 239 240 static void reset_backends(void) { 241 backend1_init_called = 0; 242 backend1_propfind_do_count = 0; 243 backend1_propfind_finish_called = 0; 244 backend1_proppatch_commit = 0; 245 backend1_proppatch_do_count = 0; 246 backend1_proppatch_finish_count = 0; 247 backend2_init_called = 0; 248 backend2_propfind_do_count = 0; 249 backend2_propfind_finish_called = 0; 250 backend2_proppatch_commit = 0; 251 backend2_proppatch_do_count = 0; 252 backend2_proppatch_finish_count = 0; 253 } 254 255 /* ----------------------------------------------------------------------*/ 256 257 258 static int test_init( 259 Session **out_sn, 260 Request **out_rq, 261 WebdavPropfindRequest **out_propfind, 262 const char *xml) 263 { 264 if(!webdav_is_initialized) { 265 if(webdav_init(NULL, NULL, NULL) != REQ_PROCEED) { 266 return 1; 267 } 268 webdav_is_initialized = 1; 269 } 270 271 Session *sn = testutil_session(); 272 Request *rq = testutil_request(sn->pool, "PROPFIND", "/"); 273 274 int error = 0; 275 276 WebdavPropfindRequest *propfind = propfind_parse( 277 sn, 278 rq, 279 xml, 280 strlen(xml), 281 &error); 282 283 if(error) { 284 return 1; 285 } 286 287 if(!propfind || !propfind->properties) { 288 return 1; 289 } 290 291 *out_sn = sn; 292 *out_rq = rq; 293 *out_propfind = propfind; 294 return 0; 295 } 296 297 static WebdavOperation* test_propfind_op( 298 Session **out_sn, 299 Request **out_rq, 300 const char *xml) 301 { 302 WebdavPropfindRequest *propfind; 303 if(test_init(out_sn, out_rq, &propfind, xml)) { 304 return NULL; 305 } 306 307 Multistatus *ms = multistatus_response(*out_sn, *out_rq); 308 if(!ms) { 309 return NULL; 310 } 311 // WebdavResponse is the public interface used by Backends 312 // for adding resources to the response 313 WebdavResponse *response = (WebdavResponse*)ms; 314 315 WebdavPropfindRequestList *requests = NULL; 316 317 // Initialize all Webdav Backends 318 if(webdav_propfind_init(&backend1, propfind, "/", "/", &requests)) { 319 return NULL; 320 } 321 322 return webdav_create_propfind_operation( 323 (*out_sn), 324 (*out_rq), 325 &backend1, 326 propfind->properties, 327 requests, 328 response); 329 } 330 331 332 UCX_TEST(test_webdav_plist_add) { 333 Session *sn = testutil_session(); 334 335 UCX_TEST_BEGIN; 336 337 WebdavPList *begin = NULL; 338 WebdavPList *end = NULL; 339 340 WebdavProperty p1, p2, p3; 341 ZERO(&p1, sizeof(WebdavProperty)); 342 ZERO(&p2, sizeof(WebdavProperty)); 343 ZERO(&p3, sizeof(WebdavProperty)); 344 int r; 345 346 r = webdav_plist_add(sn->pool, &begin, &end, &p1); 347 348 UCX_TEST_ASSERT(r == 0, "add 1 failed"); 349 UCX_TEST_ASSERT(begin && end, "ptrs are NULL"); 350 UCX_TEST_ASSERT(begin == end, "begin != end"); 351 UCX_TEST_ASSERT(begin->prev == NULL, "begin->prev not NULL"); 352 UCX_TEST_ASSERT(begin->next == NULL, "begin->next not NULL"); 353 354 r = webdav_plist_add(sn->pool, &begin, &end, &p2); 355 356 UCX_TEST_ASSERT(r == 0, "add 2 failed"); 357 UCX_TEST_ASSERT(begin && end, "add2: ptrs are NULL"); 358 UCX_TEST_ASSERT(begin->next, "begin->next is NULL"); 359 UCX_TEST_ASSERT(begin->next == end, "begin->next != end"); 360 UCX_TEST_ASSERT(end->prev = begin, "end->prev != begin"); 361 UCX_TEST_ASSERT(begin->prev == NULL, "add2: begin->prev not NULL"); 362 UCX_TEST_ASSERT(end->next == NULL, "add2: end->next not NULL"); 363 364 r = webdav_plist_add(sn->pool, &begin, &end, &p3); 365 366 UCX_TEST_ASSERT(r == 0, "add 3 failed"); 367 UCX_TEST_ASSERT(begin && end, "add3: ptrs are NULL"); 368 UCX_TEST_ASSERT(begin->next == end->prev, "begin->next != end->prev"); 369 370 UCX_TEST_END; 371 372 testutil_destroy_session(sn); 373 } 374 375 UCX_TEST(test_webdav_plist_size) { 376 Session *sn = testutil_session(); 377 378 UCX_TEST_BEGIN; 379 380 WebdavPList *begin = NULL; 381 WebdavPList *end = NULL; 382 383 WebdavProperty p1, p2, p3; 384 ZERO(&p1, sizeof(WebdavProperty)); 385 ZERO(&p2, sizeof(WebdavProperty)); 386 ZERO(&p3, sizeof(WebdavProperty)); 387 int r; 388 389 UCX_TEST_ASSERT(webdav_plist_size(begin) == 0, "size != 0"); 390 r = webdav_plist_add(sn->pool, &begin, &end, &p1); 391 UCX_TEST_ASSERT(webdav_plist_size(begin) == 1, "size != 1"); 392 r = webdav_plist_add(sn->pool, &begin, &end, &p2); 393 UCX_TEST_ASSERT(webdav_plist_size(begin) == 2, "size != 2"); 394 r = webdav_plist_add(sn->pool, &begin, &end, &p3); 395 UCX_TEST_ASSERT(webdav_plist_size(begin) == 3, "size != 3"); 396 397 UCX_TEST_END; 398 399 testutil_destroy_session(sn); 400 } 401 402 UCX_TEST(test_propfind_parse) { 403 Session *sn = testutil_session(); 404 Request *rq = testutil_request(sn->pool, "PROPFIND", "/"); 405 406 UCX_TEST_BEGIN 407 408 int error = 0; 409 410 // 411 // ----------------- TEST_PROPFIND1 ----------------- 412 // test basic propfind request 413 WebdavPropfindRequest *p1 = propfind_parse( 414 sn, 415 rq, 416 TEST_PROPFIND1, 417 strlen(TEST_PROPFIND1), 418 &error); 419 420 UCX_TEST_ASSERT(p1, "p1 is NULL"); 421 UCX_TEST_ASSERT(p1->properties, "p1: no props"); 422 UCX_TEST_ASSERT(!p1->allprop, "p1: allprop is TRUE"); 423 UCX_TEST_ASSERT(!p1->propname, "p1: propname is TRUE"); 424 UCX_TEST_ASSERT(p1->propcount == 6, "p1: wrong propcount"); 425 426 // property 1: DAV:displayname 427 WebdavPList *elm = p1->properties; 428 UCX_TEST_ASSERT( 429 !strcmp(elm->property->name, "displayname"), 430 "p1: property 1 has wrong name"); 431 UCX_TEST_ASSERT( 432 !strcmp((char*)elm->property->namespace->href, "DAV:"), 433 "p1: property 1 has wrong namespace"); 434 435 // property 2: DAV:getcontentlength 436 elm = elm->next; 437 UCX_TEST_ASSERT(elm, "p1: property 2 missing"); 438 UCX_TEST_ASSERT( 439 !strcmp(elm->property->name, "getcontentlength"), 440 "p1: property 2 has wrong name"); 441 UCX_TEST_ASSERT( 442 !strcmp((char*)elm->property->namespace->href, "DAV:"), 443 "p1: property 2 has wrong namespace"); 444 445 elm = elm->next; 446 UCX_TEST_ASSERT(elm, "p1: property 3 missing"); 447 elm = elm->next; 448 UCX_TEST_ASSERT(elm, "p1: property 4 missing"); 449 elm = elm->next; 450 UCX_TEST_ASSERT(elm, "p1: property 5 missing"); 451 452 // property 6: DAV:getetag 453 elm = elm->next; 454 UCX_TEST_ASSERT(elm, "p1: property 6 missing"); 455 UCX_TEST_ASSERT( 456 !strcmp(elm->property->name, "getetag"), 457 "p1: property 6 has wrong name"); 458 UCX_TEST_ASSERT( 459 !strcmp((char*)elm->property->namespace->href, "DAV:"), 460 "p1: property 6 has wrong namespace"); 461 UCX_TEST_ASSERT(!elm->next, "p1: should not have property 7"); 462 463 // 464 // ----------------- TEST_PROPFIND2 ----------------- 465 // test with multiple namespaces 466 WebdavPropfindRequest *p2 = propfind_parse( 467 sn, 468 rq, 469 TEST_PROPFIND2, 470 strlen(TEST_PROPFIND2), 471 &error); 472 473 UCX_TEST_ASSERT(p2, "p2 is NULL"); 474 UCX_TEST_ASSERT(p2->properties, "p2: no props"); 475 UCX_TEST_ASSERT(!p2->allprop, "p2: allprop is TRUE"); 476 UCX_TEST_ASSERT(!p2->propname, "p2: propname is TRUE"); 477 478 // property 1: DAV:resourcetype 479 elm = p2->properties; 480 UCX_TEST_ASSERT( 481 !strcmp(elm->property->name, "resourcetype"), 482 "p2: property 1 has wrong name"); 483 UCX_TEST_ASSERT( 484 !strcmp((char*)elm->property->namespace->href, "DAV:"), 485 "p2: property 1 has wrong namespace"); 486 487 // property 2: X:testprop 488 elm = elm->next; 489 UCX_TEST_ASSERT(elm, "p2: property 2 missing"); 490 UCX_TEST_ASSERT( 491 !strcmp(elm->property->name, "testprop"), 492 "p2: property 2 has wrong name"); 493 UCX_TEST_ASSERT( 494 !strcmp((char*)elm->property->namespace->href, "http://example.com/"), 495 "p2: property 2 has wrong namespace"); 496 497 // property 3: X:name 498 elm = elm->next; 499 UCX_TEST_ASSERT(elm, "p2: property 3 missing"); 500 UCX_TEST_ASSERT( 501 !strcmp(elm->property->name, "name"), 502 "p2: property 3 has wrong name"); 503 UCX_TEST_ASSERT( 504 !strcmp((char*)elm->property->namespace->href, "http://example.com/"), 505 "p2: property 3 has wrong namespace"); 506 507 // property 4: Z:testprop 508 elm = elm->next; 509 UCX_TEST_ASSERT(elm, "p2: property 4 missing"); 510 UCX_TEST_ASSERT( 511 !strcmp(elm->property->name, "testprop"), 512 "p2: property 4 has wrong name"); 513 UCX_TEST_ASSERT( 514 !strcmp((char*)elm->property->namespace->href, "testns"), 515 "p2: property 4 has wrong namespace"); 516 517 518 // 519 // ----------------- TEST_PROPFIND3 ----------------- 520 // test allprop 521 WebdavPropfindRequest *p3 = propfind_parse(sn, rq, TEST_PROPFIND3, strlen(TEST_PROPFIND3), &error); 522 523 UCX_TEST_ASSERT(p3, "p3 is NULL"); 524 UCX_TEST_ASSERT(!p3->properties, "p2: has props"); 525 UCX_TEST_ASSERT(p3->allprop, "p2: allprop is FALSE"); 526 UCX_TEST_ASSERT(!p3->propname, "p2: propname is TRUE"); 527 UCX_TEST_ASSERT(p3->propcount == 0, "p2: wrong propcount"); 528 529 530 // 531 // ----------------- TEST_PROPFIND4 ----------------- 532 // test propname 533 WebdavPropfindRequest *p4 = propfind_parse(sn, rq, TEST_PROPFIND4, strlen(TEST_PROPFIND4), &error); 534 535 UCX_TEST_ASSERT(p4, "p4 is NULL"); 536 UCX_TEST_ASSERT(!p4->properties, "p2: has props"); 537 UCX_TEST_ASSERT(!p4->allprop, "p2: allprop is TRUE"); 538 UCX_TEST_ASSERT(p4->propname, "p2: propname is FALSE"); 539 540 541 // 542 // ----------------- TEST_PROPFIND5 ----------------- 543 // test duplicate check 544 WebdavPropfindRequest *p5 = propfind_parse(sn, rq, TEST_PROPFIND5, strlen(TEST_PROPFIND5), &error); 545 546 UCX_TEST_ASSERT(p5, "p5 is NULL"); 547 UCX_TEST_ASSERT(p5->properties, "p5: no props"); 548 UCX_TEST_ASSERT(!p5->allprop, "p5: allprop is TRUE"); 549 UCX_TEST_ASSERT(!p5->propname, "p5: propname is TRUE"); 550 UCX_TEST_ASSERT(p5->propcount == 4, "p5: wrong propcount"); 551 552 // property 1: DAV:displayname 553 elm = p5->properties; 554 UCX_TEST_ASSERT(elm, "p5: property 1 missing"); 555 UCX_TEST_ASSERT( 556 !strcmp(elm->property->name, "displayname"), 557 "p5: property 1 has wrong name"); 558 UCX_TEST_ASSERT( 559 !strcmp((char*)elm->property->namespace->href, "DAV:"), 560 "p5: property 1 has wrong namespace"); 561 562 elm = elm->next; 563 UCX_TEST_ASSERT(elm, "p5: property 2 missing"); 564 elm = elm->next; 565 UCX_TEST_ASSERT(elm, "p5: property 3 missing"); 566 567 // property 4: DAV:resourcetype 568 elm = elm->next; 569 UCX_TEST_ASSERT(elm, "p5: property 4 missing"); 570 UCX_TEST_ASSERT( 571 !strcmp(elm->property->name, "resourcetype"), 572 "p5: property 4 has wrong name"); 573 UCX_TEST_ASSERT( 574 !strcmp((char*)elm->property->namespace->href, "DAV:"), 575 "p5: property 4 has wrong namespace"); 576 577 578 // 579 // ----------------- TEST_PROPFIND6 ----------------- 580 // test prop/allprop mix 581 WebdavPropfindRequest *p6 = propfind_parse(sn, rq, TEST_PROPFIND6, strlen(TEST_PROPFIND6), &error); 582 583 UCX_TEST_ASSERT(p6, "p5 is NULL"); 584 UCX_TEST_ASSERT(!p6->properties, "p5: has props"); 585 UCX_TEST_ASSERT(p6->allprop, "p5: allprop is FALSE"); 586 UCX_TEST_ASSERT(!p6->propname, "p5: propname is TRUE"); 587 UCX_TEST_ASSERT(p6->propcount == 0, "p5: wrong propcount"); 588 589 UCX_TEST_END 590 591 pool_destroy(sn->pool); 592 } 593 594 UCX_TEST(test_proppatch_parse) { 595 Session *sn = testutil_session(); 596 Request *rq = testutil_request(sn->pool, "PROPPATCH", "/"); 597 598 UCX_TEST_BEGIN 599 int error = 0; 600 601 WebdavProppatchRequest *p1 = proppatch_parse(sn, rq, TEST_PROPPATCH1, strlen(TEST_PROPPATCH1), &error); 602 603 UCX_TEST_ASSERT(p1->set, "p1: missing set props"); 604 UCX_TEST_ASSERT(!p1->remove, "p1: has remove props"); 605 UCX_TEST_ASSERT(p1->setcount == 2, "p1: wrong setcount"); 606 UCX_TEST_ASSERT(p1->set->next, "p1: set plist broken"); 607 UCX_TEST_ASSERT(!p1->set->next->next, "p1: set plist has no end"); 608 UCX_TEST_ASSERT(p1->set->property, "p1: missing property ptr in plist"); 609 UCX_TEST_ASSERT( 610 !strcmp(p1->set->property->name, "test"), 611 "p1: wrong property 1 name"); 612 613 WebdavProppatchRequest *p2 = proppatch_parse(sn, rq, TEST_PROPPATCH2, strlen(TEST_PROPPATCH2), &error); 614 615 UCX_TEST_ASSERT(p2->set, "p2: missing set props"); 616 UCX_TEST_ASSERT(p2->remove, "p2: missing remove props"); 617 UCX_TEST_ASSERT(p2->setcount == 4, "p2: wrong setcount"); 618 UCX_TEST_ASSERT(p2->removecount == 1, "p2: wrong removecount"); 619 620 UCX_TEST_ASSERT( 621 !strcmp((char*)p2->set->property->namespace->href, "http://example.com/"), 622 "p2: set property 1: wrong namespace"); 623 UCX_TEST_ASSERT( 624 !strcmp(p2->set->property->name, "a"), 625 "p2: set property 1: wrong name"); 626 WSXmlNode *p2set1 = p2->set->property->value.node; 627 UCX_TEST_ASSERT( 628 p2set1->type == WS_NODE_TEXT, 629 "p2: set property 1: wrong type"); 630 UCX_TEST_ASSERT( 631 p2set1->content, 632 "p2: set property 1: no text"); 633 UCX_TEST_ASSERT( 634 !strcmp((char*)p2set1->content, "test"), 635 "p2: set property 1: wrong value"); 636 637 WSXmlNode *p2set3 = p2->set->next->next->property->value.node; 638 UCX_TEST_ASSERT(p2set3, "p2: set property 3 missing"); 639 UCX_TEST_ASSERT( 640 p2set3->type == WS_NODE_TEXT, 641 "p2: set property 3: wrong type"); 642 UCX_TEST_ASSERT( 643 p2set3->next, 644 "p2: set property 3: missing element X:name"); 645 646 UCX_TEST_ASSERT( 647 xmlHasProp(p2set3->next, "test"BAD_CAST), 648 "p2: set property 3: missing attribute ''test''"); 649 650 UCX_TEST_ASSERT( 651 xmlHasProp(p2set3->next, "abc"BAD_CAST), 652 "p2: set property 3: missing attribute ''abc"); 653 654 xmlChar *value1 = xmlGetProp(p2set3->next, "test"BAD_CAST); 655 UCX_TEST_ASSERT( 656 !strcmp((char*) value1, "test1"), 657 "p2: set property 3: wrong attribute value 1"); 658 xmlFree(value1); 659 660 xmlChar *value2 = xmlGetProp(p2set3->next, "abc"BAD_CAST); 661 UCX_TEST_ASSERT( 662 !strcmp((char*) value2, "def"), 663 "p2: set property 3: wrong attribute value 2"); 664 xmlFree(value2); 665 666 UCX_TEST_ASSERT( 667 !strcmp(p2->remove->property->name, "e"), 668 "p2: wrong remove property"); 669 670 UCX_TEST_END 671 672 pool_destroy(sn->pool); 673 } 674 675 UCX_TEST(test_lock_parse) { 676 Session *sn = testutil_session(); 677 Request *rq = testutil_request(sn->pool, "LOCK", "/"); 678 679 UCX_TEST_BEGIN 680 int error = 0; 681 682 WebdavLockRequest *l1 = lock_parse(sn, rq, TEST_LOCK1, strlen(TEST_LOCK1), &error); 683 684 UCX_TEST_ASSERT(l1, "l1 is NULL"); 685 UCX_TEST_ASSERT(l1->type == WEBDAV_LOCK_WRITE, "l1: wrong type"); 686 UCX_TEST_ASSERT(l1->scope == WEBDAV_LOCK_SHARED, "l1: wrong scope"); 687 UCX_TEST_ASSERT(l1->owner, "l1: owner is NULL"); 688 UCX_TEST_ASSERT(!strcmp((char*)l1->owner->content, "User"), "l1: wrong owner"); 689 690 UCX_TEST_END 691 692 pool_destroy(sn->pool); 693 } 694 695 UCX_TEST(test_rqbody2buffer) { 696 Session *sn; 697 Request *rq; 698 699 UCX_TEST_BEGIN; 700 // 701 // TEST 1 702 sn = testutil_session(); 703 rq = testutil_request(sn->pool, "PUT", "/"); 704 testutil_request_body(sn, rq, "Hello World!", 12); 705 706 CxBuffer b1; 707 rqbody2buffer(sn, rq, &b1); 708 UCX_TEST_ASSERT(b1.size == 12, "b1: wrong size"); 709 UCX_TEST_ASSERT(!memcmp(b1.space,"Hello World!",12), "b1: wrong content"); 710 711 cxBufferDestroy(&b1); 712 testutil_destroy_session(sn); 713 714 // 715 // TEST 2 716 size_t len1 = 25000; 717 unsigned char *body1 = malloc(len1); 718 for(int i=0;i<len1;i++) { 719 body1[i] = i; 720 } 721 sn = testutil_session(); 722 rq = testutil_request(sn->pool, "PUT", "/"); 723 testutil_request_body(sn, rq, (char*)body1, len1); 724 725 CxBuffer b2; 726 rqbody2buffer(sn, rq, &b2); 727 UCX_TEST_ASSERT(b2.size == len1, "b2: wrong size"); 728 UCX_TEST_ASSERT(!memcmp(b2.space, body1, len1), "b2: wrong content"); 729 730 cxBufferDestroy(&b2); 731 testutil_destroy_session(sn); 732 733 UCX_TEST_END; 734 } 735 736 UCX_TEST(test_webdav_plist_iterator) { 737 Session *sn; 738 Request *rq; 739 WebdavPropfindRequest *propfind; 740 741 UCX_TEST_BEGIN; 742 UCX_TEST_ASSERT(!test_init(&sn, &rq, &propfind, TEST_PROPFIND1), "init failed"); 743 744 WebdavPList *properties = propfind->properties; 745 size_t count = 0; 746 747 WebdavPListIterator i = webdav_plist_iterator(&properties); 748 WebdavPList *cur; 749 while(webdav_plist_iterator_next(&i, &cur)) { 750 switch(i.index) { 751 case 0: { 752 UCX_TEST_ASSERT(!strcmp(cur->property->name, "displayname"), "wrong property 1"); 753 break; 754 } 755 case 1: { 756 UCX_TEST_ASSERT(!strcmp(cur->property->name, "getcontentlength"), "wrong property 2"); 757 break; 758 } 759 case 2: { 760 UCX_TEST_ASSERT(!strcmp(cur->property->name, "getcontenttype"), "wrong property 3"); 761 break; 762 } 763 case 3: { 764 UCX_TEST_ASSERT(!strcmp(cur->property->name, "getlastmodified"), "wrong property 4"); 765 break; 766 } 767 case 4: { 768 UCX_TEST_ASSERT(!strcmp(cur->property->name, "resourcetype"), "wrong property 5"); 769 break; 770 } 771 case 5: { 772 UCX_TEST_ASSERT(!strcmp(cur->property->name, "getetag"), "wrong property 6"); 773 break; 774 } 775 } 776 count++; 777 } 778 779 UCX_TEST_ASSERT(count == propfind->propcount, "wrong count"); 780 781 782 UCX_TEST_END; 783 testutil_destroy_session(sn); 784 } 785 786 UCX_TEST(test_webdav_plist_iterator_remove_current) { 787 Session *sn; 788 Request *rq; 789 WebdavPropfindRequest *propfind; 790 791 UCX_TEST_BEGIN; 792 UCX_TEST_ASSERT(!test_init(&sn, &rq, &propfind, TEST_PROPFIND1), "init failed"); 793 794 WebdavPList *properties1 = webdav_plist_clone(sn->pool, propfind->properties); 795 WebdavPList *properties2 = webdav_plist_clone(sn->pool, propfind->properties); 796 WebdavPList *properties3 = webdav_plist_clone(sn->pool, propfind->properties); 797 WebdavPList *properties4 = webdav_plist_clone(sn->pool, propfind->properties); 798 799 WebdavPListIterator i; 800 WebdavPList *cur; 801 802 // test removal of first element 803 i = webdav_plist_iterator(&properties1); 804 while(webdav_plist_iterator_next(&i, &cur)) { 805 if(i.index == 0) { 806 webdav_plist_iterator_remove_current(&i); 807 } 808 } 809 810 UCX_TEST_ASSERT(!properties1->prev, "test1: prev not cleared"); 811 UCX_TEST_ASSERT(!strcmp(properties1->property->name, "getcontentlength"), "test1: wrong property"); 812 UCX_TEST_ASSERT(!strcmp(properties1->next->property->name, "getcontenttype"), "test1: wrong property 2"); 813 UCX_TEST_ASSERT(properties1->next->prev == properties1, "test1: wrong link"); 814 815 // test removal of second element 816 i = webdav_plist_iterator(&properties2); 817 while(webdav_plist_iterator_next(&i, &cur)) { 818 if(i.index == 1) { 819 webdav_plist_iterator_remove_current(&i); 820 } 821 } 822 823 UCX_TEST_ASSERT(!strcmp(properties2->next->property->name, "getcontenttype"), "test2: wrong property"); 824 UCX_TEST_ASSERT(properties2->next->prev == properties2, "test2: wrong link"); 825 UCX_TEST_ASSERT(webdav_plist_size(properties2) == 5, "test2: wrong size"); 826 827 // remove last element 828 i = webdav_plist_iterator(&properties3); 829 while(webdav_plist_iterator_next(&i, &cur)) { 830 if(i.index == 5) { 831 webdav_plist_iterator_remove_current(&i); 832 } 833 } 834 835 UCX_TEST_ASSERT(webdav_plist_size(properties3) == 5, "test3: wrong size"); 836 UCX_TEST_ASSERT(!strcmp(properties3->next->next->next->next->property->name, "resourcetype"), "test2: wrong property"); 837 838 // remove all elements 839 i = webdav_plist_iterator(&properties4); 840 while(webdav_plist_iterator_next(&i, &cur)) { 841 webdav_plist_iterator_remove_current(&i); 842 switch(i.index) { 843 case 0: { 844 UCX_TEST_ASSERT(!strcmp(properties4->property->name, "getcontentlength"), "test4: wrong property 2"); 845 UCX_TEST_ASSERT(properties4->prev == NULL, "test4: prev not NULL (0)"); 846 break; 847 } 848 case 1: { 849 UCX_TEST_ASSERT(!strcmp(properties4->property->name, "getcontenttype"), "test4: wrong property 3"); 850 UCX_TEST_ASSERT(properties4->prev == NULL, "test4: prev not NULL (1)"); 851 break; 852 } 853 case 2: { 854 UCX_TEST_ASSERT(!strcmp(properties4->property->name, "getlastmodified"), "test4: wrong property 4"); 855 UCX_TEST_ASSERT(properties4->prev == NULL, "test4: prev not NULL (2)"); 856 break; 857 } 858 case 3: { 859 UCX_TEST_ASSERT(!strcmp(properties4->property->name, "resourcetype"), "test4: wrong property 5"); 860 UCX_TEST_ASSERT(properties4->prev == NULL, "test4: prev not NULL (3)"); 861 break; 862 } 863 case 4: { 864 UCX_TEST_ASSERT(!strcmp(properties4->property->name, "getetag"), "test4: wrong property 6"); 865 UCX_TEST_ASSERT(properties4->prev == NULL, "test4: prev not NULL (4)"); 866 break; 867 } 868 default: { 869 UCX_TEST_ASSERT(i.index <= 5, "fail"); 870 } 871 } 872 } 873 874 UCX_TEST_ASSERT(properties4 == NULL, "test4: list not NULL"); 875 876 UCX_TEST_END; 877 testutil_destroy_session(sn); 878 } 879 880 UCX_TEST(test_msresponse_addproperty) { 881 Session *sn; 882 Request *rq; 883 884 UCX_TEST_BEGIN; 885 886 WebdavOperation *op = test_propfind_op(&sn, &rq, TEST_PROPFIND1); 887 UCX_TEST_ASSERT(op, "init failed"); 888 UCX_TEST_ASSERT(op->response, "no response"); 889 890 Multistatus *ms = (Multistatus*)op->response; 891 MSResponse *r = (MSResponse*)ms->response.addresource((WebdavResponse*)ms, "/"); 892 893 WebdavProperty p1; 894 WebdavProperty p[16]; 895 const char *names[] = {"a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9"}; 896 897 WSNamespace ns1; 898 ZERO(&ns1, sizeof(WSNamespace)); 899 WSNamespace ns2; 900 ZERO(&ns2, sizeof(WSNamespace)); 901 ns1.prefix = (xmlChar*)"x1"; 902 ns1.href = (xmlChar*)"http://example.com/test/"; 903 ns2.prefix = (xmlChar*)"x2"; 904 ns2.href = (xmlChar*)"http://example.com/test/"; 905 906 WebdavProperty dp1; 907 ZERO(&dp1, sizeof(WebdavProperty)); 908 dp1.name = "dup"; 909 dp1.namespace = &ns1; 910 dp1.value.text.str = "Hello"; 911 dp1.value.text.length = 5; 912 dp1.vtype = WS_VALUE_TEXT; 913 914 WebdavProperty dp2; 915 ZERO(&dp2, sizeof(WebdavProperty)); 916 dp2.name = "dup"; 917 dp2.namespace = &ns1; 918 dp2.value.text.str = "Hello"; 919 dp2.value.text.length = 5; 920 dp2.vtype = WS_VALUE_TEXT; 921 922 WebdavProperty dp3; 923 ZERO(&dp3, sizeof(WebdavProperty)); 924 dp3.name = "dup"; 925 dp3.namespace = &ns2; 926 dp3.value.text.str = "Hello"; 927 dp3.value.text.length = 5; 928 dp3.vtype = WS_VALUE_TEXT; 929 930 // init test data 931 p1.namespace = webdav_dav_namespace(); 932 p1.lang = NULL; 933 p1.name = "test1"; 934 p1.value.data = (WSXmlData){ NULL, NULL, 0}; 935 p1.vtype = 0; 936 937 for(int i=0;i<8;i++) { 938 p[i].namespace = webdav_dav_namespace(); 939 p[i].name = names[i]; 940 p[i].lang = NULL; 941 p[i].value.node = NULL; 942 p[1].vtype = 0; 943 } 944 945 UCX_TEST_ASSERT(!r->plist_begin && !r->plist_end, "plist not empty"); 946 947 r->resource.addproperty((WebdavResource*)r, &p1, 200); 948 UCX_TEST_ASSERT(r->plist_begin, "!plist_begin"); 949 UCX_TEST_ASSERT(r->plist_begin == r->plist_end, "plist begin != end"); 950 951 r->resource.addproperty((WebdavResource*)r, &p[0], 404); 952 r->resource.addproperty((WebdavResource*)r, &p[1], 404); 953 r->resource.addproperty((WebdavResource*)r, &p[2], 403); 954 r->resource.addproperty((WebdavResource*)r, &p[3], 403); 955 r->resource.addproperty((WebdavResource*)r, &p[4], 403); 956 r->resource.addproperty((WebdavResource*)r, &p[5], 403); 957 r->resource.addproperty((WebdavResource*)r, &p[6], 500); 958 959 UCX_TEST_ASSERT(r->plist_begin == r->plist_end, "plist begin != end"); 960 961 UCX_TEST_ASSERT(r->errors, "no prop errors"); 962 UCX_TEST_ASSERT(r->errors->next, "no second error code"); 963 UCX_TEST_ASSERT(r->errors->next->next, "no third error code"); 964 UCX_TEST_ASSERT(!r->errors->next->next->next, "too many error codes"); 965 966 UCX_TEST_ASSERT(webdav_plist_size(r->errors->begin) == 2, "404 list size != 2"); 967 UCX_TEST_ASSERT(webdav_plist_size(r->errors->next->begin) == 4, "403 list size != 4"); 968 UCX_TEST_ASSERT(webdav_plist_size(r->errors->next->next->begin) == 1, "500 list size != 1"); 969 970 // new resource for prop duplication tests 971 r = (MSResponse*)ms->response.addresource((WebdavResponse*)ms, "/test"); 972 UCX_TEST_ASSERT(r, "cannot create second response"); 973 974 r->resource.addproperty((WebdavResource*)r, &dp1, 200); 975 UCX_TEST_ASSERT(r->plist_begin, "adding dp1 failed"); 976 UCX_TEST_ASSERT(!r->plist_begin->next, "dp1: list size not 1"); 977 978 r->resource.addproperty((WebdavResource*)r, &dp2, 200); 979 UCX_TEST_ASSERT(!r->plist_begin->next, "dp1: adding dp2 should not work"); 980 981 r->resource.addproperty((WebdavResource*)r, &dp2, 404); 982 UCX_TEST_ASSERT(!r->plist_begin->next, "dp1: adding dp2 with different status should not work (1)"); 983 if(r->errors) { 984 UCX_TEST_ASSERT(webdav_plist_size(r->errors->begin) == 0, "dp1: error list not empty"); 985 } 986 987 r->resource.addproperty((WebdavResource*)r, &dp3, 200); 988 UCX_TEST_ASSERT(!r->plist_begin->next, "dp1: adding dp3 should not work"); 989 990 UCX_TEST_END; 991 } 992 993 UCX_TEST(test_webdav_propfind_init) { 994 reset_backends(); 995 996 Session *sn; 997 Request *rq; 998 WebdavPropfindRequest *propfind; 999 UCX_TEST_BEGIN; 1000 UCX_TEST_ASSERT(!test_init(&sn, &rq, &propfind, TEST_PROPFIND1), "init failed"); 1001 1002 WebdavPropfindRequestList *requests = NULL; 1003 int err = webdav_propfind_init(&backend1, propfind, "/", "/", &requests); 1004 1005 UCX_TEST_ASSERT(!err, "webdav_propfind_init failed"); 1006 UCX_TEST_ASSERT(requests, "request list is empty"); 1007 UCX_TEST_ASSERT(cx_linked_list_size(requests, offsetof(WebdavPropfindRequestList, next)), "request list has wrong size"); 1008 1009 WebdavPropfindRequest *p1 = requests->propfind; 1010 WebdavPropfindRequest *p2 = requests->next->propfind; 1011 1012 // backend1 removes the first property from the plist 1013 // backend2 should have one property less 1014 1015 UCX_TEST_ASSERT(p1 && p2, "missing requests objects"); 1016 UCX_TEST_ASSERT(p1 != p2, "request objects equal"); 1017 UCX_TEST_ASSERT(p1->properties != p2->properties, "plists equal"); 1018 UCX_TEST_ASSERT(p1->propcount == p2->propcount + 1, "first property not removed"); 1019 1020 UCX_TEST_ASSERT(backend1_init_called == 1, "backend1 init not called"); 1021 UCX_TEST_ASSERT(backend2_init_called == 1, "backend2 init not called"); 1022 1023 UCX_TEST_END; 1024 1025 pool_destroy(sn->pool); 1026 } 1027 1028 UCX_TEST(test_webdav_op_propfind_begin) { 1029 reset_backends(); 1030 1031 Session *sn; 1032 Request *rq; 1033 1034 UCX_TEST_BEGIN; 1035 WebdavOperation *op = test_propfind_op(&sn, &rq, TEST_PROPFIND1); 1036 UCX_TEST_ASSERT(op, "WebdavOperation not created"); 1037 1038 int err = webdav_op_propfind_begin(op, "/", NULL, NULL); 1039 UCX_TEST_ASSERT(err == 0, "err not 0"); 1040 UCX_TEST_ASSERT(backend1_propfind_do_count == 1, "backend1 propfind_do not called"); 1041 UCX_TEST_ASSERT(backend2_propfind_do_count == 1, "backend2 propfind_do not called"); 1042 1043 1044 UCX_TEST_END; 1045 testutil_destroy_session(sn); 1046 } 1047 1048 UCX_TEST(test_webdav_op_propfind_children) { 1049 reset_backends(); 1050 1051 Session *sn; 1052 Request *rq; 1053 1054 UCX_TEST_BEGIN; 1055 WebdavOperation *op = test_propfind_op(&sn, &rq, TEST_PROPFIND1); 1056 UCX_TEST_ASSERT(op, "WebdavOperation not created"); 1057 1058 int err = webdav_op_propfind_begin(op, "/", NULL, NULL); 1059 UCX_TEST_ASSERT(err == 0, "propfind_begin error"); 1060 1061 // create test vfs with some files (code from test_vfs_readdir) 1062 rq->vfs = testvfs_create(sn); 1063 VFSContext *vfs = vfs_request_context(sn, rq); 1064 UCX_TEST_ASSERT(vfs, "no vfs"); 1065 1066 err = vfs_mkdir(vfs, "/dir"); 1067 UCX_TEST_ASSERT(err == 0, "error not 0"); 1068 1069 // add some test file to /dir 1070 UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file1", O_CREAT), "creation of file1 failed"); 1071 UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file2", O_CREAT), "creation of file2 failed"); 1072 UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file3", O_CREAT), "creation of file3 failed"); 1073 UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file4", O_CREAT), "creation of file4 failed"); 1074 1075 VFSDir *dir = vfs_opendir(vfs, "/dir"); 1076 UCX_TEST_ASSERT(dir, "dir not opened"); 1077 1078 UCX_TEST_ASSERT(backend1_propfind_do_count == 1, "backend1 propfind_do not called"); 1079 UCX_TEST_ASSERT(backend2_propfind_do_count == 1, "backend1 propfind_do not called") 1080 1081 // propfind for all children 1082 err = webdav_op_propfind_children(op, vfs, "/", "/dir"); 1083 UCX_TEST_ASSERT(err == 0, "webdav_op_propfind_children failed"); 1084 1085 // 1 dir + 4 children 1086 UCX_TEST_ASSERT(backend1_propfind_do_count == 5, "backend1 propfind_do wrong count"); 1087 UCX_TEST_ASSERT(backend2_propfind_do_count == 5, "backend2 propfind_do wrong count"); 1088 1089 UCX_TEST_END; 1090 testutil_destroy_session(sn); 1091 } 1092 1093 void init_test_webdav_method( 1094 Session **out_sn, 1095 Request **out_rq, 1096 TestIOStream **out_st, 1097 pblock **out_pb, 1098 const char *method, 1099 const char *path, 1100 const char *request_body) 1101 { 1102 Session *sn; 1103 Request *rq; 1104 TestIOStream *st; 1105 pblock *pb; 1106 1107 sn = testutil_session(); 1108 rq = testutil_request(sn->pool, method, "/"); 1109 1110 pblock_nvinsert("path", path, rq->vars); 1111 pblock_nvinsert("uri", path, rq->reqpb); 1112 1113 st = testutil_iostream(2048, TRUE); 1114 sn->csd = (IOStream*)st; 1115 1116 if(request_body) { 1117 testutil_request_body(sn, rq, request_body, strlen(request_body)); 1118 } 1119 1120 pb = pblock_create_pool(sn->pool, 4); 1121 1122 *out_sn = sn; 1123 *out_rq = rq; 1124 *out_st = st; 1125 *out_pb = pb; 1126 } 1127 1128 UCX_TEST(test_webdav_propfind) { 1129 Session *sn; 1130 Request *rq; 1131 TestIOStream *st; 1132 pblock *pb; 1133 1134 UCX_TEST_BEGIN; 1135 1136 int ret; 1137 // Test 1 1138 init_test_webdav_method(&sn, &rq, &st, &pb, "PROPFIND", "/", TEST_PROPFIND1); 1139 1140 ret = webdav_propfind(pb, sn, rq); 1141 1142 UCX_TEST_ASSERT(ret == REQ_PROCEED, "webdav_propfind (1) failed"); 1143 1144 xmlDoc *doc = xmlReadMemory( 1145 st->buf->space, st->buf->size, NULL, NULL, 0); 1146 UCX_TEST_ASSERT(doc, "propfind1: response is not valid xml"); 1147 1148 //printf("\n\n%.*s\n", (int)st->buf->size, st->buf->space); 1149 1150 testutil_destroy_session(sn); 1151 xmlFreeDoc(doc); 1152 testutil_iostream_destroy(st); 1153 1154 // Test2 1155 init_test_webdav_method(&sn, &rq, &st, &pb, "PROPFIND", "/", TEST_PROPFIND2); 1156 1157 ret = webdav_propfind(pb, sn, rq); 1158 1159 UCX_TEST_ASSERT(ret == REQ_PROCEED, "webdav_propfind (2) failed"); 1160 1161 xmlDoc *doc2 = xmlReadMemory( 1162 st->buf->space, st->buf->size, NULL, NULL, 0); 1163 UCX_TEST_ASSERT(doc, "propfind2: response is not valid xml"); 1164 1165 //printf("\n\n%.*s\n", (int)st->buf->size, st->buf->space); 1166 1167 testutil_destroy_session(sn); 1168 xmlFreeDoc(doc2); 1169 testutil_iostream_destroy(st); 1170 1171 UCX_TEST_END; 1172 1173 } 1174 1175 /* ------------------------------------------------------------------------- 1176 * 1177 * PROPPATCH TESTS 1178 * 1179 * ------------------------------------------------------------------------ */ 1180 1181 static int test_proppatch_init( 1182 Session **out_sn, 1183 Request **out_rq, 1184 WebdavProppatchRequest **out_proppatch, 1185 const char *xml) 1186 { 1187 if(!webdav_is_initialized) { 1188 if(webdav_init(NULL, NULL, NULL) != REQ_PROCEED) { 1189 return 1; 1190 } 1191 webdav_is_initialized = 1; 1192 } 1193 1194 Session *sn = testutil_session(); 1195 Request *rq = testutil_request(sn->pool, "PROPPATCH", "/"); 1196 1197 int error = 0; 1198 1199 WebdavProppatchRequest *proppatch = proppatch_parse( 1200 sn, 1201 rq, 1202 xml, 1203 strlen(xml), 1204 &error); 1205 1206 if(error) { 1207 return 1; 1208 } 1209 1210 if(!proppatch || !(proppatch->set || proppatch->remove)) { 1211 return 1; 1212 } 1213 1214 *out_sn = sn; 1215 *out_rq = rq; 1216 *out_proppatch = proppatch; 1217 return 0; 1218 } 1219 1220 static WebdavOperation* test_proppatch_op1( 1221 Session **out_sn, 1222 Request **out_rq, 1223 const char *xml) 1224 { 1225 WebdavProppatchRequest *proppatch; 1226 if(test_proppatch_init(out_sn, out_rq, &proppatch, xml)) { 1227 return NULL; 1228 } 1229 1230 Multistatus *ms = multistatus_response(*out_sn, *out_rq); 1231 if(!ms) { 1232 return NULL; 1233 } 1234 // WebdavResponse is the public interface used by Backends 1235 // for adding resources to the response 1236 WebdavResponse *response = (WebdavResponse*)ms; 1237 1238 return webdav_create_proppatch_operation( 1239 (*out_sn), 1240 (*out_rq), 1241 &backend1, 1242 proppatch, 1243 response); 1244 } 1245 1246 1247 UCX_TEST(test_proppatch_msresponse) { 1248 Session *sn; 1249 Request *rq; 1250 WebdavOperation *op; 1251 1252 Multistatus *ms; 1253 WebdavResource *res; 1254 1255 WebdavProperty p[16]; 1256 const char *names[] = {"a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9"}; 1257 for(int i=0;i<8;i++) { 1258 p[i].namespace = webdav_dav_namespace(); 1259 p[i].name = names[i]; 1260 p[i].lang = NULL; 1261 p[i].value.node = NULL; 1262 p[i].vtype = 0; 1263 } 1264 1265 UCX_TEST_BEGIN; 1266 1267 op = test_proppatch_op1(&sn, &rq, TEST_PROPPATCH2); 1268 UCX_TEST_ASSERT(op, "failed to create proppatch operation"); 1269 1270 ms = (Multistatus*)op->response; 1271 ms->proppatch = TRUE; 1272 res = ms->response.addresource(&ms->response, "/"); 1273 UCX_TEST_ASSERT(res, "cannot create resource 1"); 1274 1275 UCX_TEST_ASSERT(!res->addproperty(res, &p[0], 200), "addproperty 1 failed"); 1276 UCX_TEST_ASSERT(!res->addproperty(res, &p[1], 200), "addproperty 2 failed"); 1277 UCX_TEST_ASSERT(!res->addproperty(res, &p[2], 200), "addproperty 3 failed"); 1278 UCX_TEST_ASSERT(!res->addproperty(res, &p[3], 200), "addproperty 4 failed"); 1279 1280 UCX_TEST_ASSERT(!res->close(res), "close failed"); 1281 1282 MSResponse *msres = (MSResponse*)res; 1283 UCX_TEST_ASSERT(!msres->errors, "error list not NULL"); 1284 UCX_TEST_ASSERT(msres->plist_begin, "elm1 missing"); 1285 UCX_TEST_ASSERT(msres->plist_begin->next, "elm2 missing"); 1286 UCX_TEST_ASSERT(msres->plist_begin->next->next, "elm3 missing"); 1287 UCX_TEST_ASSERT(msres->plist_begin->next->next->next, "elm4 missing"); 1288 UCX_TEST_ASSERT(!msres->plist_begin->next->next->next->next, "count != 4"); 1289 1290 UCX_TEST_END; 1291 testutil_destroy_session(sn); 1292 } 1293 1294 UCX_TEST(test_msresponse_addproperty_with_errors) { 1295 Session *sn; 1296 Request *rq; 1297 WebdavOperation *op; 1298 1299 Multistatus *ms; 1300 WebdavResource *res; 1301 1302 WebdavProperty p[16]; 1303 const char *names[] = {"a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9"}; 1304 for(int i=0;i<8;i++) { 1305 p[i].namespace = webdav_dav_namespace(); 1306 p[i].name = names[i]; 1307 p[i].lang = NULL; 1308 p[i].value.node = NULL; 1309 p[i].vtype = 0; 1310 } 1311 1312 UCX_TEST_BEGIN; 1313 1314 op = test_proppatch_op1(&sn, &rq, TEST_PROPPATCH2); 1315 UCX_TEST_ASSERT(op, "failed to create proppatch operation"); 1316 1317 ms = (Multistatus*)op->response; 1318 ms->proppatch = TRUE; 1319 res = ms->response.addresource(&ms->response, "/"); 1320 UCX_TEST_ASSERT(res, "cannot create resource 1"); 1321 1322 UCX_TEST_ASSERT(!res->addproperty(res, &p[0], 200), "addproperty 1 failed"); 1323 UCX_TEST_ASSERT(!res->addproperty(res, &p[1], 200), "addproperty 2 failed"); 1324 UCX_TEST_ASSERT(!res->addproperty(res, &p[2], 409), "addproperty 3 failed"); 1325 UCX_TEST_ASSERT(!res->addproperty(res, &p[3], 200), "addproperty 4 failed"); 1326 1327 UCX_TEST_ASSERT(!res->close(res), "close failed"); 1328 1329 // all properties should have an error status code now 1330 // 1 x 409, 3 x 424 1331 1332 MSResponse *msres = (MSResponse*)res; 1333 1334 UCX_TEST_ASSERT(!msres->plist_begin, "plist not NULL"); 1335 UCX_TEST_ASSERT(msres->errors, "error list is NULL"); 1336 UCX_TEST_ASSERT(msres->errors->next, "second error list is missing"); 1337 UCX_TEST_ASSERT(!msres->errors->next->next, "wrong error list size"); 1338 1339 // We know that we have 2 error lists, one with status code 409 and 1340 // the other must have 409. However we don't enforce the order of the 1341 // error lists, therefore check both variants 1342 if(msres->errors->status == 409) { 1343 UCX_TEST_ASSERT(msres->errors->next->status == 424, "wrong status code in second err elm"); 1344 UCX_TEST_ASSERT(msres->errors->begin, "missing 409 property"); 1345 UCX_TEST_ASSERT(msres->errors->next->begin, "missing 424 properties"); 1346 } else { 1347 UCX_TEST_ASSERT(msres->errors->next->status == 409, "wrong status code in second err elm"); 1348 UCX_TEST_ASSERT(msres->errors->begin, "missing 424 properties"); 1349 UCX_TEST_ASSERT(msres->errors->next->begin, "missing 409 property"); 1350 } 1351 1352 UCX_TEST_END; 1353 testutil_destroy_session(sn); 1354 } 1355 1356 UCX_TEST(test_webdav_op_proppatch) { 1357 Session *sn; 1358 Request *rq; 1359 WebdavOperation *op; 1360 1361 Multistatus *ms; 1362 WebdavResource *res; 1363 1364 WebdavProperty p[16]; 1365 const char *names[] = {"a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9"}; 1366 for(int i=0;i<8;i++) { 1367 p[i].namespace = webdav_dav_namespace(); 1368 p[i].name = names[i]; 1369 p[i].lang = NULL; 1370 p[i].value.node = NULL; 1371 p[1].vtype = 0; 1372 } 1373 1374 UCX_TEST_BEGIN; 1375 1376 // TEST_PROPPATCH2 should succeed 1377 reset_backends(); 1378 op = test_proppatch_op1(&sn, &rq, TEST_PROPPATCH2); 1379 UCX_TEST_ASSERT(op, "failed to create proppatch operation"); 1380 1381 int ret = webdav_op_proppatch(op, "/", "/"); 1382 UCX_TEST_ASSERT(ret == 0, "webdav_op_proppatch failed"); 1383 UCX_TEST_ASSERT(backend1_proppatch_commit, "backend1 no commit"); 1384 UCX_TEST_ASSERT(backend2_proppatch_commit, "backend2 no commit"); 1385 UCX_TEST_ASSERT(backend1_proppatch_do_count == 1, "backend1 wrong count (1)"); 1386 UCX_TEST_ASSERT(backend2_proppatch_do_count == 1, "backend1 wrong count (1)"); 1387 UCX_TEST_ASSERT(backend1_proppatch_finish_count == 1, "backend1 wrong finish count (1)"); 1388 UCX_TEST_ASSERT(backend2_proppatch_finish_count == 1, "backend1 wrong finish count (1)"); 1389 1390 // TEST_PROPPATCH3 should fail (commit == FALSE) 1391 reset_backends(); 1392 op = test_proppatch_op1(&sn, &rq, TEST_PROPPATCH3); 1393 UCX_TEST_ASSERT(op, "failed to create proppatch operation 2"); 1394 1395 ret = webdav_op_proppatch(op, "/", "/"); 1396 UCX_TEST_ASSERT(ret == 0, "webdav_op_proppatch failed (2)"); 1397 UCX_TEST_ASSERT(!backend1_proppatch_commit, "backend1 commit"); 1398 UCX_TEST_ASSERT(!backend2_proppatch_commit, "backend2 commit"); 1399 1400 // TEST_PROPPATCH4 should abort 1401 reset_backends(); 1402 op = test_proppatch_op1(&sn, &rq, TEST_PROPPATCH4); 1403 UCX_TEST_ASSERT(op, "failed to create proppatch operation 3"); 1404 1405 ret = webdav_op_proppatch(op, "/", "/"); 1406 UCX_TEST_ASSERT(ret != 0, "webdav_op_proppatch should fail"); 1407 UCX_TEST_ASSERT(backend1_proppatch_do_count == 1, "backend1 wrong count (2)"); 1408 UCX_TEST_ASSERT(backend2_proppatch_do_count == 1, "backend1 wrong count (2)"); 1409 UCX_TEST_ASSERT(backend1_proppatch_finish_count == 1, "backend1 wrong finish count (2)"); 1410 UCX_TEST_ASSERT(backend2_proppatch_finish_count == 0, "backend1 wrong finish count (2)"); 1411 1412 UCX_TEST_END; 1413 testutil_destroy_session(sn); 1414 } 1415 1416 #define xstreq(a, b) (!strcmp((const char*)a, (const char*)b)) 1417 1418 UCX_TEST(test_webdav_proppatch) { 1419 Session *sn; 1420 Request *rq; 1421 TestIOStream *st; 1422 pblock *pb; 1423 1424 UCX_TEST_BEGIN; 1425 1426 int ret; 1427 // Test 1 1428 init_test_webdav_method(&sn, &rq, &st, &pb, "PROPPATCH", "/", TEST_PROPPATCH2); 1429 rq->davCollection = &backend1; 1430 ret = webdav_proppatch(pb, sn, rq); 1431 1432 UCX_TEST_ASSERT(ret == REQ_PROCEED, "webdav_proppatch (1) failed"); 1433 1434 xmlDoc *doc = xmlReadMemory( 1435 st->buf->space, st->buf->size, NULL, NULL, 0); 1436 UCX_TEST_ASSERT(doc, "proppatch1: response is not valid xml"); 1437 1438 //printf("\n\n%.*s\n", (int)st->buf->size, st->buf->space); 1439 1440 xmlNode *root = xmlDocGetRootElement(doc); 1441 UCX_TEST_ASSERT(root, "proppatch1: no root"); 1442 1443 xmlNode *nodeC = NULL; 1444 xmlNode *node = root->children; 1445 int depth = 1; 1446 while(node) { 1447 const xmlChar *name = node->name; 1448 int nextNode = 1; 1449 if(node->type != XML_ELEMENT_NODE) { 1450 // nothing 1451 } else if(depth == 1) { 1452 if(xstreq(name, "response")) { 1453 nextNode = 0; 1454 } 1455 } else if(depth == 2) { 1456 if(xstreq(name, "propstat")) { 1457 nextNode = 0; 1458 } 1459 } else if(depth == 3) { 1460 if(xstreq(name, "prop")) { 1461 nextNode = 0; 1462 } 1463 } else if(depth == 4) { 1464 if(xstreq(name, "c")) { 1465 nodeC = node; 1466 break; 1467 } 1468 } 1469 1470 if(nextNode) { 1471 node = node->next; 1472 } else { 1473 node = node->children; 1474 depth++; 1475 } 1476 } 1477 1478 UCX_TEST_ASSERT(nodeC, "prop c not in response"); 1479 UCX_TEST_ASSERT(!nodeC->children, "properties must not have a value"); 1480 1481 testutil_destroy_session(sn); 1482 xmlFreeDoc(doc); 1483 testutil_iostream_destroy(st); 1484 1485 1486 UCX_TEST_END; 1487 } 1488 1489 1490 /* ------------------------------------------------------------------------- 1491 * 1492 * WEBDAV VFS TESTS 1493 * 1494 * ------------------------------------------------------------------------ */ 1495 1496 static int mkcol_data1 = 10; 1497 static int mkcol_data2 = 20; 1498 static int mkcol_data3 = 30; 1499 static int mkcol_data4 = 40; 1500 1501 static int mkcol_count = 0; 1502 static int mkcol_finish_count = 0; 1503 1504 static int mkcol_err = 0; 1505 1506 static int set_created = 0; 1507 1508 static int test_webdav_mkcol(WebdavVFSRequest *req, WSBool *created) { 1509 mkcol_count++; 1510 1511 switch(mkcol_count) { 1512 case 1: { 1513 req->userdata = &mkcol_data1; 1514 break; 1515 } 1516 case 2: { 1517 req->userdata = &mkcol_data2; 1518 break; 1519 } 1520 case 3: { 1521 req->userdata = &mkcol_data3; 1522 break; 1523 } 1524 case 4: { 1525 req->userdata = &mkcol_data4; 1526 break; 1527 } 1528 default: break; 1529 } 1530 1531 if(set_created) { 1532 *created = TRUE; 1533 set_created = 0; 1534 } 1535 1536 return 0; 1537 } 1538 1539 static int test_webdav_mkcol_finish(WebdavVFSRequest *req, WSBool success) { 1540 mkcol_finish_count++; 1541 1542 if(mkcol_finish_count == 1) { 1543 int *data = req->userdata; 1544 if(data != &mkcol_data1) { 1545 mkcol_err = 1; 1546 } 1547 } else if(mkcol_finish_count == 3) { 1548 int *data = req->userdata; 1549 if(data != &mkcol_data3) { 1550 mkcol_err = 1; 1551 } 1552 } else { 1553 int *data = req->userdata; 1554 // data4 should never be used 1555 if(data == &mkcol_data4) { 1556 mkcol_err = 1; 1557 } 1558 } 1559 1560 return 0; 1561 } 1562 1563 static int test_webdav_mkcol_fail(WebdavVFSRequest *req, WSBool *created) { 1564 mkcol_count++; 1565 return 1; 1566 } 1567 1568 static int delete_count = 0; 1569 static int delete_finish_count = 0; 1570 1571 static int test_backend_webdav_delete(WebdavVFSRequest *req, WSBool *created) { 1572 delete_count++; 1573 return 0; 1574 } 1575 1576 static int test_backend_webdav_delete_finish(WebdavVFSRequest *req, WSBool success) { 1577 delete_finish_count++; 1578 return 0; 1579 } 1580 1581 1582 UCX_TEST(test_webdav_vfs_op_do) { 1583 Session *sn; 1584 Request *rq; 1585 TestIOStream *st; 1586 pblock *pb; 1587 1588 // Tests performed primarily with MKCOL, because webdav_vfs_op_do 1589 // behaves the same for both operations 1590 // the only difference are the callbacks 1591 1592 init_test_webdav_method(&sn, &rq, &st, &pb, "MKCOL", "/", NULL); 1593 VFS *testvfs = testvfs_create(sn); 1594 rq->vfs = testvfs; 1595 1596 WebdavBackend dav1; 1597 ZERO(&dav1, sizeof(WebdavBackend)); 1598 dav1.opt_mkcol = test_webdav_mkcol; 1599 dav1.opt_mkcol_finish = test_webdav_mkcol_finish; 1600 dav1.opt_delete = test_backend_webdav_delete; 1601 dav1.opt_delete_finish = test_backend_webdav_delete_finish; 1602 1603 WebdavBackend dav2; 1604 ZERO(&dav2, sizeof(WebdavBackend)); 1605 dav2.opt_mkcol_finish = test_webdav_mkcol_finish; 1606 1607 WebdavBackend dav3; 1608 ZERO(&dav3, sizeof(WebdavBackend)); 1609 dav3.opt_mkcol = test_webdav_mkcol; 1610 1611 WebdavBackend dav4; 1612 ZERO(&dav4, sizeof(WebdavBackend)); 1613 dav4.opt_mkcol = test_webdav_mkcol; 1614 dav4.opt_mkcol_finish = test_webdav_mkcol_finish; 1615 1616 dav1.next = &dav2; 1617 dav2.next = &dav3; 1618 dav3.next = &dav4; 1619 1620 rq->davCollection = &dav1; 1621 1622 UCX_TEST_BEGIN; 1623 1624 WebdavVFSOperation *op1 = webdav_vfs_op(sn, rq, &dav1, FALSE); 1625 1626 int ret = webdav_vfs_op_do(op1, WEBDAV_VFS_MKDIR); 1627 1628 UCX_TEST_ASSERT(!ret, "webdav_vfs_op_do failed"); 1629 UCX_TEST_ASSERT(mkcol_count == 3, "wrong mkcol_count"); 1630 UCX_TEST_ASSERT(mkcol_finish_count == 3, "wrong mkcol_finish_count"); 1631 UCX_TEST_ASSERT(mkcol_err == 0, "mkcol_err"); 1632 1633 // test without VFS, but set *created to TRUE to skip VFS usage 1634 rq->vfs = NULL; 1635 set_created = 1; 1636 1637 WebdavVFSOperation *op2 = webdav_vfs_op(sn, rq, &dav1, FALSE); 1638 ret = webdav_vfs_op_do(op2, WEBDAV_VFS_MKDIR); 1639 1640 UCX_TEST_ASSERT(!ret, "op2 failed"); 1641 1642 // test 3: abort after first backend 1643 mkcol_count = 0; 1644 mkcol_finish_count = 0; 1645 dav1.opt_mkcol = test_webdav_mkcol_fail; 1646 1647 WebdavVFSOperation *op3 = webdav_vfs_op(sn, rq, &dav1, FALSE); 1648 ret = webdav_vfs_op_do(op3, WEBDAV_VFS_MKDIR); 1649 1650 UCX_TEST_ASSERT(ret, "op3 should fail"); 1651 UCX_TEST_ASSERT(mkcol_count == 1, "op3: wrong mkcol_count"); 1652 UCX_TEST_ASSERT(mkcol_finish_count == 1, "op3: wrong mkcol_finish_count"); 1653 1654 // test DELETE to make sure, delete callbacks will be used 1655 pblock_replace("path", "/deltest", rq->vars); 1656 rq->vfs = testvfs; 1657 WebdavVFSOperation *op_del = webdav_vfs_op(sn, rq, &dav1, FALSE); 1658 vfs_open(op_del->vfs, "/deltest", O_CREAT); 1659 ret = webdav_vfs_op_do(op_del, WEBDAV_VFS_DELETE); 1660 1661 UCX_TEST_ASSERT(!ret, "op_del failed"); 1662 UCX_TEST_ASSERT(delete_count == 1, "op_del: wrong delete_count"); 1663 UCX_TEST_ASSERT(delete_finish_count == 1, "op_del: wrong delete_finish_count"); 1664 1665 1666 UCX_TEST_END; 1667 } 1668 1669 UCX_TEST(test_webdav_delete){ 1670 Session *sn; 1671 Request *rq; 1672 TestIOStream *st; 1673 pblock *pb; 1674 1675 init_test_webdav_method(&sn, &rq, &st, &pb, "DELETE", "/", NULL); 1676 rq->vfs = testvfs_create(sn); 1677 1678 WebdavBackend dav1; 1679 ZERO(&dav1, sizeof(WebdavBackend)); 1680 dav1.opt_delete = test_backend_webdav_delete; 1681 dav1.opt_delete_finish = test_backend_webdav_delete_finish; 1682 delete_count = 0; 1683 delete_finish_count = 0; 1684 rq->davCollection = &dav1; 1685 1686 UCX_TEST_BEGIN; 1687 1688 // prepare 1689 VFSContext *vfs = vfs_request_context(sn, rq); 1690 int err; 1691 err = vfs_mkdir(vfs, "/dir1"); 1692 UCX_TEST_ASSERT(err == 0, "mkdir dir1 failed"); 1693 err = vfs_mkdir(vfs, "/dir2"); 1694 UCX_TEST_ASSERT(err == 0, "mkdir dir2 failed"); 1695 err = vfs_mkdir(vfs, "/dir2/dir3"); 1696 UCX_TEST_ASSERT(err == 0, "mkdir dir3 failed"); 1697 err = vfs_mkdir(vfs, "/dir2/dir4"); 1698 UCX_TEST_ASSERT(err == 0, "mkdir dir4 failed"); 1699 err = vfs_mkdir(vfs, "/dir2/dir4/dir5"); 1700 UCX_TEST_ASSERT(err == 0, "mkdir dir5 failed"); 1701 1702 SYS_FILE f0 = vfs_open(vfs, "/file0", O_CREAT); 1703 UCX_TEST_ASSERT(f0, "f0 create failed"); 1704 // no f1 1705 SYS_FILE f2 = vfs_open(vfs, "/dir2/file2", O_CREAT); 1706 UCX_TEST_ASSERT(f2, "f2 create failed"); 1707 SYS_FILE f3 = vfs_open(vfs, "/dir2/dir3/file3", O_CREAT); 1708 UCX_TEST_ASSERT(f3, "f3 create failed"); 1709 SYS_FILE f4 = vfs_open(vfs, "/dir2/dir4/file4", O_CREAT); 1710 UCX_TEST_ASSERT(f4, "f4 create failed"); 1711 SYS_FILE f5 = vfs_open(vfs, "/dir2/dir4/dir5/file5", O_CREAT); 1712 UCX_TEST_ASSERT(f5, "f5 create failed"); 1713 1714 // delete single file 1715 pblock_replace("path", "/file0", rq->vars); 1716 err = webdav_delete(NULL, sn, rq); 1717 UCX_TEST_ASSERT(err == 0, "DELETE /file0 failed"); 1718 UCX_TEST_ASSERT(delete_count == 1, "del1: wrong delete count"); 1719 1720 delete_count = 0; 1721 pblock_replace("path", "/dir1", rq->vars); 1722 err = webdav_delete(NULL, sn, rq); 1723 UCX_TEST_ASSERT(err == 0, "DELETE /dir1 failed"); 1724 UCX_TEST_ASSERT(delete_count == 1, "del1: wrong delete count"); 1725 1726 delete_count = 0; 1727 pblock_replace("path", "/dir2", rq->vars); 1728 err = webdav_delete(NULL, sn, rq); 1729 UCX_TEST_ASSERT(err == 0, "DELETE /dir2 failed"); 1730 UCX_TEST_ASSERT(delete_count == 8, "del2: wrong delete count"); 1731 1732 UCX_TEST_END; 1733 } 1734 1735 UCX_TEST(test_webdav_put) { 1736 Session *sn; 1737 Request *rq; 1738 TestIOStream *st; 1739 pblock *pb; 1740 1741 const char *content_const = "Hello World"; 1742 1743 init_test_webdav_method(&sn, &rq, &st, &pb, "PUT", "/", content_const); 1744 rq->vfs = testvfs_create(sn); 1745 1746 UCX_TEST_BEGIN; 1747 1748 int err; 1749 1750 pblock_replace("path", "/file0", rq->vars); 1751 err = webdav_put(NULL, sn, rq); 1752 1753 UCX_TEST_ASSERT(err == REQ_PROCEED, "put failed"); 1754 1755 VFSContext *vfs = vfs_request_context(sn, rq); 1756 SYS_FILE f0 = vfs_open(vfs, "/file0", 0); 1757 UCX_TEST_ASSERT(f0, "cannot open file0"); 1758 1759 char buf[1024]; 1760 int r = system_fread(f0, buf, 1024); 1761 1762 UCX_TEST_ASSERT(r == strlen(content_const), "wrong file size"); 1763 UCX_TEST_ASSERT(!memcmp(content_const, buf, r), "wrong file content"); 1764 1765 testutil_destroy_session(sn); 1766 testutil_iostream_destroy(st); 1767 1768 UCX_TEST_END; 1769 } 1770