src/server/webdav/webdav.c

changeset 59
ab25c0a231d0
parent 58
66c22e54aa90
child 64
c7f5b062e622
--- a/src/server/webdav/webdav.c	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/webdav/webdav.c	Mon May 06 13:44:27 2013 +0200
@@ -41,6 +41,39 @@
 #include "../daemon/protocol.h"
 
 #include "davparser.h"
+#include "persistence.h"
+
+static UcxMap *pmgr_map; // char*, PersistenceManager
+
+int webdav_init(pblock *pb, Session *sn, Request *rq) {
+    pmgr_map = ucx_map_new(8);
+    PersistenceManager *defaultmgr = create_property_backend();
+    ucx_map_cstr_put(pmgr_map, "default", defaultmgr);
+    return REQ_PROCEED;
+}
+
+void webdav_add_persistence_manager(char *name, PersistenceManager *mgr) {
+    if(!pmgr_map) {
+        webdav_init(NULL, NULL, NULL);
+    }
+    ucx_map_cstr_put(pmgr_map, name, mgr);
+}
+
+int webdav_setcollection(pblock *pb, Session *sn, Request *rq) {
+    //char *name = pblock_findkeyval(pb_key_name, pb);
+    char *db = pblock_findval("db", pb);
+    
+    if(!db) {
+        db = "default";
+    }
+    
+    // setup DavCollection
+    DavCollection *dav = pool_malloc(sn->pool, sizeof(DavCollection));
+    dav->mgr = ucx_map_cstr_get(pmgr_map, db);
+    rq->davCollection = dav;
+    
+    return REQ_NOACTION;
+}
 
 int webdav_service(pblock *pb, Session *sn, Request *rq) {
     char *method = pblock_findkeyval(pb_key_method, rq->reqpb);
@@ -217,26 +250,30 @@
     /*
      * get requested properties and initialize some stuff
      */
+    DavCollection *collection = rq->davCollection;
+    
     PropfindRequest *davrq = dav_parse_propfind(sn, rq, xml_body, xml_len);
     davrq->sn = sn;
     davrq->rq = rq;
     davrq->out = sbuf_new(512);
-    davrq->propertyBackend = create_property_backend();
-    
-    /* write xml response header */
-    sbuf_puts(davrq->out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
-    sbuf_puts(davrq->out, "<D:multistatus xmlns:D=\"DAV:\">\n");
+    davrq->persistencemgr = collection->mgr;
     
     /* begin multistatus response */
     char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
     char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars);
+    davrq->uri = uri;
+    davrq->path = ppath;
     
     VFSContext *vfs = vfs_request_context(sn, rq);
     
     struct stat st;
     if(vfs_stat(vfs, ppath, &st) != 0) {
         return REQ_ABORTED;
-    } 
+    }
+    
+    // begin propfind
+    davrq->isdir = S_ISDIR(st.st_mode);
+    davrq->persistencemgr->propfind_begin(davrq->persistencemgr, davrq);
     
     /*
      * if the requested webdav resource(file) is a directory, we create
@@ -257,26 +294,49 @@
         }
     }
     
-    /* create the response for the requested resource */
+    // create the response for the requested resource
     dav_resource_response(davrq, sstr(ppath), sstr(uri));
     
-    /* end xml */
+    // end propfind
+    davrq->persistencemgr->propfind_begin(davrq->persistencemgr, davrq);
+    
+    // end xml
     sbuf_puts(davrq->out, "</D:multistatus>\n");
     
-    /* send the xml response to the client */
+    //printf("%s\n", davrq->out->ptr);
+    
+    // write xml response header
+    sbuf_t *out = sbuf_new(256);
+    sbuf_puts(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
+    sbuf_puts(out, "<D:multistatus");
+    UcxMapIterator nsiter = ucx_map_iterator(davrq->nsmap->map);
+    XmlNs *ns;
+    UCX_MAP_FOREACH(ns, nsiter) {
+        sbuf_puts(out, " xmlns:");
+        sbuf_puts(out, ns->prefix);
+        sbuf_puts(out, "=\"");
+        sbuf_puts(out, ns->xmlns);
+        sbuf_puts(out, "\"");
+    }
+    sbuf_puts(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_nninsert(
+            "content-length",
+            out->length + davrq->out->length,
+            rq->srvhdrs);
     
-    //pblock_nvinsert("connection", "close", rq->srvhdrs);
     http_start_response(sn, rq);
     
-    //printf("%s\n", davrq->out->ptr);
-    ssize_t nr = net_write(sn->csd, davrq->out->ptr, davrq->out->length);
-    //printf("net_write returned: %d\n", r);
+    // write content
+    size_t nr;
+    nr = net_write(sn->csd, out->ptr, out->length);
+    nr = net_write(sn->csd, davrq->out->ptr, davrq->out->length);
     
-    
+    sbuf_free(out);
     dav_free_propfind(davrq);
     
     return REQ_PROCEED;
@@ -292,7 +352,7 @@
         return REQ_ABORTED;
     }
 
-    /* Get request body which contains the webdav XML request */
+    // Get request body which contains the webdav XML request
     char   *xml_body;
     size_t xml_len = 0;
 
@@ -300,7 +360,7 @@
     if(ctlen) {
         xml_len = atoi(ctlen);
     } else {
-        /* invalid request */
+        // invalid request
         printf("invalid request\n");
         return REQ_ABORTED;
     }
@@ -311,12 +371,12 @@
     }
     xml_body[xml_len] = 0;
     if(!xml_body) {
-        /* server error */
+        // server error
         printf("server error\n");
         return REQ_ABORTED;
     }
 
-    /* get request body */
+    // get request body
     int r = 0;
     char *xb = xml_body;
     size_t xl = xml_len;
@@ -328,17 +388,15 @@
     /*
      * parse the xml request and create the proppatch object
      */
+    DavCollection *collection = rq->davCollection;
+    
     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->backend = collection->mgr;
     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
@@ -350,9 +408,19 @@
      */ 
     
     /* write xml response header */
-    /* TODO: add possible xml namespaces */
     sbuf_puts(davrq->out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
-    sbuf_puts(davrq->out, "<D:multistatus xmlns:D=\"DAV:\">\n");
+    //sbuf_puts(davrq->out, "<D:multistatus xmlns:D=\"DAV:\">\n");
+    sbuf_puts(davrq->out, "<D:multistatus");
+    UcxMapIterator nsiter = ucx_map_iterator(davrq->nsmap->map);
+    XmlNs *ns;
+    UCX_MAP_FOREACH(ns, nsiter) {
+        sbuf_puts(davrq->out, " xmlns:");
+        sbuf_puts(davrq->out, ns->prefix);
+        sbuf_puts(davrq->out, "=\"");
+        sbuf_puts(davrq->out, ns->xmlns);
+        sbuf_puts(davrq->out, "\"");
+    }
+    sbuf_puts(davrq->out, ">\n");
     
     sbuf_puts(davrq->out, "<D:response>\n<D:href>");
     sbuf_puts(davrq->out, uri);
@@ -391,7 +459,11 @@
     sbuf_append(davrq->out, uri);
     sbuf_puts(davrq->out, "</D:href>\n");
     
-    davrq->propertyBackend->propfind(davrq->propertyBackend, davrq, path.ptr);
+    if(davrq->persistencemgr->vfs_props) {
+        // get some DAV properties from the file system
+        dav_rq_propfind(davrq->persistencemgr, davrq, path.ptr);
+    }
+    davrq->persistencemgr->propfind(davrq->persistencemgr, davrq, path.ptr);
     
     if(davrq->prop) {
         /* 
@@ -407,7 +479,10 @@
         sbuf_puts(davrq->out, "<D:propstat>\n<D:prop>\n");
         DAV_FOREACH(elm, davrq->notFoundProps) {
             DavProperty *prop = (DavProperty*)elm->data;
-            sbuf_puts(davrq->out, "<D:");
+            sbuf_put(davrq->out, '<');
+            sbuf_puts(davrq->out, prop->xmlns->prefix);
+            sbuf_put(davrq->out, ':');
+            
             sbuf_puts(davrq->out, prop->name);
             sbuf_puts(davrq->out, " />\n");
         }
@@ -436,13 +511,17 @@
         davrq->prop = 1;
     }
     
-    sbuf_puts(davrq->out, "<D:");
+    sbuf_put(davrq->out, '<');
+    sbuf_puts(davrq->out, prop->xmlns->prefix);
+    sbuf_put(davrq->out, ':');
     sbuf_puts(davrq->out, prop->name);
-    sbuf_puts(davrq->out, ">");
+    sbuf_put(davrq->out, '>');
     
     sbuf_append(davrq->out, sstrn(str, len));
     
-    sbuf_puts(davrq->out, "</D:");
+    sbuf_puts(davrq->out, "</");
+    sbuf_puts(davrq->out, prop->xmlns->prefix);
+    sbuf_put(davrq->out, ':');
     sbuf_puts(davrq->out, prop->name);
     sbuf_puts(davrq->out, ">\n");
 }
@@ -460,16 +539,19 @@
 
 
 /* WebDAV Default Backend */
-static DAVPropertyBackend dav_file_backend = {
+static PersistenceManager dav_file_backend = {
+    NULL,
+    NULL,
     dav_rq_propfind,
-    dav_rq_proppatch
+    dav_rq_proppatch,
+    0
 };
 
-DAVPropertyBackend* create_property_backend() {
+PersistenceManager* create_property_backend() {
     return &dav_file_backend;
 }
 
-void dav_rq_propfind(DAVPropertyBackend *b, PropfindRequest *rq ,char *path) {
+void dav_rq_propfind(PersistenceManager *b, PropfindRequest *rq ,char *path) {
     struct stat st;
     if(stat(path, &st) != 0) {
         perror("dav_be_propfind");
@@ -478,7 +560,7 @@
     
     if(rq->allprop) {
         DavProperty prop;
-        prop.xmlns = "DAV:";
+        prop.xmlns = xmlnsmap_get(rq->nsmap, "DAV:");
         
         prop.name = "resourcetype";
         if(S_ISDIR(st.st_mode)) {
@@ -531,7 +613,7 @@
     }
 }
 
-void dav_rq_proppatch(DAVPropertyBackend *b, ProppatchRequest *rq) {
+void dav_rq_proppatch(PersistenceManager *b, ProppatchRequest *rq) {
     DAV_FOREACH(p, rq->setProps) {
         XmlElement *prop = (XmlElement*)p->data;
         propstat_add(rq->propstat, 403, prop);
@@ -557,6 +639,17 @@
     }
     map->map = uxm;
     map->pool = pool;
+    map->num = 0;
+    
+    // create DAV: namespace
+    XmlNs *ns = pool_malloc(map->pool, sizeof(XmlNs));
+    ns->xmlns = "DAV:";
+    ns->prefix = "D";
+    ns->nslen = 4;
+    ns->prelen = 1;
+    
+    ucx_map_cstr_put(uxm, "DAV:", ns);
+    
     return map;
 }
 
@@ -575,13 +668,16 @@
         return NULL;
     }
     
-    xmlns->xmlns = ns;
-    xmlns->nslen = strlen(ns);
+    sstr_t newns = sstrdup(sstr(ns));
     
-    xmlns->prefix = NULL;
-    xmlns->prelen = 0;
+    xmlns->xmlns = newns.ptr;
+    xmlns->nslen = newns.length;
+    
+    xmlns->prefix = pool_calloc(map->pool, 1, 8);
+    xmlns->prelen = snprintf(xmlns->prefix, 7, "x%d", map->num);
     
     ucx_map_cstr_put(map->map, ns, xmlns); /* TODO: check return value */
+    map->num++;
     return xmlns;
 }
 
@@ -598,11 +694,11 @@
     }
 }
 
-void xmlelm_write(XmlElement *elm, sbuf_t *out, int wv) {
+void xmlelm_write(XmlElement *elm, Buffer *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);
+    sbuf_append(out, sstr(elm->name));
     
     if(wv) {
         if(elm->ctlen == 0) {
@@ -616,7 +712,7 @@
                 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, sstr(elm->name));
                 sbuf_append(out, sstrn(">", 1));
             }
         } else {
@@ -625,7 +721,7 @@
             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, sstr(elm->name));
             sbuf_append(out, sstrn(">", 1));
         }
     } else {
@@ -659,7 +755,7 @@
     }
 }
 
-void propstat_write(Propstat *propstat, sbuf_t *out, int wv) {
+void propstat_write(Propstat *propstat, Buffer *out, int wv) {
     if(propstat->okprop) {
         sbuf_puts(out, "<D:propstat>\n<D:prop>\n");
         

mercurial