src/server/webdav/webdav.c

changeset 30
27c7511c0e34
parent 29
e8619defde14
child 31
280250e45ba6
equal deleted inserted replaced
29:e8619defde14 30:27c7511c0e34
34 #include "../ucx/string.h" 34 #include "../ucx/string.h"
35 #include "../util/pool.h" 35 #include "../util/pool.h"
36 #include "../util/pblock.h" 36 #include "../util/pblock.h"
37 #include "../util/date.h" 37 #include "../util/date.h"
38 38
39 #include "../daemon/protocol.h"
40
39 #include "davparser.h" 41 #include "davparser.h"
40 42
41 int webdav_service(pblock *pb, Session *sn, Request *rq) { 43 int webdav_service(pblock *pb, Session *sn, Request *rq) {
42 char *method = pblock_findkeyval(pb_key_method, rq->reqpb); 44 char *method = pblock_findkeyval(pb_key_method, rq->reqpb);
43 if(method == NULL) { 45 if(method == NULL) {
48 return webdav_propfind(pb, sn, rq); 50 return webdav_propfind(pb, sn, rq);
49 } else if(!strcmp(method, "PROPPATCH")) { 51 } else if(!strcmp(method, "PROPPATCH")) {
50 return webdav_proppatch(pb, sn, rq); 52 return webdav_proppatch(pb, sn, rq);
51 } else if(!strcmp(method, "PUT")) { 53 } else if(!strcmp(method, "PUT")) {
52 return webdav_put(pb, sn, rq); 54 return webdav_put(pb, sn, rq);
55 } else if(!strcmp(method, "DELETE")) {
56 return webdav_delete(pb, sn, rq);
57 } else if(!strcmp(method, "MKCOL")) {
58 return webdav_mkcol(pb, sn, rq);
53 } 59 }
54 60
55 return REQ_NOACTION; 61 return REQ_NOACTION;
56 } 62 }
57 63
104 http_start_response(sn, rq); 110 http_start_response(sn, rq);
105 111
106 return REQ_PROCEED; 112 return REQ_PROCEED;
107 } 113 }
108 114
115 int webdav_delete(pblock *pb, Session *sn, Request *rq) {
116 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
117 char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars);
118
119 int status = 204;
120
121 struct stat st;
122 if(stat(ppath, &st) != 0) {
123 /* ERROR */
124 status = 403; /* TODO: check errno */
125 }
126
127 if(!strcmp(uri, "/")) {
128 status = 403;
129 } else if((st.st_mode & S_IFDIR) == S_IFDIR) {
130 if(rmdir(ppath) != 0) {
131 /* ERROR */
132 status = 403;
133 }
134 } else {
135 if(unlink(ppath) != 0) {
136 /* ERROR */
137 status = 403; /* TODO: check errno */
138 }
139 }
140
141 protocol_status(sn, rq, status, NULL);
142 pblock_removekey(pb_key_content_type, rq->srvhdrs);
143 pblock_nninsert("content-length", 0, rq->srvhdrs);
144 http_start_response(sn, rq);
145
146 return REQ_PROCEED;
147 }
148
149 int webdav_mkcol(pblock *pb, Session *sn, Request *rq) {
150 char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars);
151
152 int status = 201;
153 if(mkdir(ppath, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
154 status = 403;
155 }
156
157 protocol_status(sn, rq, status, NULL);
158 pblock_removekey(pb_key_content_type, rq->srvhdrs);
159 pblock_nninsert("content-length", 0, rq->srvhdrs);
160 http_start_response(sn, rq);
161
162 return REQ_ABORTED;
163 }
164
165 int webdav_copy(pblock *pb, Session *sn, Request *rq) {
166 return REQ_ABORTED;
167 }
168
169 int webdav_move(pblock *pb, Session *sn, Request *rq) {
170 return REQ_ABORTED;
171 }
172
109 int webdav_propfind(pblock *pb, Session *sn, Request *rq) { 173 int webdav_propfind(pblock *pb, Session *sn, Request *rq) {
110 /* TODO: clean up if errors occurs */ 174 /* TODO: clean up if errors occurs */
111 175
112 /* Get request body which contains the webdav XML request */ 176 /* Get request body which contains the webdav XML request */
113 char *xml_body; 177 char *xml_body;
160 char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars); 224 char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars);
161 225
162 struct stat st; 226 struct stat st;
163 if(stat(ppath, &st) != 0) { 227 if(stat(ppath, &st) != 0) {
164 perror("webdav_propfind: stat"); 228 perror("webdav_propfind: stat");
229 fprintf(stderr, " file: %s\n", ppath);
165 return REQ_ABORTED; 230 return REQ_ABORTED;
166 } 231 }
167 232
168 /* 233 /*
169 * if the requested webdav resource(file) is a directory, we create 234 * if the requested webdav resource(file) is a directory, we create
244 309
245 return REQ_PROCEED; 310 return REQ_PROCEED;
246 } 311 }
247 312
248 int webdav_proppatch(pblock *pb, Session *sn, Request *rq) { 313 int webdav_proppatch(pblock *pb, Session *sn, Request *rq) {
314 printf("webdav-proppatch\n");
249 /* TODO: clean up if errors occurs */ 315 /* TODO: clean up if errors occurs */
250 /* TODO: this is the same code as in propfind */ 316 /* TODO: this is the same code as in propfind */
317 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
318 if(uri == NULL) {
319 /* TODO: error */
320 return REQ_ABORTED;
321 }
251 322
252 /* Get request body which contains the webdav XML request */ 323 /* Get request body which contains the webdav XML request */
253 char *xml_body; 324 char *xml_body;
254 size_t xml_len = 0; 325 size_t xml_len = 0;
255 326
280 while((r = netbuf_getbytes(sn->inbuf, xb, xl)) != NETBUF_EOF) { 351 while((r = netbuf_getbytes(sn->inbuf, xb, xl)) != NETBUF_EOF) {
281 xb += r; 352 xb += r;
282 xl -= r; 353 xl -= r;
283 } 354 }
284 355
285 356 /*
357 * parse the xml request and create the proppatch object
358 */
359 ProppatchRequest *davrq = dav_parse_proppatch(sn, rq, xml_body, xml_len);
360 davrq->sn = sn;
361 davrq->rq = rq;
362 davrq->out = sbuf_new(512);
363 davrq->backend = create_property_backend();
364 davrq->propstat = propstat_create(sn->pool);
365
366 /* TODO: create prefixes for every namespace */
367 XmlNs *ns = xmlnsmap_get(davrq->nsmap, "DAV:");
368 ns->prefix = "D";
369 ns->prelen = 1;
370
371 /*
372 * begin multistatus response
373 *
374 * The webdav backend does the most work. The backend->proppatch function
375 * modifies the properties and adds status informations to the propstat
376 * member of the ProppatchRequest. All we have to do here is to create
377 * the xml response and send it to the client
378 */
379
380 /* write xml response header */
381 /* TODO: add possible xml namespaces */
382 sbuf_puts(davrq->out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
383 sbuf_puts(davrq->out, "<D:multistatus xmlns:D=\"DAV:\">\n");
384
385 sbuf_puts(davrq->out, "<D:response>\n<D:href>");
386 sbuf_puts(davrq->out, uri);
387 sbuf_puts(davrq->out, "</D:href>\n");
388
389 /* do proppatch operation */
390 davrq->backend->proppatch(davrq->backend, davrq);
391
392 propstat_write(davrq->propstat, davrq->out, 0);
393
394 sbuf_puts(davrq->out, "</D:response>\n");
395 sbuf_puts(davrq->out, "</D:multistatus>\n");
396
397
398 /* send the xml response to the client */
399 protocol_status(sn, rq, 207, "Multi Status");
400 pblock_removekey(pb_key_content_type, rq->srvhdrs);
401 pblock_nvinsert("content-type", "text/xml", rq->srvhdrs);
402 pblock_nninsert("content-length", davrq->out->length, rq->srvhdrs);
403
404 pblock_nvinsert("connection", "close", rq->srvhdrs);
405 http_start_response(sn, rq);
406
407 net_write(sn->csd, davrq->out->ptr, davrq->out->length);
286 408
287 return REQ_PROCEED; 409 return REQ_PROCEED;
288 } 410 }
289 411
290 void dav_resource_response(PropfindRequest *davrq, sstr_t path, sstr_t uri) { 412 void dav_resource_response(PropfindRequest *davrq, sstr_t path, sstr_t uri) {
366 DAVPropertyBackend* create_property_backend() { 488 DAVPropertyBackend* create_property_backend() {
367 DAVPropertyBackend *pb = malloc(sizeof(DAVPropertyBackend)); 489 DAVPropertyBackend *pb = malloc(sizeof(DAVPropertyBackend));
368 if(pb == NULL) { 490 if(pb == NULL) {
369 // 491 //
370 } 492 }
371 pb->propfind = dav_rq_propfind; 493 pb->propfind = dav_rq_propfind;
494 pb->proppatch = dav_rq_proppatch;
372 return pb; 495 return pb;
373 } 496 }
374 497
375 void dav_rq_propfind(DAVPropertyBackend *b, PropfindRequest *rq ,char *path) { 498 void dav_rq_propfind(DAVPropertyBackend *b, PropfindRequest *rq ,char *path) {
376 struct stat st; 499 struct stat st;
402 } else { 525 } else {
403 dav_propfind_add_prop_error(rq, prop, 404); 526 dav_propfind_add_prop_error(rq, prop, 404);
404 } 527 }
405 } 528 }
406 } 529 }
530
531 void dav_rq_proppatch(DAVPropertyBackend *b, ProppatchRequest *rq) {
532 DAV_FOREACH(p, rq->setProps) {
533 XmlElement *prop = (XmlElement*)p->data;
534 propstat_add(rq->propstat, 403, prop);
535 }
536
537 DAV_FOREACH(p, rq->removeProps) {
538 XmlElement *prop = (XmlElement*)p->data;
539 propstat_add(rq->propstat, 403, prop);
540 }
541 }
542
543
544
545 /*---------------------------------- utils ----------------------------------*/
546
547 /* XmlNsMap */
548
549 XmlNsMap* xmlnsmap_create() {
550 XmlNsMap *map = malloc(sizeof(XmlNsMap));
551 UcxMap *uxm = ucx_map_new(16);
552 if(map == NULL || uxm == NULL) {
553 return NULL;
554 }
555 map->map = uxm;
556 return map;
557 }
558
559 void xmlnsmap_free(XmlNsMap *map) {
560 /* TODO: implement */
561 }
562
563 XmlNs* xmlnsmap_put(XmlNsMap *map, char *ns) {
564 XmlNs *xmlns = xmlnsmap_get(map, ns);
565 if(xmlns != NULL) {
566 return xmlns;
567 }
568
569 xmlns = malloc(sizeof(XmlNs));
570 if(xmlns == NULL) {
571 return NULL;
572 }
573
574 xmlns->xmlns = ns;
575 xmlns->nslen = strlen(ns);
576
577 xmlns->prefix = NULL;
578 xmlns->prelen = 0;
579
580 ucx_map_cstr_put(map->map, ns, xmlns); /* TODO: check return value */
581 return xmlns;
582 }
583
584 XmlNs* xmlnsmap_get(XmlNsMap *map, char *ns) {
585 return ucx_map_cstr_get(map->map, ns);
586 }
587
588
589 /* XmlElement */
590
591 void xmlelm_add_child(XmlElement *parent, XmlElement *child) {
592 if(parent->ctlen == 0) {
593 parent->content = ucx_dlist_append(parent->content, child);
594 }
595 }
596
597 void xmlelm_write(XmlElement *elm, sbuf_t *out, int wv) {
598 sbuf_append(out, sstrn("<", 1));
599 sbuf_append(out, sstrn(elm->xmlns->prefix, elm->xmlns->prelen));
600 sbuf_append(out, sstrn(":", 1));
601 sbuf_append(out, elm->name);
602
603 if(wv) {
604 if(elm->ctlen == 0) {
605 if(elm->content == NULL) {
606 sbuf_append(out, sstrn(" />", 3));
607 } else {
608 sbuf_append(out, sstrn(">", 1));
609 DAV_FOREACH(pr, (UcxDlist*)elm->content) {
610 xmlelm_write((XmlElement*)pr->data, out, 1);
611 }
612 sbuf_append(out, sstrn("</", 2));
613 sbuf_append(out, sstrn(elm->xmlns->prefix, elm->xmlns->prelen));
614 sbuf_append(out, sstrn(":", 1));
615 sbuf_append(out, elm->name);
616 sbuf_append(out, sstrn(">", 1));
617 }
618 } else {
619 sbuf_append(out, sstrn(" />", 3));
620 sbuf_append(out, sstrn((char*)elm->content, elm->ctlen));
621 sbuf_append(out, sstrn("</", 2));
622 sbuf_append(out, sstrn(elm->xmlns->prefix, elm->xmlns->prelen));
623 sbuf_append(out, sstrn(":", 1));
624 sbuf_append(out, elm->name);
625 sbuf_append(out, sstrn(">", 1));
626 }
627 } else {
628 sbuf_append(out, sstrn(" />", 3));
629 }
630 }
631
632
633 /* PropstatMap */
634
635 Propstat* propstat_create(pool_handle_t *pool) {
636 Propstat *propstat = (Propstat*)pool_malloc(pool, sizeof(Propstat));
637 propstat->map = ucx_map_new(8);
638 propstat->okprop = NULL;
639 propstat->pool = pool;
640 return propstat;
641 }
642
643 void propstat_add(Propstat *propstat, int status, XmlElement *prop) {
644 if(status == 200) {
645 propstat->okprop = ucx_dlist_append(propstat->okprop, prop);
646 } else {
647 UcxKey key;
648 key.data = &status;
649 key.len = sizeof(int);
650
651 UcxDlist *list = ucx_map_get(propstat->map, key);
652 list = ucx_dlist_append(list, prop);
653
654 ucx_map_put(propstat->map, key, list);
655 }
656 }
657
658 void propstat_write(Propstat *propstat, sbuf_t *out, int wv) {
659 if(propstat->okprop) {
660 sbuf_puts(out, "<D:propstat>\n<D:prop>\n");
661
662 DAV_FOREACH(prop, propstat->okprop) {
663 xmlelm_write((XmlElement*)prop->data, out, wv);
664 }
665
666 sbuf_puts(out, "\n</D:prop>\n<D:status>HTTP/1.1 200 OK</D:status>\n");
667 sbuf_puts(out, "</D:propstat>\n");
668 }
669
670 for(int i=0;i<propstat->map->size;i++) {
671 UcxMapElement *elm = &propstat->map->map[i];
672 while(elm) {
673 UcxDlist *proplist = (UcxDlist*)elm->data;
674
675 if(proplist) {
676 sbuf_puts(out, "<D:propstat>\n<D:prop>\n");
677
678 DAV_FOREACH(prop, proplist) {
679 xmlelm_write((XmlElement*)prop->data, out, wv);
680 }
681
682 sbuf_puts(out, "\n</D:prop>\n<D:status>");
683
684 int status = *(int*)elm->key.data;
685 if(status < 1000 && status > 0) {
686 char buf[5];
687 buf[4] = 0;
688 sprintf(buf, "%d ", status);
689 sbuf_puts(out, "HTTP/1.1 ");
690 sbuf_puts(out, buf);
691 sbuf_puts(out, (char*)protocol_status_message(status));
692 }
693
694 sbuf_puts(out, "</D:status>\n</D:propstat>\n");
695 }
696
697 elm = elm->next;
698 }
699 }
700 }

mercurial