1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <cx/buffer.h>
34 #include <cx/list.h>
35 #include <cx/linked_list.h>
36 #include <cx/hash_map.h>
37 #include <cx/printf.h>
38
39 #include "webdav.h"
40
41 #include "search.h"
42 #include "versioning.h"
43 #include "multistatus.h"
44 #include "requestparser.h"
45 #include "operation.h"
46
47 #include "xattrbackend.h"
48
49 #include "../util/pblock.h"
50 #include "../util/util.h"
51 #include "../daemon/session.h"
52 #include "../daemon/http.h"
53 #include "../daemon/protocol.h"
54 #include "../daemon/vfs.h"
55
56
57
58
59
60
61 static CxMap *method_handler_map;
62
63
64
65
66
67
68 static CxMap *webdav_type_map;
69
70 static WebdavBackend default_backend;
71
72 static WSNamespace dav_namespace;
73
74 static WebdavProperty dav_resourcetype_empty;
75 static WebdavProperty dav_resourcetype_collection;
76 static WSXmlData dav_resourcetype_collection_value;
77
78 #define WEBDAV_RESOURCE_TYPE_COLLECTION "<D:collection/>"
79
80
81 static WebdavBackend* default_backend_create(Session *sn, Request *rq, pblock *pb,
void *initData) {
82 WebdavBackend *dav = pool_malloc(sn->pool,
sizeof(WebdavBackend));
83 if(!dav) {
84 return NULL;
85 }
86
87 *dav = default_backend;
88 return dav;
89 }
90
91 static int init_default_backend(
void) {
92 memset(&default_backend,
0,
sizeof(WebdavBackend));
93 default_backend.propfind_init = default_propfind_init;
94 default_backend.propfind_do = default_propfind_do;
95 default_backend.propfind_finish = default_propfind_finish;
96 default_backend.proppatch_do = default_proppatch_do;
97 default_backend.proppatch_finish = default_proppatch_finish;
98 default_backend.opt_mkcol =
NULL;
99 default_backend.opt_delete =
NULL;
100 default_backend.settings =
WS_WEBDAV_PROPFIND_USE_VFS;
101 default_backend.instance =
NULL;
102
103 return webdav_register_backend(
"default",
NULL, default_backend_create);
104 }
105
106
107 int webdav_register_backend(
const char *name, webdav_init_func webdavInit, webdav_create_func webdavCreate) {
108 WebdavType *webdavType = malloc(
sizeof(WebdavType));
109 webdavType->init = webdavInit;
110 webdavType->create = webdavCreate;
111 return cxMapPut(webdav_type_map, cx_hash_key_str(name), webdavType);
112 }
113
114 WebdavType* webdav_get_type(cxstring dav_class) {
115 return cxMapGet(webdav_type_map, cx_hash_key_bytes((
unsigned const char *)dav_class.ptr, dav_class.length));
116 }
117
118 void* webdav_init_backend(ServerConfiguration *cfg,
pool_handle_t *pool, WebdavType *dav_class, WSConfigNode *config,
int *error) {
119 *error =
0;
120 if(dav_class->init) {
121 void *initData = dav_class->init(cfg, pool, config);
122 if(!initData) {
123 *error =
1;
124 }
125 return initData;
126 }
else {
127 return NULL;
128 }
129 }
130
131 WebdavBackend* webdav_create(Session *sn, Request *rq,
const char *dav_class, pblock *pb,
void *initData) {
132 WebdavType *webdavType = cxMapGet(webdav_type_map, cx_hash_key_str(dav_class));
133 if(!webdavType) {
134 log_ereport(
LOG_MISCONFIG,
"webdav_create: unkown dav type %s", dav_class);
135 return NULL;
136 }
137
138 return webdavType->create(sn, rq, pb, initData);
139 }
140
141 static WSBool webdav_is_initialized =
FALSE;
142
143 int webdav_init(pblock *pb, Session *sn, Request *rq) {
144 if(webdav_is_initialized) {
145 return REQ_NOACTION;
146 }
147 webdav_is_initialized =
TRUE;
148
149 webdav_type_map = cxHashMapCreate(cxDefaultAllocator,
CX_STORE_POINTERS,
8);
150 if(!webdav_type_map) {
151 return REQ_ABORTED;
152 }
153
154 method_handler_map = cxHashMapCreate(cxDefaultAllocator,
CX_STORE_POINTERS,
64);
155 if(!method_handler_map) {
156 return REQ_ABORTED;
157 }
158
159 if(init_default_backend()) {
160 return REQ_ABORTED;
161 }
162
163 if(webdav_init_xattr_backend()) {
164 return REQ_ABORTED;
165 }
166
167 cxMapPut(method_handler_map, cx_hash_key_str(
"OPTIONS"), webdav_options);
168 cxMapPut(method_handler_map, cx_hash_key_str(
"PROPFIND"), webdav_propfind);
169 cxMapPut(method_handler_map, cx_hash_key_str(
"PROPPATCH"), webdav_proppatch);
170 cxMapPut(method_handler_map, cx_hash_key_str(
"MKCOL"), webdav_mkcol);
171 cxMapPut(method_handler_map, cx_hash_key_str(
"POST"), webdav_post);
172 cxMapPut(method_handler_map, cx_hash_key_str(
"DELETE"), webdav_delete);
173 cxMapPut(method_handler_map, cx_hash_key_str(
"PUT"), webdav_put);
174 cxMapPut(method_handler_map, cx_hash_key_str(
"COPY"), webdav_copy);
175 cxMapPut(method_handler_map, cx_hash_key_str(
"MOVE"), webdav_move);
176 cxMapPut(method_handler_map, cx_hash_key_str(
"LOCK"), webdav_lock);
177 cxMapPut(method_handler_map, cx_hash_key_str(
"UNLOCK"), webdav_unlock);
178 cxMapPut(method_handler_map, cx_hash_key_str(
"REPORT"), webdav_report);
179 cxMapPut(method_handler_map, cx_hash_key_str(
"ACL"), webdav_acl);
180
181 cxMapPut(method_handler_map, cx_hash_key_str(
"SEARCH"), webdav_search);
182
183 cxMapPut(method_handler_map, cx_hash_key_str(
"VERSION-CONTROL"), webdav_version_control);
184 cxMapPut(method_handler_map, cx_hash_key_str(
"CHECKOUT"), webdav_checkout);
185 cxMapPut(method_handler_map, cx_hash_key_str(
"CHECKIN"), webdav_checkin);
186 cxMapPut(method_handler_map, cx_hash_key_str(
"UNCHECKOUT"), webdav_uncheckout);
187 cxMapPut(method_handler_map, cx_hash_key_str(
"MKWORKSPACE"), webdav_mkworkspace);
188 cxMapPut(method_handler_map, cx_hash_key_str(
"UPDATE"), webdav_update);
189 cxMapPut(method_handler_map, cx_hash_key_str(
"LABEL"), webdav_label);
190 cxMapPut(method_handler_map, cx_hash_key_str(
"MERGE"), webdav_merge);
191
192 dav_namespace.href = (xmlChar*)
"DAV:";
193 dav_namespace.prefix = (xmlChar*)
"D";
194
195 dav_resourcetype_empty.namespace = &dav_namespace;
196 dav_resourcetype_empty.name =
"resourcetype";
197
198 dav_resourcetype_collection_value.data =
WEBDAV_RESOURCE_TYPE_COLLECTION;
199 dav_resourcetype_collection_value.length =
sizeof(
WEBDAV_RESOURCE_TYPE_COLLECTION)-
1;
200
201 dav_resourcetype_collection.namespace = &dav_namespace;
202 dav_resourcetype_collection.name =
"resourcetype";
203 dav_resourcetype_collection.value.data = dav_resourcetype_collection_value;
204 dav_resourcetype_collection.vtype =
WS_VALUE_XML_DATA;
205
206 return REQ_PROCEED;
207 }
208
209
210 int webdav_service(pblock *pb, Session *sn, Request *rq) {
211 if(!method_handler_map) {
212 log_ereport(
LOG_FAILURE,
"WebDAV module not initialized");
213 protocol_status(sn, rq,
500,
NULL);
214 return REQ_ABORTED;
215 }
216 char *method = pblock_findkeyval(pb_key_method, rq->reqpb);
217
218 FuncPtr saf = (FuncPtr)cxMapGet(method_handler_map, cx_hash_key_str(method));
219 if(!saf) {
220 return REQ_NOACTION;
221 }
222
223 return saf(pb, sn, rq);
224 }
225
226 int rqbody2buffer(Session *sn, Request *rq, CxBuffer *buf) {
227 if(!sn->inbuf) {
228
229 protocol_status(sn, rq,
400,
NULL);
230 return 1;
231 }
232
233 CxAllocator *a = pool_allocator(sn->pool);
234 if(cxBufferInit(buf,
NULL, sn->inbuf->maxsize, a,
CX_BUFFER_AUTO_EXTEND|
CX_BUFFER_FREE_CONTENTS)) {
235 protocol_status(sn, rq,
500,
NULL);
236 return 1;
237 }
238
239 char in[
2048];
240 int r;
241 while((r = netbuf_getbytes(sn->inbuf, in,
2048)) >
0) {
242 if(cxBufferWrite(in,
1, r, buf) != r) {
243 protocol_status(sn, rq,
500,
NULL);
244 cxBufferDestroy(buf);
245 return 1;
246 }
247 }
248
249 return 0;
250 }
251
252 int webdav_options(pblock *pb, Session *sn, Request *rq) {
253 return REQ_ABORTED;
254 }
255
256 static const char* propfind_error2str(
int error) {
257 switch(error) {
258 case PROPFIND_PARSER_OK:
return "ok";
259 case PROPFIND_PARSER_NO_PROPFIND:
return "invalid xml root element";
260 case PROPFIND_PARSER_NO_PROPERTIES:
return "no properties specified";
261 case PROPFIND_PARSER_INVALID_REQUEST:
return "invalid propfind request";
262 case PROPFIND_PARSER_OOM:
return "OOM";
263 case PROPFIND_PARSER_ERROR:
return "error";
264 }
265 return "";
266 }
267
268 int webdav_propfind(pblock *pb, Session *sn, Request *rq) {
269 char *expect = pblock_findkeyval(pb_key_expect, rq->headers);
270 if(expect) {
271 if(!strcasecmp(expect,
"100-continue")) {
272 if(http_send_continue(sn)) {
273 return REQ_ABORTED;
274 }
275 }
276 }
277
278 CxBuffer reqbody;
279 if(rqbody2buffer(sn, rq, &reqbody)) {
280 return REQ_ABORTED;
281 }
282
283 int error =
0;
284 WebdavPropfindRequest *propfind = propfind_parse(
285 sn,
286 rq,
287 reqbody.space,
288 reqbody.size,
289 &error);
290 cxBufferDestroy(&reqbody);
291 if(!propfind) {
292 log_ereport(
LOG_FAILURE,
"webdav-propfind: %s", propfind_error2str(error));
293 return REQ_ABORTED;
294 }
295
296 WebdavBackend *dav = rq->davCollection ?
297 rq->davCollection : &default_backend;
298
299
300
301 char *path = pblock_findkeyval(pb_key_path, rq->vars);
302 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
303
304
305
306
307 Multistatus *ms = multistatus_response(sn, rq);
308 if(!ms) {
309 return REQ_ABORTED;
310 }
311
312 int ret = webdav_propfind_do(dav, propfind, (WebdavResponse*)ms,
NULL, path, uri);
313
314
315 if(ret ==
REQ_PROCEED) {
316 if(multistatus_send(ms, sn->csd)) {
317 ret =
REQ_ABORTED;
318 }
319 }
else if(rq->status_num <
400 || rq->status_num >=
500) {
320 log_ereport(
LOG_FAILURE,
"webdav-propfind: operation failed");
321 }
322
323
324 if(propfind->doc) {
325 xmlFreeDoc(propfind->doc);
326 }
327
328 return ret;
329 }
330
331
332
333
334
335
336
337 int webdav_propfind_init(
338 WebdavBackend *dav,
339 WebdavPropfindRequest *propfind,
340 const char *path,
341 const char *uri,
342 WebdavPropfindRequestList **out_req)
343 {
344 pool_handle_t *pool = propfind->sn->pool;
345 CxAllocator *a = pool_allocator(pool);
346
347
348 WebdavPropfindRequestList *requestObjectsBegin =
NULL;
349 WebdavPropfindRequestList *requestObjectsEnd =
NULL;
350
351
352 WebdavPList *newProp = webdav_plist_clone(pool, propfind->properties);
353 size_t newPropCount = propfind->propcount;
354
355
356
357
358
359 WebdavBackend *davList = dav;
360 while(davList) {
361
362 WebdavPropfindRequest *pReq = pool_malloc(
363 pool,
364 sizeof(WebdavPropfindRequest));
365 memcpy(pReq, propfind,
sizeof(WebdavPropfindRequest));
366
367 pReq->properties = newProp;
368 pReq->propcount = newPropCount;
369 pReq->dav = davList;
370
371
372 WebdavPropfindRequestList *reqListElm = pool_malloc(pool,
sizeof(WebdavPropfindRequestList));
373 if(!reqListElm) {
374 return REQ_ABORTED;
375 }
376 reqListElm->propfind = pReq;
377 reqListElm->next =
NULL;
378 cx_linked_list_add(
379 (
void**)&requestObjectsBegin,
380 (
void**)&requestObjectsEnd,
381 -
1,
382 offsetof(WebdavPropfindRequestList, next),
383 reqListElm);
384
385
386 newProp = webdav_plist_clone(pool, newProp);
387
388
389
390 if(davList->propfind_init(pReq, path, uri, &newProp)) {
391 return REQ_ABORTED;
392 }
393
394 newPropCount = webdav_plist_size(newProp);
395
396 davList = davList->next;
397 }
398
399 *out_req = requestObjectsBegin;
400 return REQ_PROCEED;
401 }
402
403 int webdav_propfind_do(
404 WebdavBackend *dav,
405 WebdavPropfindRequest *propfind,
406 WebdavResponse *response,
407 VFSContext *vfs,
408 char *path,
409 char *uri)
410 {
411 Session *sn = propfind->sn;
412 Request *rq = propfind->rq;
413
414
415 uint32_t settings = dav->settings;
416
417
418 WebdavPropfindRequestList *requestObjects =
NULL;
419
420
421 if(webdav_propfind_init(dav, propfind, path, uri, &requestObjects)) {
422 return REQ_ABORTED;
423 }
424
425 WebdavOperation *op = webdav_create_propfind_operation(
426 sn,
427 rq,
428 dav,
429 propfind->properties,
430 requestObjects,
431 response);
432
433
434
435 WSBool usevfs = (settings &
WS_WEBDAV_PROPFIND_USE_VFS)
436 ==
WS_WEBDAV_PROPFIND_USE_VFS;
437 struct stat s;
438 struct stat *statptr =
NULL;
439
440 if(usevfs && !vfs) {
441 vfs = vfs_request_context(sn, rq);
442 if(!vfs) {
443 return REQ_ABORTED;
444 }
445
446 if(vfs_stat(vfs, path, &s)) {
447 protocol_status(sn, rq, util_errno2status(vfs->vfs_errno),
NULL);
448 return REQ_ABORTED;
449 }
450 statptr = &s;
451 if(!
S_ISDIR(s.st_mode)) {
452
453 usevfs =
FALSE;
454 }
455 }
456 if(propfind->depth ==
0) {
457 usevfs =
FALSE;
458 }
459
460 int ret =
REQ_PROCEED;
461
462
463 if(!webdav_op_propfind_begin(op, uri,
NULL, statptr)) {
464
465
466
467
468
469
470
471 if(usevfs) {
472 if(webdav_op_propfind_children(op, vfs, uri, path)) {
473 ret =
REQ_ABORTED;
474 }
475 }
476 }
477
478
479
480
481 if(webdav_op_propfind_finish(op)) {
482
483 ret =
REQ_ABORTED;
484 }
485
486 return ret;
487 }
488
489
490 static const char* proppatch_error2str(
int error) {
491 switch(error) {
492 case PROPPATCH_PARSER_OK:
return "ok";
493 case PROPPATCH_PARSER_NO_PROPERTYUPDATE:
return "no property update";
494 case PROPPATCH_PARSER_NO_PROPERTIES:
return "no properties";
495 case PROPPATCH_PARSER_INVALID_REQUEST:
return "invalid proppatch request";
496 case PROPPATCH_PARSER_DUPLICATE:
return "proppatch property duplicate";
497 case PROPPATCH_PARSER_OOM:
return "OOM";
498 case PROPPATCH_PARSER_ERROR:
return "proppatch parser error";
499 }
500 return "error";
501 }
502
503 int webdav_proppatch(pblock *pb, Session *sn, Request *rq) {
504 char *expect = pblock_findkeyval(pb_key_expect, rq->headers);
505 if(expect) {
506 if(!strcasecmp(expect,
"100-continue")) {
507 if(http_send_continue(sn)) {
508 return REQ_ABORTED;
509 }
510 }
511 }
512
513 CxBuffer reqbody;
514 if(rqbody2buffer(sn, rq, &reqbody)) {
515
516 return REQ_ABORTED;
517 }
518
519 int error =
0;
520 WebdavProppatchRequest *proppatch = proppatch_parse(
521 sn,
522 rq,
523 reqbody.space,
524 reqbody.size,
525 &error);
526 cxBufferDestroy(&reqbody);
527 if(!proppatch) {
528 log_ereport(
LOG_FAILURE,
"webdav-proppatch: %s", proppatch_error2str(error));
529 return REQ_ABORTED;
530 }
531
532 WebdavBackend *dav = rq->davCollection ?
533 rq->davCollection : &default_backend;
534
535
536 char *path = pblock_findkeyval(pb_key_path, rq->vars);
537 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
538
539
540
541
542 Multistatus *ms = multistatus_response(sn, rq);
543 if(!ms) {
544 return REQ_ABORTED;
545 }
546 ms->proppatch =
TRUE;
547
548
549
550 WebdavResponse *response = (WebdavResponse*)ms;
551
552 WebdavOperation *op = webdav_create_proppatch_operation(
553 sn,
554 rq,
555 dav,
556 proppatch,
557 response);
558
559 int ret =
REQ_PROCEED;
560
561
562 if(webdav_op_proppatch(op, uri, path)) {
563 log_ereport(
LOG_FAILURE,
"webdav-proppatch: proppatch operation failed");
564 ret =
REQ_ABORTED;
565 }
566
567
568 if(ret ==
REQ_PROCEED) {
569 if(multistatus_send(ms, sn->csd)) {
570 log_ereport(
LOG_FAILURE,
"webdav-proppatch: multistatus_send failed");
571 }
572 }
else {
573 protocol_status(sn, rq,
500,
NULL);
574 }
575
576
577 xmlFreeDoc(proppatch->doc);
578
579 return ret;
580 }
581
582 int webdav_mkcol(pblock *pb, Session *sn, Request *rq) {
583 WebdavVFSOperation *op = webdav_vfs_op(sn, rq, rq->davCollection,
TRUE);
584 if(!op) {
585 return REQ_ABORTED;
586 }
587
588 int ret =
REQ_ABORTED;
589 if(!webdav_vfs_op_do(op,
WEBDAV_VFS_MKDIR)) {
590 pblock_nvinsert(
"content-length",
"0", rq->srvhdrs);
591 protocol_status(sn, rq,
201,
NULL);
592 protocol_start_response(sn, rq);
593 ret =
REQ_PROCEED;
594 }
else if(rq->status_num <=
0) {
595 int status_code =
500;
596 if(op->vfs->vfs_errno ==
EEXIST) {
597
598 status_code =
405;
599 }
else if(op->vfs->vfs_errno ==
ENOENT) {
600
601
602
603 status_code =
409;
604 }
else {
605 log_ereport(
LOG_VERBOSE,
"webdav_mkcol: errno: %d", op->vfs->vfs_errno);
606 }
607 protocol_status(sn, rq, status_code,
NULL);
608 }
609
610 return ret;
611 }
612
613 int webdav_post(pblock *pb, Session *sn, Request *rq) {
614 return REQ_ABORTED;
615 }
616
617 typedef struct DeleteFile {
618 char *path;
619 struct stat s;
620 struct DeleteFile *prev;
621 struct DeleteFile *next;
622 } DeleteFile;
623
624 typedef struct DeleteLists {
625 CxAllocator *a;
626 DeleteFile *dirs_begin;
627 DeleteFile *dirs_end;
628 DeleteFile *files_begin;
629 DeleteFile *files_end;
630 } DeleteOp;
631
632 static int deletelist_add(
633 VFSContext *vfs,
634 const char *href,
635 const char *path,
636 VFSDir *parent,
637 struct stat *s,
638 void *userdata)
639 {
640 DeleteOp *op = userdata;
641
642
643 DeleteFile *file = cxMalloc(op->a,
sizeof(DeleteFile));
644 if(!file) {
645 return 1;
646 }
647 file->path = cx_strdup_a(op->a, cx_str((
char*)path)).ptr;
648 if(!file->path) {
649 return 1;
650 }
651 file->s = *s;
652 file->next =
NULL;
653
654
655 DeleteFile **begin;
656 DeleteFile **end;
657 if(
S_ISDIR(s->st_mode)) {
658 begin = &op->dirs_begin;
659 end = &op->dirs_end;
660 }
else {
661 begin = &op->files_begin;
662 end = &op->files_end;
663 }
664
665
666 cx_linked_list_add(
667 (
void**)begin, (
void**)end,
668 offsetof(DeleteFile, prev), offsetof(DeleteFile, next),
669 file);
670
671 return 0;
672 }
673
674 static int webdav_delete_collection(WebdavVFSOperation *op)
675 {
676 DeleteOp del;
677 ZERO(&del,
sizeof(DeleteOp));
678 del.a = pool_allocator(op->sn->pool);
679
680
681 if(webdav_op_iterate_children(op->vfs, -
1,
NULL, op->path,
682 deletelist_add, &del))
683 {
684 return 1;
685 }
686
687
688 DeleteFile root;
689 root.path = op->path;
690 root.s = *op->stat;
691 root.prev =
NULL;
692 root.next = del.dirs_begin;
693
694 if(del.dirs_begin) {
695 del.dirs_begin->prev = &root;
696 }
else {
697 del.dirs_end = &root;
698 }
699 del.dirs_begin = &root;
700
701
702 for(DeleteFile *file=del.files_begin;file;file=file->next) {
703 WebdavVFSOperation sub = webdav_vfs_sub_op(op, file->path, &file->s);
704 if(webdav_vfs_op_do(&sub,
WEBDAV_VFS_DELETE)) {
705 return 1;
706 }
707 }
708
709
710 for(DeleteFile *file=del.dirs_end;file;file=file->prev) {
711 WebdavVFSOperation sub = webdav_vfs_sub_op(op, file->path, &file->s);
712 if(webdav_vfs_op_do(&sub,
WEBDAV_VFS_DELETE)) {
713 return 1;
714 }
715 }
716
717 return 0;
718 }
719
720 int webdav_delete(pblock *pb, Session *sn, Request *rq) {
721 WebdavVFSOperation *op = webdav_vfs_op(sn, rq, rq->davCollection,
TRUE);
722 if(!op) {
723 return REQ_ABORTED;
724 }
725
726
727 struct stat s;
728 if(vfs_stat(op->vfs, op->path, &s)) {
729 sys_set_error_status(op->vfs);
730 return REQ_ABORTED;
731 }
732 op->stat = &s;
733
734 int ret;
735 if(
S_ISDIR(s.st_mode)) {
736 ret = webdav_delete_collection(op);
737 }
else {
738 ret = webdav_vfs_op_do(op,
WEBDAV_VFS_DELETE);
739 }
740
741
742 if(ret ==
REQ_PROCEED) {
743 pblock_nvinsert(
"content-length",
"0", rq->srvhdrs);
744 protocol_status(sn, rq,
204,
NULL);
745 protocol_start_response(sn, rq);
746 }
else {
747 protocol_status(sn, rq,
500,
NULL);
748 }
749
750 return ret;
751 }
752
753 int webdav_put(pblock *pb, Session *sn, Request *rq) {
754 char *path = pblock_findkeyval(pb_key_path, rq->vars);
755
756 VFSContext *vfs = vfs_request_context(sn, rq);
757 if(!vfs) {
758 protocol_status(sn, rq,
PROTOCOL_SERVER_ERROR,
NULL);
759 return REQ_ABORTED;
760 }
761
762 struct stat s;
763 int create_file =
0;
764 if(vfs_stat(vfs, path, &s)) {
765 if(vfs->vfs_errno ==
ENOENT) {
766 create_file =
O_CREAT;
767 }
else {
768 protocol_status(sn, rq, util_errno2status(vfs->vfs_errno),
NULL);
769 return REQ_ABORTED;
770 }
771 }
else if(
S_ISDIR(s.st_mode)) {
772
773 protocol_status(sn, rq,
PROTOCOL_METHOD_NOT_ALLOWED,
NULL);
774 return REQ_ABORTED;
775 }
776 vfs->error_response_set =
FALSE;
777
778 SYS_FILE fd = vfs_open(vfs, path,
O_WRONLY |
O_TRUNC | create_file);
779 if(!fd) {
780
781 return REQ_ABORTED;
782 }
783
784
785
786
787
788 char *expect = pblock_findkeyval(pb_key_expect, rq->headers);
789 if(expect) {
790 if(!strcasecmp(expect,
"100-continue")) {
791 if(http_send_continue(sn)) {
792 return REQ_ABORTED;
793 }
794 }
795 }
796
797 char in[
4096];
798 int r;
799 while((r = netbuf_getbytes(sn->inbuf, in,
2048)) >
0) {
800 int w =
0;
801 while(w < r) {
802 w += system_fwrite(fd, in, r);
803 }
804 }
805
806 system_fclose(fd);
807
808 int status = create_file ?
PROTOCOL_CREATED :
PROTOCOL_NO_CONTENT;
809 pblock_nvinsert(
"content-length",
"0", rq->srvhdrs);
810 protocol_status(sn, rq, status,
NULL);
811 protocol_start_response(sn, rq);
812
813 return REQ_PROCEED;
814 }
815
816 int webdav_copy(pblock *pb, Session *sn, Request *rq) {
817 char *path = pblock_findkeyval(pb_key_path, rq->vars);
818 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
819
820 char *destination = pblock_findval(
"destination", rq->headers);
821 if(!destination) {
822 protocol_status(sn, rq,
PROTOCOL_BAD_REQUEST,
NULL);
823 return REQ_ABORTED;
824 }
825
826 VFSContext *vfs = vfs_request_context(sn, rq);
827 if(!vfs) {
828 protocol_status(sn, rq,
PROTOCOL_SERVER_ERROR,
NULL);
829 return REQ_ABORTED;
830 }
831
832 struct stat src_s;
833 if(vfs_stat(vfs, path, &src_s)) {
834 protocol_status(sn, rq, util_errno2status(vfs->vfs_errno),
NULL);
835 return REQ_ABORTED;
836 }
837
838
839
840
841 return REQ_ABORTED;
842 }
843
844 int webdav_move(pblock *pb, Session *sn, Request *rq) {
845 return REQ_ABORTED;
846 }
847
848 int webdav_lock(pblock *pb, Session *sn, Request *rq) {
849 return REQ_ABORTED;
850 }
851
852 int webdav_unlock(pblock *pb, Session *sn, Request *rq) {
853 return REQ_ABORTED;
854 }
855
856 int webdav_report(pblock *pb, Session *sn, Request *rq) {
857 return REQ_ABORTED;
858 }
859
860 int webdav_acl(pblock *pb, Session *sn, Request *rq) {
861 return REQ_ABORTED;
862 }
863
864
865
866
867
868 int default_propfind_init(
869 WebdavPropfindRequest *rq,
870 const char* path,
871 const char *href,
872 WebdavPList **outplist)
873 {
874 DefaultWebdavData *data = pool_malloc(
875 rq->sn->pool,
876 sizeof(DefaultWebdavData));
877 if(!data) {
878 return 1;
879 }
880 rq->userdata = data;
881
882 data->vfsproperties = webdav_vfs_properties(outplist,
TRUE, rq->allprop,
0);
883
884 return 0;
885 }
886
887 int default_propfind_do(
888 WebdavPropfindRequest *request,
889 WebdavResponse *response,
890 VFS_DIR parent,
891 WebdavResource *resource,
892 struct stat *s)
893 {
894 DefaultWebdavData *data = request->userdata;
895
896 if(!s) {
897
898
899
900
901 return 1;
902 }
903
904
905 if(webdav_add_vfs_properties(
906 resource,
907 request->sn->pool,
908 data->vfsproperties,
909 s))
910 {
911 return 1;
912 }
913
914 return 0;
915 }
916
917 int default_propfind_finish(WebdavPropfindRequest *rq) {
918 return 0;
919 }
920
921 int default_proppatch_do(
922 WebdavProppatchRequest *request,
923 WebdavResource *response,
924 VFSFile *file,
925 WebdavPList **setInOut,
926 WebdavPList **removeInOut)
927 {
928 return 0;
929 }
930
931 int default_proppatch_finish(
932 WebdavProppatchRequest *request,
933 WebdavResource *response,
934 VFSFile *file,
935 WSBool commit)
936 {
937 return 0;
938 }
939
940
941
942
943
944 CxHashKey webdav_property_key_a(
const CxAllocator *a,
const char *ns,
const char *name) {
945 CxHashKey key;
946 cxmutstr data = cx_asprintf(
"%s\n%s", name, ns);
947 if(data.ptr) {
948 key.data = data.ptr;
949 key.len = data.length;
950 cx_hash_murmur(&key);
951 }
else {
952 key.data =
NULL;
953 key.len =
0;
954 key.hash =
0;
955 }
956 return key;
957 }
958
959 CxHashKey webdav_property_key(
const char *ns,
const char *name) {
960 return webdav_property_key_a(cxDefaultAllocator, ns, name);
961 }
962
963
964
965 int webdav_getdepth(Request *rq) {
966 char *depth_str = pblock_findkeyval(pb_key_depth, rq->headers);
967 int depth =
0;
968 if(depth_str) {
969 size_t dlen = strlen(depth_str);
970 if(!memcmp(depth_str,
"infinity", dlen)) {
971 depth = -
1;
972 }
else if(dlen ==
1 && depth_str[
0] ==
'1') {
973 depth =
1;
974 }
975 }
976 return depth;
977 }
978
979 int webdav_plist_add(
980 pool_handle_t *pool,
981 WebdavPList **begin,
982 WebdavPList **end,
983 WebdavProperty *prop)
984 {
985 WebdavPList *elm = pool_malloc(pool,
sizeof(WebdavPList));
986 if(!elm) {
987 return 1;
988 }
989 elm->prev = *end;
990 elm->next =
NULL;
991 elm->property = prop;
992
993 if(!*begin) {
994 *begin = elm;
995 *end = elm;
996 return 0;
997 }
998
999 (*end)->next = elm;
1000 *end = elm;
1001
1002 return 0;
1003 }
1004
1005 WebdavPList* webdav_plist_clone(
pool_handle_t *pool, WebdavPList *list) {
1006 return webdav_plist_clone_s(pool, list,
NULL);
1007 }
1008
1009 WebdavPList* webdav_plist_clone_s(
1010 pool_handle_t *pool,
1011 WebdavPList *list,
1012 size_t *newlen)
1013 {
1014 WebdavPList *new_list =
NULL;
1015 WebdavPList *new_list_end =
NULL;
1016
1017 size_t len =
0;
1018
1019 WebdavPList *elm = list;
1020 while(elm) {
1021
1022 WebdavPList *new_elm = pool_malloc(pool,
sizeof(WebdavPList));
1023 if(!new_elm) {
1024 if(newlen) *newlen =
0;
1025 return NULL;
1026 }
1027 new_elm->property = elm->property;
1028 new_elm->prev = new_list_end;
1029 new_elm->next =
NULL;
1030
1031 if(new_list_end) {
1032 new_list_end->next = new_elm;
1033 }
else {
1034 new_list = new_elm;
1035 }
1036 new_list_end = new_elm;
1037
1038 len++;
1039 elm = elm->next;
1040 }
1041
1042 if(newlen) *newlen = len;
1043 return new_list;
1044 }
1045
1046 size_t webdav_plist_size(WebdavPList *list) {
1047 size_t count =
0;
1048 WebdavPList *elm = list;
1049 while(elm) {
1050 count++;
1051 elm = elm->next;
1052 }
1053 return count;
1054 }
1055
1056 WebdavPListIterator webdav_plist_iterator(WebdavPList **list) {
1057 WebdavPListIterator i;
1058 i.list = list;
1059 i.cur =
NULL;
1060 i.next = *list;
1061 i.index =
0;
1062 return i;
1063 }
1064
1065 int webdav_plist_iterator_next(WebdavPListIterator *i, WebdavPList **cur) {
1066 if(i->cur) {
1067 i->index++;
1068 }
1069
1070 i->cur = i->next;
1071 i->next = i->cur ? i->cur->next :
NULL;
1072 *cur = i->cur;
1073
1074 return i->cur !=
NULL;
1075 }
1076
1077 void webdav_plist_iterator_remove_current(WebdavPListIterator *i) {
1078 WebdavPList *cur = i->cur;
1079 if(cur->prev) {
1080 cur->prev->next = cur->next;
1081 if(cur->next) {
1082 cur->next->prev = cur->prev;
1083 }
1084 }
else {
1085 *i->list = cur->next;
1086 if(cur->next) {
1087 cur->next->prev =
NULL;
1088 }
1089 }
1090 }
1091
1092 int webdav_nslist_add(
1093 pool_handle_t *pool,
1094 WebdavNSList **begin,
1095 WebdavNSList **end,
1096 WSNamespace *ns)
1097 {
1098
1099 WebdavNSList *elm = pool_malloc(pool,
sizeof(WebdavNSList));
1100 if(!elm) {
1101 return 1;
1102 }
1103 elm->prev = *end;
1104 elm->next =
NULL;
1105 elm->namespace = ns;
1106
1107 if(!*begin) {
1108 *begin = elm;
1109 *end = elm;
1110 return 0;
1111 }
1112
1113 (*end)->next = elm;
1114 *end = elm;
1115
1116 return 0;
1117 }
1118
1119
1120 WSNamespace* webdav_dav_namespace(
void) {
1121 return &dav_namespace;
1122 }
1123
1124 WebdavProperty* webdav_resourcetype_collection(
void) {
1125 return &dav_resourcetype_collection;
1126 }
1127
1128 WebdavProperty* webdav_resourcetype_empty(
void) {
1129 return &dav_resourcetype_empty;
1130 }
1131
1132 WebdavProperty* webdav_dav_property(
1133 pool_handle_t *pool,
1134 const char *name)
1135 {
1136 WebdavProperty *property = pool_malloc(pool,
sizeof(WebdavProperty));
1137 if(!property) {
1138 return NULL;
1139 }
1140 memset(property,
0,
sizeof(WebdavProperty));
1141
1142 property->namespace = &dav_namespace;
1143 property->name = name;
1144 return property;
1145 }
1146
1147 int webdav_resource_add_dav_stringproperty(
1148 WebdavResource *res,
1149 pool_handle_t pool,
1150 const char *name,
1151 const char *str,
1152 size_t len)
1153 {
1154 WebdavProperty *property = webdav_dav_property(pool, name);
1155 if(!property) {
1156 return 1;
1157 }
1158
1159 property->name = pool_strdup(pool, name);
1160 if(!property->name) {
1161 return 1;
1162 }
1163
1164 char *value = pool_malloc(pool, len+
1);
1165 if(!value) {
1166 return 1;
1167 }
1168 memcpy(value, str, len);
1169 value[len] =
'\0';
1170 property->value.text.str = value;
1171 property->value.text.length = len;
1172 property->vtype =
WS_VALUE_TEXT;
1173
1174 return res->addproperty(res, property,
200);
1175 }
1176
1177 int webdav_resource_add_stringproperty(
1178 WebdavResource *res,
1179 pool_handle_t pool,
1180 const char *xmlns_prefix,
1181 const char *xmlns_href,
1182 const char *name,
1183 const char *str,
1184 size_t len)
1185 {
1186 WebdavProperty *property = pool_malloc(pool,
sizeof(WebdavProperty));
1187 if(!property) {
1188 return 1;
1189 }
1190 memset(property,
0,
sizeof(WebdavProperty));
1191
1192 property->name = pool_strdup(pool, name);
1193 if(!property->name) {
1194 return 1;
1195 }
1196
1197 xmlNs *ns = pool_malloc(pool,
sizeof(xmlNs));
1198 if(!ns) {
1199 return 1;
1200 }
1201 memset(ns,
0,
sizeof(xmlNs));
1202 ns->prefix = (
const xmlChar*)pool_strdup(pool, xmlns_prefix);
1203 ns->href = (
const xmlChar*)pool_strdup(pool, xmlns_href);
1204 if(!ns->prefix || !ns->href) {
1205 return 1;
1206 }
1207
1208 char *value = pool_malloc(pool, len+
1);
1209 if(!value) {
1210 return 1;
1211 }
1212 memcpy(value, str, len);
1213 value[len] =
'\0';
1214 property->value.text.str = value;
1215 property->value.text.length = len;
1216 property->vtype =
WS_VALUE_TEXT;
1217
1218 property->value.text.str = value;
1219 property->value.text.length = len;
1220 property->vtype =
WS_VALUE_TEXT;
1221
1222 return res->addproperty(res, property,
200);
1223 }
1224
1225 int webdav_property_set_value(
1226 WebdavProperty *p,
1227 pool_handle_t *pool,
1228 char *value)
1229 {
1230 WSXmlNode *node = pool_malloc(pool,
sizeof(WSXmlNode));
1231 if(!node) {
1232 return 1;
1233 }
1234 ZERO(node,
sizeof(WSXmlNode));
1235
1236 node->content = (xmlChar*)value;
1237 node->type =
XML_TEXT_NODE;
1238
1239 p->value.node = node;
1240 p->vtype =
WS_VALUE_XML_NODE;
1241 return 0;
1242 }
1243
1244 WebdavVFSProperties webdav_vfs_properties(
1245 WebdavPList **plistInOut,
1246 WSBool removefromlist,
1247 WSBool allprop,
1248 uint32_t flags)
1249 {
1250 WebdavVFSProperties ret;
1251 ZERO(&ret,
sizeof(WebdavVFSProperties));
1252
1253 WSBool etag =
1;
1254 WSBool creationdate =
1;
1255
1256 WebdavPListIterator i = webdav_plist_iterator(plistInOut);
1257 WebdavPList *cur;
1258 while(webdav_plist_iterator_next(&i, &cur)) {
1259 WSNamespace *ns = cur->property->namespace;
1260 if(ns && !strcmp((
const char*)ns->href,
"DAV:")) {
1261 const char *name = cur->property->name;
1262 WSBool remove_prop = removefromlist;
1263 if(!strcmp(name,
"getlastmodified")) {
1264 ret.getlastmodified =
1;
1265 }
else if(!strcmp(name,
"getcontentlength")) {
1266 ret.getcontentlength =
1;
1267 }
else if(!strcmp(name,
"resourcetype")) {
1268 ret.getresourcetype =
1;
1269 }
else if(etag && !strcmp(name,
"getetag")) {
1270 ret.getetag =
1;
1271 }
else if(creationdate && !strcmp(name,
"creationdate")) {
1272 ret.creationdate =
1;
1273 }
else {
1274 remove_prop =
FALSE;
1275 }
1276
1277 if(remove_prop) {
1278 webdav_plist_iterator_remove_current(&i);
1279 }
1280 }
1281 }
1282
1283 if(allprop) {
1284 ret.creationdate =
1;
1285 ret.getcontentlength =
1;
1286 ret.getetag =
1;
1287 ret.getlastmodified =
1;
1288 ret.getresourcetype =
1;
1289 }
1290
1291 return ret;
1292 }
1293
1294 int webdav_add_vfs_properties(
1295 WebdavResource *res,
1296 pool_handle_t *pool,
1297 WebdavVFSProperties properties,
1298 struct stat *s)
1299 {
1300 if(properties.getresourcetype) {
1301 if(
S_ISDIR(s->st_mode)) {
1302 res->addproperty(res, &dav_resourcetype_collection,
200);
1303 }
else {
1304 res->addproperty(res, &dav_resourcetype_empty,
200);
1305 }
1306 }
1307 if(properties.getcontentlength) {
1308 char *buf = pool_malloc(pool,
64);
1309 if(!buf) {
1310 return 1;
1311 }
1312 uint64_t contentlength = s->st_size;
1313 snprintf(buf,
64,
"%" PRIu64, contentlength);
1314 if(webdav_resource_add_dav_stringproperty(res, pool,
"getcontentlength", buf, strlen(buf))) {
1315 return 1;
1316 }
1317 }
1318 if(properties.getlastmodified) {
1319 char *buf = pool_malloc(pool,
HTTP_DATE_LEN+
1);
1320 if(!buf) {
1321 return 1;
1322 }
1323 buf[
HTTP_DATE_LEN] =
0;
1324
1325 struct tm mtms;
1326 struct tm *mtm = system_gmtime(&s->st_mtime, &mtms);
1327
1328 if(mtm) {
1329 strftime(buf,
HTTP_DATE_LEN,
HTTP_DATE_FMT, mtm);
1330 if(webdav_resource_add_dav_stringproperty(res, pool,
"getlastmodified", buf, strlen(buf))) {
1331 return 1;
1332 }
1333 }
else {
1334 return 1;
1335 }
1336 }
1337 if(properties.creationdate) {
1338
1339 }
1340 if(properties.getetag) {
1341 char *buf = pool_malloc(pool,
96);
1342 if(!buf) {
1343 return 1;
1344 }
1345 snprintf(buf,
1346 96,
1347 "\"%x-%x\"",
1348 (
int)s->st_size,
1349 (
int)s->st_mtime);
1350 if(webdav_resource_add_dav_stringproperty(res, pool,
"getetag", buf, strlen(buf))) {
1351 return 1;
1352 }
1353 }
1354
1355 return 0;
1356 }
1357