diff -r e8619defde14 -r 27c7511c0e34 src/server/webdav/webdav.c
--- a/src/server/webdav/webdav.c Wed May 16 12:47:28 2012 +0200
+++ b/src/server/webdav/webdav.c Thu May 24 12:51:52 2012 +0200
@@ -36,6 +36,8 @@
#include "../util/pblock.h"
#include "../util/date.h"
+#include "../daemon/protocol.h"
+
#include "davparser.h"
int webdav_service(pblock *pb, Session *sn, Request *rq) {
@@ -50,6 +52,10 @@
return webdav_proppatch(pb, sn, rq);
} else if(!strcmp(method, "PUT")) {
return webdav_put(pb, sn, rq);
+ } else if(!strcmp(method, "DELETE")) {
+ return webdav_delete(pb, sn, rq);
+ } else if(!strcmp(method, "MKCOL")) {
+ return webdav_mkcol(pb, sn, rq);
}
return REQ_NOACTION;
@@ -106,6 +112,64 @@
return REQ_PROCEED;
}
+int webdav_delete(pblock *pb, Session *sn, Request *rq) {
+ char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
+ char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars);
+
+ int status = 204;
+
+ struct stat st;
+ if(stat(ppath, &st) != 0) {
+ /* ERROR */
+ status = 403; /* TODO: check errno */
+ }
+
+ if(!strcmp(uri, "/")) {
+ status = 403;
+ } else if((st.st_mode & S_IFDIR) == S_IFDIR) {
+ if(rmdir(ppath) != 0) {
+ /* ERROR */
+ status = 403;
+ }
+ } else {
+ if(unlink(ppath) != 0) {
+ /* ERROR */
+ status = 403; /* TODO: check errno */
+ }
+ }
+
+ protocol_status(sn, rq, status, NULL);
+ pblock_removekey(pb_key_content_type, rq->srvhdrs);
+ pblock_nninsert("content-length", 0, rq->srvhdrs);
+ http_start_response(sn, rq);
+
+ return REQ_PROCEED;
+}
+
+int webdav_mkcol(pblock *pb, Session *sn, Request *rq) {
+ char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars);
+
+ int status = 201;
+ if(mkdir(ppath, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
+ status = 403;
+ }
+
+ protocol_status(sn, rq, status, NULL);
+ pblock_removekey(pb_key_content_type, rq->srvhdrs);
+ pblock_nninsert("content-length", 0, rq->srvhdrs);
+ http_start_response(sn, rq);
+
+ return REQ_ABORTED;
+}
+
+int webdav_copy(pblock *pb, Session *sn, Request *rq) {
+ return REQ_ABORTED;
+}
+
+int webdav_move(pblock *pb, Session *sn, Request *rq) {
+ return REQ_ABORTED;
+}
+
int webdav_propfind(pblock *pb, Session *sn, Request *rq) {
/* TODO: clean up if errors occurs */
@@ -162,6 +226,7 @@
struct stat st;
if(stat(ppath, &st) != 0) {
perror("webdav_propfind: stat");
+ fprintf(stderr, " file: %s\n", ppath);
return REQ_ABORTED;
}
@@ -246,8 +311,14 @@
}
int webdav_proppatch(pblock *pb, Session *sn, Request *rq) {
+ printf("webdav-proppatch\n");
/* TODO: clean up if errors occurs */
/* TODO: this is the same code as in propfind */
+ char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
+ if(uri == NULL) {
+ /* TODO: error */
+ return REQ_ABORTED;
+ }
/* Get request body which contains the webdav XML request */
char *xml_body;
@@ -282,7 +353,58 @@
xl -= r;
}
+ /*
+ * parse the xml request and create the proppatch object
+ */
+ ProppatchRequest *davrq = dav_parse_proppatch(sn, rq, xml_body, xml_len);
+ davrq->sn = sn;
+ davrq->rq = rq;
+ davrq->out = sbuf_new(512);
+ davrq->backend = create_property_backend();
+ davrq->propstat = propstat_create(sn->pool);
+ /* TODO: create prefixes for every namespace */
+ XmlNs *ns = xmlnsmap_get(davrq->nsmap, "DAV:");
+ ns->prefix = "D";
+ ns->prelen = 1;
+
+ /*
+ * begin multistatus response
+ *
+ * The webdav backend does the most work. The backend->proppatch function
+ * modifies the properties and adds status informations to the propstat
+ * member of the ProppatchRequest. All we have to do here is to create
+ * the xml response and send it to the client
+ */
+
+ /* write xml response header */
+ /* TODO: add possible xml namespaces */
+ sbuf_puts(davrq->out, "\n");
+ sbuf_puts(davrq->out, "\n");
+
+ sbuf_puts(davrq->out, "\n");
+ sbuf_puts(davrq->out, uri);
+ sbuf_puts(davrq->out, "\n");
+
+ /* do proppatch operation */
+ davrq->backend->proppatch(davrq->backend, davrq);
+
+ propstat_write(davrq->propstat, davrq->out, 0);
+
+ sbuf_puts(davrq->out, "\n");
+ sbuf_puts(davrq->out, "\n");
+
+
+ /* send the xml response to the client */
+ protocol_status(sn, rq, 207, "Multi Status");
+ pblock_removekey(pb_key_content_type, rq->srvhdrs);
+ pblock_nvinsert("content-type", "text/xml", rq->srvhdrs);
+ pblock_nninsert("content-length", davrq->out->length, rq->srvhdrs);
+
+ pblock_nvinsert("connection", "close", rq->srvhdrs);
+ http_start_response(sn, rq);
+
+ net_write(sn->csd, davrq->out->ptr, davrq->out->length);
return REQ_PROCEED;
}
@@ -368,7 +490,8 @@
if(pb == NULL) {
//
}
- pb->propfind = dav_rq_propfind;
+ pb->propfind = dav_rq_propfind;
+ pb->proppatch = dav_rq_proppatch;
return pb;
}
@@ -404,3 +527,174 @@
}
}
}
+
+void dav_rq_proppatch(DAVPropertyBackend *b, ProppatchRequest *rq) {
+ DAV_FOREACH(p, rq->setProps) {
+ XmlElement *prop = (XmlElement*)p->data;
+ propstat_add(rq->propstat, 403, prop);
+ }
+
+ DAV_FOREACH(p, rq->removeProps) {
+ XmlElement *prop = (XmlElement*)p->data;
+ propstat_add(rq->propstat, 403, prop);
+ }
+}
+
+
+
+/*---------------------------------- utils ----------------------------------*/
+
+/* XmlNsMap */
+
+XmlNsMap* xmlnsmap_create() {
+ XmlNsMap *map = malloc(sizeof(XmlNsMap));
+ UcxMap *uxm = ucx_map_new(16);
+ if(map == NULL || uxm == NULL) {
+ return NULL;
+ }
+ map->map = uxm;
+ return map;
+}
+
+void xmlnsmap_free(XmlNsMap *map) {
+ /* TODO: implement */
+}
+
+XmlNs* xmlnsmap_put(XmlNsMap *map, char *ns) {
+ XmlNs *xmlns = xmlnsmap_get(map, ns);
+ if(xmlns != NULL) {
+ return xmlns;
+ }
+
+ xmlns = malloc(sizeof(XmlNs));
+ if(xmlns == NULL) {
+ return NULL;
+ }
+
+ xmlns->xmlns = ns;
+ xmlns->nslen = strlen(ns);
+
+ xmlns->prefix = NULL;
+ xmlns->prelen = 0;
+
+ ucx_map_cstr_put(map->map, ns, xmlns); /* TODO: check return value */
+ return xmlns;
+}
+
+XmlNs* xmlnsmap_get(XmlNsMap *map, char *ns) {
+ return ucx_map_cstr_get(map->map, ns);
+}
+
+
+/* XmlElement */
+
+void xmlelm_add_child(XmlElement *parent, XmlElement *child) {
+ if(parent->ctlen == 0) {
+ parent->content = ucx_dlist_append(parent->content, child);
+ }
+}
+
+void xmlelm_write(XmlElement *elm, sbuf_t *out, int wv) {
+ sbuf_append(out, sstrn("<", 1));
+ sbuf_append(out, sstrn(elm->xmlns->prefix, elm->xmlns->prelen));
+ sbuf_append(out, sstrn(":", 1));
+ sbuf_append(out, elm->name);
+
+ if(wv) {
+ if(elm->ctlen == 0) {
+ if(elm->content == NULL) {
+ sbuf_append(out, sstrn(" />", 3));
+ } else {
+ sbuf_append(out, sstrn(">", 1));
+ DAV_FOREACH(pr, (UcxDlist*)elm->content) {
+ xmlelm_write((XmlElement*)pr->data, out, 1);
+ }
+ sbuf_append(out, sstrn("", 2));
+ sbuf_append(out, sstrn(elm->xmlns->prefix, elm->xmlns->prelen));
+ sbuf_append(out, sstrn(":", 1));
+ sbuf_append(out, elm->name);
+ sbuf_append(out, sstrn(">", 1));
+ }
+ } else {
+ sbuf_append(out, sstrn(" />", 3));
+ sbuf_append(out, sstrn((char*)elm->content, elm->ctlen));
+ sbuf_append(out, sstrn("", 2));
+ sbuf_append(out, sstrn(elm->xmlns->prefix, elm->xmlns->prelen));
+ sbuf_append(out, sstrn(":", 1));
+ sbuf_append(out, elm->name);
+ sbuf_append(out, sstrn(">", 1));
+ }
+ } else {
+ sbuf_append(out, sstrn(" />", 3));
+ }
+}
+
+
+/* PropstatMap */
+
+Propstat* propstat_create(pool_handle_t *pool) {
+ Propstat *propstat = (Propstat*)pool_malloc(pool, sizeof(Propstat));
+ propstat->map = ucx_map_new(8);
+ propstat->okprop = NULL;
+ propstat->pool = pool;
+ return propstat;
+}
+
+void propstat_add(Propstat *propstat, int status, XmlElement *prop) {
+ if(status == 200) {
+ propstat->okprop = ucx_dlist_append(propstat->okprop, prop);
+ } else {
+ UcxKey key;
+ key.data = &status;
+ key.len = sizeof(int);
+
+ UcxDlist *list = ucx_map_get(propstat->map, key);
+ list = ucx_dlist_append(list, prop);
+
+ ucx_map_put(propstat->map, key, list);
+ }
+}
+
+void propstat_write(Propstat *propstat, sbuf_t *out, int wv) {
+ if(propstat->okprop) {
+ sbuf_puts(out, "\n\n");
+
+ DAV_FOREACH(prop, propstat->okprop) {
+ xmlelm_write((XmlElement*)prop->data, out, wv);
+ }
+
+ sbuf_puts(out, "\n\nHTTP/1.1 200 OK\n");
+ sbuf_puts(out, "\n");
+ }
+
+ for(int i=0;imap->size;i++) {
+ UcxMapElement *elm = &propstat->map->map[i];
+ while(elm) {
+ UcxDlist *proplist = (UcxDlist*)elm->data;
+
+ if(proplist) {
+ sbuf_puts(out, "\n\n");
+
+ DAV_FOREACH(prop, proplist) {
+ xmlelm_write((XmlElement*)prop->data, out, wv);
+ }
+
+ sbuf_puts(out, "\n\n");
+
+ int status = *(int*)elm->key.data;
+ if(status < 1000 && status > 0) {
+ char buf[5];
+ buf[4] = 0;
+ sprintf(buf, "%d ", status);
+ sbuf_puts(out, "HTTP/1.1 ");
+ sbuf_puts(out, buf);
+ sbuf_puts(out, (char*)protocol_status_message(status));
+ }
+
+ sbuf_puts(out, "\n\n");
+ }
+
+ elm = elm->next;
+ }
+ }
+}