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; |
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) { |
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 } |