src/server/test/webdav.c

changeset 385
a1f4cb076d2f
parent 376
61d481d3c2e4
child 415
d938228c382e
equal deleted inserted replaced
210:21274e5950af 385:a1f4cb076d2f
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 UcxList *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, BAD_CAST"test"),
648 "p2: set property 3: missing attribute 'test'");
649
650 UCX_TEST_ASSERT(
651 xmlHasProp(p2set3->next, BAD_CAST"abc"),
652 "p2: set property 3: missing attribute 'abc");
653
654 xmlChar *value1 = xmlGetProp(p2set3->next, BAD_CAST"test");
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, BAD_CAST"abc");
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 UcxBuffer *b1 = rqbody2buffer(sn, rq);
707 UCX_TEST_ASSERT(b1->size == 12, "b1: wrong size");
708 UCX_TEST_ASSERT(!memcmp(b1->space,"Hello World!",12), "b1: wrong content");
709
710 ucx_buffer_free(b1);
711 testutil_destroy_session(sn);
712
713 //
714 // TEST 2
715 size_t len1 = 25000;
716 unsigned char *body1 = malloc(len1);
717 for(int i=0;i<len1;i++) {
718 body1[i] = i;
719 }
720 sn = testutil_session();
721 rq = testutil_request(sn->pool, "PUT", "/");
722 testutil_request_body(sn, rq, (char*)body1, len1);
723
724 UcxBuffer *b2 = rqbody2buffer(sn, rq);
725 UCX_TEST_ASSERT(b2->size == len1, "b2: wrong size");
726 UCX_TEST_ASSERT(!memcmp(b2->space, body1, len1), "b2: wrong content");
727
728 ucx_buffer_free(b2);
729 testutil_destroy_session(sn);
730
731 UCX_TEST_END;
732 }
733
734 UCX_TEST(test_webdav_plist_iterator) {
735 Session *sn;
736 Request *rq;
737 WebdavPropfindRequest *propfind;
738
739 UCX_TEST_BEGIN;
740 UCX_TEST_ASSERT(!test_init(&sn, &rq, &propfind, TEST_PROPFIND1), "init failed");
741
742 WebdavPList *properties = propfind->properties;
743 size_t count = 0;
744
745 WebdavPListIterator i = webdav_plist_iterator(&properties);
746 WebdavPList *cur;
747 while(webdav_plist_iterator_next(&i, &cur)) {
748 switch(i.index) {
749 case 0: {
750 UCX_TEST_ASSERT(!strcmp(cur->property->name, "displayname"), "wrong property 1");
751 break;
752 }
753 case 1: {
754 UCX_TEST_ASSERT(!strcmp(cur->property->name, "getcontentlength"), "wrong property 2");
755 break;
756 }
757 case 2: {
758 UCX_TEST_ASSERT(!strcmp(cur->property->name, "getcontenttype"), "wrong property 3");
759 break;
760 }
761 case 3: {
762 UCX_TEST_ASSERT(!strcmp(cur->property->name, "getlastmodified"), "wrong property 4");
763 break;
764 }
765 case 4: {
766 UCX_TEST_ASSERT(!strcmp(cur->property->name, "resourcetype"), "wrong property 5");
767 break;
768 }
769 case 5: {
770 UCX_TEST_ASSERT(!strcmp(cur->property->name, "getetag"), "wrong property 6");
771 break;
772 }
773 }
774 count++;
775 }
776
777 UCX_TEST_ASSERT(count == propfind->propcount, "wrong count");
778
779
780 UCX_TEST_END;
781 testutil_destroy_session(sn);
782 }
783
784 UCX_TEST(test_webdav_plist_iterator_remove_current) {
785 Session *sn;
786 Request *rq;
787 WebdavPropfindRequest *propfind;
788
789 UCX_TEST_BEGIN;
790 UCX_TEST_ASSERT(!test_init(&sn, &rq, &propfind, TEST_PROPFIND1), "init failed");
791
792 WebdavPList *properties1 = webdav_plist_clone(sn->pool, propfind->properties);
793 WebdavPList *properties2 = webdav_plist_clone(sn->pool, propfind->properties);
794 WebdavPList *properties3 = webdav_plist_clone(sn->pool, propfind->properties);
795 WebdavPList *properties4 = webdav_plist_clone(sn->pool, propfind->properties);
796
797 WebdavPListIterator i;
798 WebdavPList *cur;
799
800 // test removal of first element
801 i = webdav_plist_iterator(&properties1);
802 while(webdav_plist_iterator_next(&i, &cur)) {
803 if(i.index == 0) {
804 webdav_plist_iterator_remove_current(&i);
805 }
806 }
807
808 UCX_TEST_ASSERT(!properties1->prev, "test1: prev not cleared");
809 UCX_TEST_ASSERT(!strcmp(properties1->property->name, "getcontentlength"), "test1: wrong property");
810 UCX_TEST_ASSERT(!strcmp(properties1->next->property->name, "getcontenttype"), "test1: wrong property 2");
811 UCX_TEST_ASSERT(properties1->next->prev == properties1, "test1: wrong link");
812
813 // test removal of second element
814 i = webdav_plist_iterator(&properties2);
815 while(webdav_plist_iterator_next(&i, &cur)) {
816 if(i.index == 1) {
817 webdav_plist_iterator_remove_current(&i);
818 }
819 }
820
821 UCX_TEST_ASSERT(!strcmp(properties2->next->property->name, "getcontenttype"), "test2: wrong property");
822 UCX_TEST_ASSERT(properties2->next->prev == properties2, "test2: wrong link");
823 UCX_TEST_ASSERT(webdav_plist_size(properties2) == 5, "test2: wrong size");
824
825 // remove last element
826 i = webdav_plist_iterator(&properties3);
827 while(webdav_plist_iterator_next(&i, &cur)) {
828 if(i.index == 5) {
829 webdav_plist_iterator_remove_current(&i);
830 }
831 }
832
833 UCX_TEST_ASSERT(webdav_plist_size(properties3) == 5, "test3: wrong size");
834 UCX_TEST_ASSERT(!strcmp(properties3->next->next->next->next->property->name, "resourcetype"), "test2: wrong property");
835
836 // remove all elements
837 i = webdav_plist_iterator(&properties4);
838 while(webdav_plist_iterator_next(&i, &cur)) {
839 webdav_plist_iterator_remove_current(&i);
840 switch(i.index) {
841 case 0: {
842 UCX_TEST_ASSERT(!strcmp(properties4->property->name, "getcontentlength"), "test4: wrong property 2");
843 UCX_TEST_ASSERT(properties4->prev == NULL, "test4: prev not NULL (0)");
844 break;
845 }
846 case 1: {
847 UCX_TEST_ASSERT(!strcmp(properties4->property->name, "getcontenttype"), "test4: wrong property 3");
848 UCX_TEST_ASSERT(properties4->prev == NULL, "test4: prev not NULL (1)");
849 break;
850 }
851 case 2: {
852 UCX_TEST_ASSERT(!strcmp(properties4->property->name, "getlastmodified"), "test4: wrong property 4");
853 UCX_TEST_ASSERT(properties4->prev == NULL, "test4: prev not NULL (2)");
854 break;
855 }
856 case 3: {
857 UCX_TEST_ASSERT(!strcmp(properties4->property->name, "resourcetype"), "test4: wrong property 5");
858 UCX_TEST_ASSERT(properties4->prev == NULL, "test4: prev not NULL (3)");
859 break;
860 }
861 case 4: {
862 UCX_TEST_ASSERT(!strcmp(properties4->property->name, "getetag"), "test4: wrong property 6");
863 UCX_TEST_ASSERT(properties4->prev == NULL, "test4: prev not NULL (4)");
864 break;
865 }
866 default: {
867 UCX_TEST_ASSERT(i.index <= 5, "fail");
868 }
869 }
870 }
871
872 UCX_TEST_ASSERT(properties4 == NULL, "test4: list not NULL");
873
874 UCX_TEST_END;
875 testutil_destroy_session(sn);
876 }
877
878 UCX_TEST(test_msresponse_addproperty) {
879 Session *sn;
880 Request *rq;
881
882 UCX_TEST_BEGIN;
883
884 WebdavOperation *op = test_propfind_op(&sn, &rq, TEST_PROPFIND1);
885 UCX_TEST_ASSERT(op, "init failed");
886 UCX_TEST_ASSERT(op->response, "no response");
887
888 Multistatus *ms = (Multistatus*)op->response;
889 MSResponse *r = (MSResponse*)ms->response.addresource((WebdavResponse*)ms, "/");
890
891 WebdavProperty p1;
892 WebdavProperty p[16];
893 const char *names[] = {"a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9"};
894
895 WSNamespace ns1;
896 ZERO(&ns1, sizeof(WSNamespace));
897 WSNamespace ns2;
898 ZERO(&ns2, sizeof(WSNamespace));
899 ns1.prefix = (xmlChar*)"x1";
900 ns1.href = (xmlChar*)"http://example.com/test/";
901 ns2.prefix = (xmlChar*)"x2";
902 ns2.href = (xmlChar*)"http://example.com/test/";
903
904 WebdavProperty dp1;
905 ZERO(&dp1, sizeof(WebdavProperty));
906 dp1.name = "dup";
907 dp1.namespace = &ns1;
908 dp1.value.text.str = "Hello";
909 dp1.value.text.length = 5;
910 dp1.vtype = WS_VALUE_TEXT;
911
912 WebdavProperty dp2;
913 ZERO(&dp2, sizeof(WebdavProperty));
914 dp2.name = "dup";
915 dp2.namespace = &ns1;
916 dp2.value.text.str = "Hello";
917 dp2.value.text.length = 5;
918 dp2.vtype = WS_VALUE_TEXT;
919
920 WebdavProperty dp3;
921 ZERO(&dp3, sizeof(WebdavProperty));
922 dp3.name = "dup";
923 dp3.namespace = &ns2;
924 dp3.value.text.str = "Hello";
925 dp3.value.text.length = 5;
926 dp3.vtype = WS_VALUE_TEXT;
927
928 // init test data
929 p1.namespace = webdav_dav_namespace();
930 p1.lang = NULL;
931 p1.name = "test1";
932 p1.value.data = (WSXmlData){ NULL, NULL, 0};
933 p1.vtype = 0;
934
935 for(int i=0;i<8;i++) {
936 p[i].namespace = webdav_dav_namespace();
937 p[i].name = names[i];
938 p[i].lang = NULL;
939 p[i].value.node = NULL;
940 p[1].vtype = 0;
941 }
942
943 UCX_TEST_ASSERT(!r->plist_begin && !r->plist_end, "plist not empty");
944
945 r->resource.addproperty((WebdavResource*)r, &p1, 200);
946 UCX_TEST_ASSERT(r->plist_begin, "!plist_begin");
947 UCX_TEST_ASSERT(r->plist_begin == r->plist_end, "plist begin != end");
948
949 r->resource.addproperty((WebdavResource*)r, &p[0], 404);
950 r->resource.addproperty((WebdavResource*)r, &p[1], 404);
951 r->resource.addproperty((WebdavResource*)r, &p[2], 403);
952 r->resource.addproperty((WebdavResource*)r, &p[3], 403);
953 r->resource.addproperty((WebdavResource*)r, &p[4], 403);
954 r->resource.addproperty((WebdavResource*)r, &p[5], 403);
955 r->resource.addproperty((WebdavResource*)r, &p[6], 500);
956
957 UCX_TEST_ASSERT(r->plist_begin == r->plist_end, "plist begin != end");
958
959 UCX_TEST_ASSERT(r->errors, "no prop errors");
960 UCX_TEST_ASSERT(r->errors->next, "no second error code");
961 UCX_TEST_ASSERT(r->errors->next->next, "no third error code");
962 UCX_TEST_ASSERT(!r->errors->next->next->next, "too many error codes");
963
964 UCX_TEST_ASSERT(webdav_plist_size(r->errors->begin) == 2, "404 list size != 2");
965 UCX_TEST_ASSERT(webdav_plist_size(r->errors->next->begin) == 4, "403 list size != 4");
966 UCX_TEST_ASSERT(webdav_plist_size(r->errors->next->next->begin) == 1, "500 list size != 1");
967
968 // new resource for prop duplication tests
969 r = (MSResponse*)ms->response.addresource((WebdavResponse*)ms, "/test");
970 UCX_TEST_ASSERT(r, "cannot create second response");
971
972 r->resource.addproperty((WebdavResource*)r, &dp1, 200);
973 UCX_TEST_ASSERT(r->plist_begin, "adding dp1 failed");
974 UCX_TEST_ASSERT(!r->plist_begin->next, "dp1: list size not 1");
975
976 r->resource.addproperty((WebdavResource*)r, &dp2, 200);
977 UCX_TEST_ASSERT(!r->plist_begin->next, "dp1: adding dp2 should not work");
978
979 r->resource.addproperty((WebdavResource*)r, &dp2, 404);
980 UCX_TEST_ASSERT(!r->plist_begin->next, "dp1: adding dp2 with different status should not work (1)");
981 if(r->errors) {
982 UCX_TEST_ASSERT(webdav_plist_size(r->errors->begin) == 0, "dp1: error list not empty");
983 }
984
985 r->resource.addproperty((WebdavResource*)r, &dp3, 200);
986 UCX_TEST_ASSERT(!r->plist_begin->next, "dp1: adding dp3 should not work");
987
988 UCX_TEST_END;
989 }
990
991 UCX_TEST(test_webdav_propfind_init) {
992 reset_backends();
993
994 Session *sn;
995 Request *rq;
996 WebdavPropfindRequest *propfind;
997 UCX_TEST_BEGIN;
998 UCX_TEST_ASSERT(!test_init(&sn, &rq, &propfind, TEST_PROPFIND1), "init failed");
999
1000 UcxList *requests = NULL;
1001 int err = webdav_propfind_init(&backend1, propfind, "/", "/", &requests);
1002
1003 UCX_TEST_ASSERT(!err, "webdav_propfind_init failed");
1004 UCX_TEST_ASSERT(requests, "request list is empty");
1005 UCX_TEST_ASSERT(ucx_list_size(requests), "request list has wrong size");
1006
1007 WebdavPropfindRequest *p1 = requests->data;
1008 WebdavPropfindRequest *p2 = requests->next->data;
1009
1010 // backend1 removes the first property from the plist
1011 // backend2 should have one property less
1012
1013 UCX_TEST_ASSERT(p1 && p2, "missing requests objects");
1014 UCX_TEST_ASSERT(p1 != p2, "request objects equal");
1015 UCX_TEST_ASSERT(p1->properties != p2->properties, "plists equal");
1016 UCX_TEST_ASSERT(p1->propcount == p2->propcount + 1, "first property not removed");
1017
1018 UCX_TEST_ASSERT(backend1_init_called == 1, "backend1 init not called");
1019 UCX_TEST_ASSERT(backend2_init_called == 1, "backend2 init not called");
1020
1021 UCX_TEST_END;
1022
1023 pool_destroy(sn->pool);
1024 }
1025
1026 UCX_TEST(test_webdav_op_propfind_begin) {
1027 reset_backends();
1028
1029 Session *sn;
1030 Request *rq;
1031
1032 UCX_TEST_BEGIN;
1033 WebdavOperation *op = test_propfind_op(&sn, &rq, TEST_PROPFIND1);
1034 UCX_TEST_ASSERT(op, "WebdavOperation not created");
1035
1036 int err = webdav_op_propfind_begin(op, "/", NULL, NULL);
1037 UCX_TEST_ASSERT(err == 0, "err not 0");
1038 UCX_TEST_ASSERT(backend1_propfind_do_count == 1, "backend1 propfind_do not called");
1039 UCX_TEST_ASSERT(backend2_propfind_do_count == 1, "backend2 propfind_do not called");
1040
1041
1042 UCX_TEST_END;
1043 testutil_destroy_session(sn);
1044 }
1045
1046 UCX_TEST(test_webdav_op_propfind_children) {
1047 reset_backends();
1048
1049 Session *sn;
1050 Request *rq;
1051
1052 UCX_TEST_BEGIN;
1053 WebdavOperation *op = test_propfind_op(&sn, &rq, TEST_PROPFIND1);
1054 UCX_TEST_ASSERT(op, "WebdavOperation not created");
1055
1056 int err = webdav_op_propfind_begin(op, "/", NULL, NULL);
1057 UCX_TEST_ASSERT(err == 0, "propfind_begin error");
1058
1059 // create test vfs with some files (code from test_vfs_readdir)
1060 rq->vfs = testvfs_create(sn);
1061 VFSContext *vfs = vfs_request_context(sn, rq);
1062 UCX_TEST_ASSERT(vfs, "no vfs");
1063
1064 err = vfs_mkdir(vfs, "/dir");
1065 UCX_TEST_ASSERT(err == 0, "error not 0");
1066
1067 // add some test file to /dir
1068 UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file1", O_CREAT), "creation of file1 failed");
1069 UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file2", O_CREAT), "creation of file2 failed");
1070 UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file3", O_CREAT), "creation of file3 failed");
1071 UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file4", O_CREAT), "creation of file4 failed");
1072
1073 VFSDir *dir = vfs_opendir(vfs, "/dir");
1074 UCX_TEST_ASSERT(dir, "dir not opened");
1075
1076 UCX_TEST_ASSERT(backend1_propfind_do_count == 1, "backend1 propfind_do not called");
1077 UCX_TEST_ASSERT(backend2_propfind_do_count == 1, "backend1 propfind_do not called")
1078
1079 // propfind for all children
1080 err = webdav_op_propfind_children(op, vfs, "/", "/dir");
1081 UCX_TEST_ASSERT(err == 0, "webdav_op_propfind_children failed");
1082
1083 // 1 dir + 4 children
1084 UCX_TEST_ASSERT(backend1_propfind_do_count == 5, "backend1 propfind_do wrong count");
1085 UCX_TEST_ASSERT(backend2_propfind_do_count == 5, "backend2 propfind_do wrong count");
1086
1087 UCX_TEST_END;
1088 testutil_destroy_session(sn);
1089 }
1090
1091 void init_test_webdav_method(
1092 Session **out_sn,
1093 Request **out_rq,
1094 TestIOStream **out_st,
1095 pblock **out_pb,
1096 const char *method,
1097 const char *path,
1098 const char *request_body)
1099 {
1100 Session *sn;
1101 Request *rq;
1102 TestIOStream *st;
1103 pblock *pb;
1104
1105 sn = testutil_session();
1106 rq = testutil_request(sn->pool, method, "/");
1107
1108 pblock_nvinsert("path", path, rq->vars);
1109 pblock_nvinsert("uri", path, rq->reqpb);
1110
1111 st = testutil_iostream(2048, TRUE);
1112 sn->csd = (IOStream*)st;
1113
1114 if(request_body) {
1115 testutil_request_body(sn, rq, request_body, strlen(request_body));
1116 }
1117
1118 pb = pblock_create_pool(sn->pool, 4);
1119
1120 *out_sn = sn;
1121 *out_rq = rq;
1122 *out_st = st;
1123 *out_pb = pb;
1124 }
1125
1126 UCX_TEST(test_webdav_propfind) {
1127 Session *sn;
1128 Request *rq;
1129 TestIOStream *st;
1130 pblock *pb;
1131
1132 UCX_TEST_BEGIN;
1133
1134 int ret;
1135 // Test 1
1136 init_test_webdav_method(&sn, &rq, &st, &pb, "PROPFIND", "/", TEST_PROPFIND1);
1137
1138 ret = webdav_propfind(pb, sn, rq);
1139
1140 UCX_TEST_ASSERT(ret == REQ_PROCEED, "webdav_propfind (1) failed");
1141
1142 xmlDoc *doc = xmlReadMemory(
1143 st->buf->space, st->buf->size, NULL, NULL, 0);
1144 UCX_TEST_ASSERT(doc, "propfind1: response is not valid xml");
1145
1146 //printf("\n\n%.*s\n", (int)st->buf->size, st->buf->space);
1147
1148 testutil_destroy_session(sn);
1149 xmlFreeDoc(doc);
1150 testutil_iostream_destroy(st);
1151
1152 // Test2
1153 init_test_webdav_method(&sn, &rq, &st, &pb, "PROPFIND", "/", TEST_PROPFIND2);
1154
1155 ret = webdav_propfind(pb, sn, rq);
1156
1157 UCX_TEST_ASSERT(ret == REQ_PROCEED, "webdav_propfind (2) failed");
1158
1159 xmlDoc *doc2 = xmlReadMemory(
1160 st->buf->space, st->buf->size, NULL, NULL, 0);
1161 UCX_TEST_ASSERT(doc, "propfind2: response is not valid xml");
1162
1163 //printf("\n\n%.*s\n", (int)st->buf->size, st->buf->space);
1164
1165 testutil_destroy_session(sn);
1166 xmlFreeDoc(doc2);
1167 testutil_iostream_destroy(st);
1168
1169 UCX_TEST_END;
1170
1171 }
1172
1173 /* -------------------------------------------------------------------------
1174 *
1175 * PROPPATCH TESTS
1176 *
1177 * ------------------------------------------------------------------------ */
1178
1179 static int test_proppatch_init(
1180 Session **out_sn,
1181 Request **out_rq,
1182 WebdavProppatchRequest **out_proppatch,
1183 const char *xml)
1184 {
1185 if(!webdav_is_initialized) {
1186 if(webdav_init(NULL, NULL, NULL) != REQ_PROCEED) {
1187 return 1;
1188 }
1189 webdav_is_initialized = 1;
1190 }
1191
1192 Session *sn = testutil_session();
1193 Request *rq = testutil_request(sn->pool, "PROPPATCH", "/");
1194
1195 int error = 0;
1196
1197 WebdavProppatchRequest *proppatch = proppatch_parse(
1198 sn,
1199 rq,
1200 xml,
1201 strlen(xml),
1202 &error);
1203
1204 if(error) {
1205 return 1;
1206 }
1207
1208 if(!proppatch || !(proppatch->set || proppatch->remove)) {
1209 return 1;
1210 }
1211
1212 *out_sn = sn;
1213 *out_rq = rq;
1214 *out_proppatch = proppatch;
1215 return 0;
1216 }
1217
1218 static WebdavOperation* test_proppatch_op1(
1219 Session **out_sn,
1220 Request **out_rq,
1221 const char *xml)
1222 {
1223 WebdavProppatchRequest *proppatch;
1224 if(test_proppatch_init(out_sn, out_rq, &proppatch, xml)) {
1225 return NULL;
1226 }
1227
1228 Multistatus *ms = multistatus_response(*out_sn, *out_rq);
1229 if(!ms) {
1230 return NULL;
1231 }
1232 // WebdavResponse is the public interface used by Backends
1233 // for adding resources to the response
1234 WebdavResponse *response = (WebdavResponse*)ms;
1235
1236 return webdav_create_proppatch_operation(
1237 (*out_sn),
1238 (*out_rq),
1239 &backend1,
1240 proppatch,
1241 response);
1242 }
1243
1244
1245 UCX_TEST(test_proppatch_msresponse) {
1246 Session *sn;
1247 Request *rq;
1248 WebdavOperation *op;
1249
1250 Multistatus *ms;
1251 WebdavResource *res;
1252
1253 WebdavProperty p[16];
1254 const char *names[] = {"a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9"};
1255 for(int i=0;i<8;i++) {
1256 p[i].namespace = webdav_dav_namespace();
1257 p[i].name = names[i];
1258 p[i].lang = NULL;
1259 p[i].value.node = NULL;
1260 p[i].vtype = 0;
1261 }
1262
1263 UCX_TEST_BEGIN;
1264
1265 op = test_proppatch_op1(&sn, &rq, TEST_PROPPATCH2);
1266 UCX_TEST_ASSERT(op, "failed to create proppatch operation");
1267
1268 ms = (Multistatus*)op->response;
1269 ms->proppatch = TRUE;
1270 res = ms->response.addresource(&ms->response, "/");
1271 UCX_TEST_ASSERT(res, "cannot create resource 1");
1272
1273 UCX_TEST_ASSERT(!res->addproperty(res, &p[0], 200), "addproperty 1 failed");
1274 UCX_TEST_ASSERT(!res->addproperty(res, &p[1], 200), "addproperty 2 failed");
1275 UCX_TEST_ASSERT(!res->addproperty(res, &p[2], 200), "addproperty 3 failed");
1276 UCX_TEST_ASSERT(!res->addproperty(res, &p[3], 200), "addproperty 4 failed");
1277
1278 UCX_TEST_ASSERT(!res->close(res), "close failed");
1279
1280 MSResponse *msres = (MSResponse*)res;
1281 UCX_TEST_ASSERT(!msres->errors, "error list not NULL");
1282 UCX_TEST_ASSERT(msres->plist_begin, "elm1 missing");
1283 UCX_TEST_ASSERT(msres->plist_begin->next, "elm2 missing");
1284 UCX_TEST_ASSERT(msres->plist_begin->next->next, "elm3 missing");
1285 UCX_TEST_ASSERT(msres->plist_begin->next->next->next, "elm4 missing");
1286 UCX_TEST_ASSERT(!msres->plist_begin->next->next->next->next, "count != 4");
1287
1288 UCX_TEST_END;
1289 testutil_destroy_session(sn);
1290 }
1291
1292 UCX_TEST(test_msresponse_addproperty_with_errors) {
1293 Session *sn;
1294 Request *rq;
1295 WebdavOperation *op;
1296
1297 Multistatus *ms;
1298 WebdavResource *res;
1299
1300 WebdavProperty p[16];
1301 const char *names[] = {"a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9"};
1302 for(int i=0;i<8;i++) {
1303 p[i].namespace = webdav_dav_namespace();
1304 p[i].name = names[i];
1305 p[i].lang = NULL;
1306 p[i].value.node = NULL;
1307 p[i].vtype = 0;
1308 }
1309
1310 UCX_TEST_BEGIN;
1311
1312 op = test_proppatch_op1(&sn, &rq, TEST_PROPPATCH2);
1313 UCX_TEST_ASSERT(op, "failed to create proppatch operation");
1314
1315 ms = (Multistatus*)op->response;
1316 ms->proppatch = TRUE;
1317 res = ms->response.addresource(&ms->response, "/");
1318 UCX_TEST_ASSERT(res, "cannot create resource 1");
1319
1320 UCX_TEST_ASSERT(!res->addproperty(res, &p[0], 200), "addproperty 1 failed");
1321 UCX_TEST_ASSERT(!res->addproperty(res, &p[1], 200), "addproperty 2 failed");
1322 UCX_TEST_ASSERT(!res->addproperty(res, &p[2], 409), "addproperty 3 failed");
1323 UCX_TEST_ASSERT(!res->addproperty(res, &p[3], 200), "addproperty 4 failed");
1324
1325 UCX_TEST_ASSERT(!res->close(res), "close failed");
1326
1327 // all properties should have an error status code now
1328 // 1 x 409, 3 x 424
1329
1330 MSResponse *msres = (MSResponse*)res;
1331
1332 UCX_TEST_ASSERT(!msres->plist_begin, "plist not NULL");
1333 UCX_TEST_ASSERT(msres->errors, "error list is NULL");
1334 UCX_TEST_ASSERT(msres->errors->next, "second error list is missing");
1335 UCX_TEST_ASSERT(!msres->errors->next->next, "wrong error list size");
1336
1337 // We know that we have 2 error lists, one with status code 409 and
1338 // the other must have 409. However we don't enforce the order of the
1339 // error lists, therefore check both variants
1340 if(msres->errors->status == 409) {
1341 UCX_TEST_ASSERT(msres->errors->next->status == 424, "wrong status code in second err elm");
1342 UCX_TEST_ASSERT(msres->errors->begin, "missing 409 property");
1343 UCX_TEST_ASSERT(msres->errors->next->begin, "missing 424 properties");
1344 } else {
1345 UCX_TEST_ASSERT(msres->errors->next->status == 409, "wrong status code in second err elm");
1346 UCX_TEST_ASSERT(msres->errors->begin, "missing 424 properties");
1347 UCX_TEST_ASSERT(msres->errors->next->begin, "missing 409 property");
1348 }
1349
1350 UCX_TEST_END;
1351 testutil_destroy_session(sn);
1352 }
1353
1354 UCX_TEST(test_webdav_op_proppatch) {
1355 Session *sn;
1356 Request *rq;
1357 WebdavOperation *op;
1358
1359 Multistatus *ms;
1360 WebdavResource *res;
1361
1362 WebdavProperty p[16];
1363 const char *names[] = {"a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9"};
1364 for(int i=0;i<8;i++) {
1365 p[i].namespace = webdav_dav_namespace();
1366 p[i].name = names[i];
1367 p[i].lang = NULL;
1368 p[i].value.node = NULL;
1369 p[1].vtype = 0;
1370 }
1371
1372 UCX_TEST_BEGIN;
1373
1374 // TEST_PROPPATCH2 should succeed
1375 reset_backends();
1376 op = test_proppatch_op1(&sn, &rq, TEST_PROPPATCH2);
1377 UCX_TEST_ASSERT(op, "failed to create proppatch operation");
1378
1379 int ret = webdav_op_proppatch(op, "/", "/");
1380 UCX_TEST_ASSERT(ret == 0, "webdav_op_proppatch failed");
1381 UCX_TEST_ASSERT(backend1_proppatch_commit, "backend1 no commit");
1382 UCX_TEST_ASSERT(backend2_proppatch_commit, "backend2 no commit");
1383 UCX_TEST_ASSERT(backend1_proppatch_do_count == 1, "backend1 wrong count (1)");
1384 UCX_TEST_ASSERT(backend2_proppatch_do_count == 1, "backend1 wrong count (1)");
1385 UCX_TEST_ASSERT(backend1_proppatch_finish_count == 1, "backend1 wrong finish count (1)");
1386 UCX_TEST_ASSERT(backend2_proppatch_finish_count == 1, "backend1 wrong finish count (1)");
1387
1388 // TEST_PROPPATCH3 should fail (commit == FALSE)
1389 reset_backends();
1390 op = test_proppatch_op1(&sn, &rq, TEST_PROPPATCH3);
1391 UCX_TEST_ASSERT(op, "failed to create proppatch operation 2");
1392
1393 ret = webdav_op_proppatch(op, "/", "/");
1394 UCX_TEST_ASSERT(ret == 0, "webdav_op_proppatch failed (2)");
1395 UCX_TEST_ASSERT(!backend1_proppatch_commit, "backend1 commit");
1396 UCX_TEST_ASSERT(!backend2_proppatch_commit, "backend2 commit");
1397
1398 // TEST_PROPPATCH4 should abort
1399 reset_backends();
1400 op = test_proppatch_op1(&sn, &rq, TEST_PROPPATCH4);
1401 UCX_TEST_ASSERT(op, "failed to create proppatch operation 3");
1402
1403 ret = webdav_op_proppatch(op, "/", "/");
1404 UCX_TEST_ASSERT(ret != 0, "webdav_op_proppatch should fail");
1405 UCX_TEST_ASSERT(backend1_proppatch_do_count == 1, "backend1 wrong count (2)");
1406 UCX_TEST_ASSERT(backend2_proppatch_do_count == 1, "backend1 wrong count (2)");
1407 UCX_TEST_ASSERT(backend1_proppatch_finish_count == 1, "backend1 wrong finish count (2)");
1408 UCX_TEST_ASSERT(backend2_proppatch_finish_count == 0, "backend1 wrong finish count (2)");
1409
1410 UCX_TEST_END;
1411 testutil_destroy_session(sn);
1412 }
1413
1414 #define xstreq(a, b) (!strcmp((const char*)a, (const char*)b))
1415
1416 UCX_TEST(test_webdav_proppatch) {
1417 Session *sn;
1418 Request *rq;
1419 TestIOStream *st;
1420 pblock *pb;
1421
1422 UCX_TEST_BEGIN;
1423
1424 int ret;
1425 // Test 1
1426 init_test_webdav_method(&sn, &rq, &st, &pb, "PROPPATCH", "/", TEST_PROPPATCH2);
1427 rq->davCollection = &backend1;
1428 ret = webdav_proppatch(pb, sn, rq);
1429
1430 UCX_TEST_ASSERT(ret == REQ_PROCEED, "webdav_proppatch (1) failed");
1431
1432 xmlDoc *doc = xmlReadMemory(
1433 st->buf->space, st->buf->size, NULL, NULL, 0);
1434 UCX_TEST_ASSERT(doc, "proppatch1: response is not valid xml");
1435
1436 //printf("\n\n%.*s\n", (int)st->buf->size, st->buf->space);
1437
1438 xmlNode *root = xmlDocGetRootElement(doc);
1439 UCX_TEST_ASSERT(root, "proppatch1: no root");
1440
1441 xmlNode *nodeC = NULL;
1442 xmlNode *node = root->children;
1443 int depth = 1;
1444 while(node) {
1445 const xmlChar *name = node->name;
1446 int nextNode = 1;
1447 if(node->type != XML_ELEMENT_NODE) {
1448 // nothing
1449 } else if(depth == 1) {
1450 if(xstreq(name, "response")) {
1451 nextNode = 0;
1452 }
1453 } else if(depth == 2) {
1454 if(xstreq(name, "propstat")) {
1455 nextNode = 0;
1456 }
1457 } else if(depth == 3) {
1458 if(xstreq(name, "prop")) {
1459 nextNode = 0;
1460 }
1461 } else if(depth == 4) {
1462 if(xstreq(name, "c")) {
1463 nodeC = node;
1464 break;
1465 }
1466 }
1467
1468 if(nextNode) {
1469 node = node->next;
1470 } else {
1471 node = node->children;
1472 depth++;
1473 }
1474 }
1475
1476 UCX_TEST_ASSERT(nodeC, "prop c not in response");
1477 UCX_TEST_ASSERT(!nodeC->children, "properties must not have a value");
1478
1479 testutil_destroy_session(sn);
1480 xmlFreeDoc(doc);
1481 testutil_iostream_destroy(st);
1482
1483
1484 UCX_TEST_END;
1485 }
1486
1487
1488 /* -------------------------------------------------------------------------
1489 *
1490 * WEBDAV VFS TESTS
1491 *
1492 * ------------------------------------------------------------------------ */
1493
1494 static int mkcol_data1 = 10;
1495 static int mkcol_data2 = 20;
1496 static int mkcol_data3 = 30;
1497 static int mkcol_data4 = 40;
1498
1499 static int mkcol_count = 0;
1500 static int mkcol_finish_count = 0;
1501
1502 static int mkcol_err = 0;
1503
1504 static int set_created = 0;
1505
1506 static int test_webdav_mkcol(WebdavVFSRequest *req, WSBool *created) {
1507 mkcol_count++;
1508
1509 switch(mkcol_count) {
1510 case 1: {
1511 req->userdata = &mkcol_data1;
1512 break;
1513 }
1514 case 2: {
1515 req->userdata = &mkcol_data2;
1516 break;
1517 }
1518 case 3: {
1519 req->userdata = &mkcol_data3;
1520 break;
1521 }
1522 case 4: {
1523 req->userdata = &mkcol_data4;
1524 break;
1525 }
1526 default: break;
1527 }
1528
1529 if(set_created) {
1530 *created = TRUE;
1531 set_created = 0;
1532 }
1533
1534 return 0;
1535 }
1536
1537 static int test_webdav_mkcol_finish(WebdavVFSRequest *req, WSBool success) {
1538 mkcol_finish_count++;
1539
1540 if(mkcol_finish_count == 1) {
1541 int *data = req->userdata;
1542 if(data != &mkcol_data1) {
1543 mkcol_err = 1;
1544 }
1545 } else if(mkcol_finish_count == 3) {
1546 int *data = req->userdata;
1547 if(data != &mkcol_data3) {
1548 mkcol_err = 1;
1549 }
1550 } else {
1551 int *data = req->userdata;
1552 // data4 should never be used
1553 if(data == &mkcol_data4) {
1554 mkcol_err = 1;
1555 }
1556 }
1557
1558 return 0;
1559 }
1560
1561 static int test_webdav_mkcol_fail(WebdavVFSRequest *req, WSBool *created) {
1562 mkcol_count++;
1563 return 1;
1564 }
1565
1566 static int delete_count = 0;
1567 static int delete_finish_count = 0;
1568
1569 static int test_backend_webdav_delete(WebdavVFSRequest *req, WSBool *created) {
1570 delete_count++;
1571 return 0;
1572 }
1573
1574 static int test_backend_webdav_delete_finish(WebdavVFSRequest *req, WSBool success) {
1575 delete_finish_count++;
1576 return 0;
1577 }
1578
1579
1580 UCX_TEST(test_webdav_vfs_op_do) {
1581 Session *sn;
1582 Request *rq;
1583 TestIOStream *st;
1584 pblock *pb;
1585
1586 // Tests performed primarily with MKCOL, because webdav_vfs_op_do
1587 // behaves the same for both operations
1588 // the only difference are the callbacks
1589
1590 init_test_webdav_method(&sn, &rq, &st, &pb, "MKCOL", "/", NULL);
1591 VFS *testvfs = testvfs_create(sn);
1592 rq->vfs = testvfs;
1593
1594 WebdavBackend dav1;
1595 ZERO(&dav1, sizeof(WebdavBackend));
1596 dav1.opt_mkcol = test_webdav_mkcol;
1597 dav1.opt_mkcol_finish = test_webdav_mkcol_finish;
1598 dav1.opt_delete = test_backend_webdav_delete;
1599 dav1.opt_delete_finish = test_backend_webdav_delete_finish;
1600
1601 WebdavBackend dav2;
1602 ZERO(&dav2, sizeof(WebdavBackend));
1603 dav2.opt_mkcol_finish = test_webdav_mkcol_finish;
1604
1605 WebdavBackend dav3;
1606 ZERO(&dav3, sizeof(WebdavBackend));
1607 dav3.opt_mkcol = test_webdav_mkcol;
1608
1609 WebdavBackend dav4;
1610 ZERO(&dav4, sizeof(WebdavBackend));
1611 dav4.opt_mkcol = test_webdav_mkcol;
1612 dav4.opt_mkcol_finish = test_webdav_mkcol_finish;
1613
1614 dav1.next = &dav2;
1615 dav2.next = &dav3;
1616 dav3.next = &dav4;
1617
1618 rq->davCollection = &dav1;
1619
1620 UCX_TEST_BEGIN;
1621
1622 WebdavVFSOperation *op1 = webdav_vfs_op(sn, rq, &dav1, FALSE);
1623
1624 int ret = webdav_vfs_op_do(op1, WEBDAV_VFS_MKDIR);
1625
1626 UCX_TEST_ASSERT(!ret, "webdav_vfs_op_do failed");
1627 UCX_TEST_ASSERT(mkcol_count == 3, "wrong mkcol_count");
1628 UCX_TEST_ASSERT(mkcol_finish_count == 3, "wrong mkcol_finish_count");
1629 UCX_TEST_ASSERT(mkcol_err == 0, "mkcol_err");
1630
1631 // test without VFS, but set *created to TRUE to skip VFS usage
1632 rq->vfs = NULL;
1633 set_created = 1;
1634
1635 WebdavVFSOperation *op2 = webdav_vfs_op(sn, rq, &dav1, FALSE);
1636 ret = webdav_vfs_op_do(op2, WEBDAV_VFS_MKDIR);
1637
1638 UCX_TEST_ASSERT(!ret, "op2 failed");
1639
1640 // test 3: abort after first backend
1641 mkcol_count = 0;
1642 mkcol_finish_count = 0;
1643 dav1.opt_mkcol = test_webdav_mkcol_fail;
1644
1645 WebdavVFSOperation *op3 = webdav_vfs_op(sn, rq, &dav1, FALSE);
1646 ret = webdav_vfs_op_do(op3, WEBDAV_VFS_MKDIR);
1647
1648 UCX_TEST_ASSERT(ret, "op3 should fail");
1649 UCX_TEST_ASSERT(mkcol_count == 1, "op3: wrong mkcol_count");
1650 UCX_TEST_ASSERT(mkcol_finish_count == 1, "op3: wrong mkcol_finish_count");
1651
1652 // test DELETE to make sure, delete callbacks will be used
1653 pblock_replace("path", "/deltest", rq->vars);
1654 rq->vfs = testvfs;
1655 WebdavVFSOperation *op_del = webdav_vfs_op(sn, rq, &dav1, FALSE);
1656 vfs_open(op_del->vfs, "/deltest", O_CREAT);
1657 ret = webdav_vfs_op_do(op_del, WEBDAV_VFS_DELETE);
1658
1659 UCX_TEST_ASSERT(!ret, "op_del failed");
1660 UCX_TEST_ASSERT(delete_count == 1, "op_del: wrong delete_count");
1661 UCX_TEST_ASSERT(delete_finish_count == 1, "op_del: wrong delete_finish_count");
1662
1663
1664 UCX_TEST_END;
1665 }
1666
1667 UCX_TEST(test_webdav_delete){
1668 Session *sn;
1669 Request *rq;
1670 TestIOStream *st;
1671 pblock *pb;
1672
1673 init_test_webdav_method(&sn, &rq, &st, &pb, "DELETE", "/", NULL);
1674 rq->vfs = testvfs_create(sn);
1675
1676 WebdavBackend dav1;
1677 ZERO(&dav1, sizeof(WebdavBackend));
1678 dav1.opt_delete = test_backend_webdav_delete;
1679 dav1.opt_delete_finish = test_backend_webdav_delete_finish;
1680 delete_count = 0;
1681 delete_finish_count = 0;
1682 rq->davCollection = &dav1;
1683
1684 UCX_TEST_BEGIN;
1685
1686 // prepare
1687 VFSContext *vfs = vfs_request_context(sn, rq);
1688 int err;
1689 err = vfs_mkdir(vfs, "/dir1");
1690 UCX_TEST_ASSERT(err == 0, "mkdir dir1 failed");
1691 err = vfs_mkdir(vfs, "/dir2");
1692 UCX_TEST_ASSERT(err == 0, "mkdir dir2 failed");
1693 err = vfs_mkdir(vfs, "/dir2/dir3");
1694 UCX_TEST_ASSERT(err == 0, "mkdir dir3 failed");
1695 err = vfs_mkdir(vfs, "/dir2/dir4");
1696 UCX_TEST_ASSERT(err == 0, "mkdir dir4 failed");
1697 err = vfs_mkdir(vfs, "/dir2/dir4/dir5");
1698 UCX_TEST_ASSERT(err == 0, "mkdir dir5 failed");
1699
1700 SYS_FILE f0 = vfs_open(vfs, "/file0", O_CREAT);
1701 UCX_TEST_ASSERT(f0, "f0 create failed");
1702 // no f1
1703 SYS_FILE f2 = vfs_open(vfs, "/dir2/file2", O_CREAT);
1704 UCX_TEST_ASSERT(f2, "f2 create failed");
1705 SYS_FILE f3 = vfs_open(vfs, "/dir2/dir3/file3", O_CREAT);
1706 UCX_TEST_ASSERT(f3, "f3 create failed");
1707 SYS_FILE f4 = vfs_open(vfs, "/dir2/dir4/file4", O_CREAT);
1708 UCX_TEST_ASSERT(f4, "f4 create failed");
1709 SYS_FILE f5 = vfs_open(vfs, "/dir2/dir4/dir5/file5", O_CREAT);
1710 UCX_TEST_ASSERT(f5, "f5 create failed");
1711
1712 // delete single file
1713 pblock_replace("path", "/file0", rq->vars);
1714 err = webdav_delete(NULL, sn, rq);
1715 UCX_TEST_ASSERT(err == 0, "DELETE /file0 failed");
1716 UCX_TEST_ASSERT(delete_count == 1, "del1: wrong delete count");
1717
1718 delete_count = 0;
1719 pblock_replace("path", "/dir1", rq->vars);
1720 err = webdav_delete(NULL, sn, rq);
1721 UCX_TEST_ASSERT(err == 0, "DELETE /dir1 failed");
1722 UCX_TEST_ASSERT(delete_count == 1, "del1: wrong delete count");
1723
1724 delete_count = 0;
1725 pblock_replace("path", "/dir2", rq->vars);
1726 err = webdav_delete(NULL, sn, rq);
1727 UCX_TEST_ASSERT(err == 0, "DELETE /dir2 failed");
1728 UCX_TEST_ASSERT(delete_count == 8, "del2: wrong delete count");
1729
1730 UCX_TEST_END;
1731 }
1732
1733 UCX_TEST(test_webdav_put) {
1734 Session *sn;
1735 Request *rq;
1736 TestIOStream *st;
1737 pblock *pb;
1738
1739 const char *content_const = "Hello World";
1740
1741 init_test_webdav_method(&sn, &rq, &st, &pb, "PUT", "/", content_const);
1742 rq->vfs = testvfs_create(sn);
1743
1744 UCX_TEST_BEGIN;
1745
1746 int err;
1747
1748 pblock_replace("path", "/file0", rq->vars);
1749 err = webdav_put(NULL, sn, rq);
1750
1751 UCX_TEST_ASSERT(err == REQ_PROCEED, "put failed");
1752
1753 VFSContext *vfs = vfs_request_context(sn, rq);
1754 SYS_FILE f0 = vfs_open(vfs, "/file0", 0);
1755 UCX_TEST_ASSERT(f0, "cannot open file0");
1756
1757 char buf[1024];
1758 int r = system_fread(f0, buf, 1024);
1759
1760 UCX_TEST_ASSERT(r == strlen(content_const), "wrong file size");
1761 UCX_TEST_ASSERT(!memcmp(content_const, buf, r), "wrong file content");
1762
1763 testutil_destroy_session(sn);
1764 testutil_iostream_destroy(st);
1765
1766 UCX_TEST_END;
1767 }

mercurial