src/server/webdav/webdav.c

changeset 26
37ff8bf54b89
parent 24
1a7853a4257e
child 27
05b7576dca2b
--- a/src/server/webdav/webdav.c	Sat Feb 25 12:43:26 2012 +0100
+++ b/src/server/webdav/webdav.c	Sun Feb 26 19:51:14 2012 +0100
@@ -38,13 +38,10 @@
 #include "davparser.h"
 
 int webdav_service(pblock *pb, Session *sn, Request *rq) {
-    /* TODO:
-     * Dies ist die Implementierung für PROPFIND. Es sollte für jede webdav-
-     * Methode eine eigene Service-Funktion geben. Solange die anderen
-     * Methoden nicht implementiert werden, behandelt webdav_service nur
-     * PROPFIND.
-     */
+    return webdav_propfind(pb, sn, rq);
+}
 
+int webdav_propfind(pblock *pb, Session *sn, Request *rq) {
     /* TODO: clean up if errors occurs */
 
     /* Get request body which contains the webdav XML request */
@@ -61,6 +58,9 @@
     }
 
     xml_body = pool_malloc(sn->pool, xml_len + 1);
+    if(xml_body == NULL) {
+        return REQ_ABORTED;
+    }
     xml_body[xml_len] = 0;
     if(!xml_body) {
         /* server error */
@@ -77,182 +77,198 @@
         xl -= xml_len;
     }
 
+    /*
+     * get requested properties and initialize some stuff
+     */
     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();
-    davrq->notFoundProps = NULL;
-    davrq->forbiddenProps = NULL;
-    davrq->out = sbuf_new(512);
-
-    /* write header */
+    
+    /* 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");
-
-    /* get stat of file */
+    
+    /* begin multistatus response */
+    int is_dir = 0;
+    char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
     char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars);
-    char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
-
+    
     struct stat st;
     if(stat(ppath, &st) != 0) {
-        perror("webdav_service: stat");
+        perror("webdav_propfind: stat");
         return REQ_ABORTED;
-    }
-    /* TODO: check for more modes */
+    } 
+    
+    /*
+     * if the requested webdav resource(file) is a directory, we create
+     * a response for every child
+     */
     if(S_ISDIR(st.st_mode)) {
         DIR *dir = opendir(ppath);
         if(dir == NULL) {
             protocol_status(sn, rq, 500, NULL);
-            printf("webdav_service: DIR is null\n");
+            printf("webdav_propfind: DIR is null\n");
             return REQ_ABORTED;
         }
-
+        
         struct dirent *f;
         while((f = readdir(dir)) != NULL) {
             if(strcmp(f->d_name, ".") == 0 || strcmp(f->d_name, "..") == 0) {
                 continue;
             }
-
+            
             sstr_t filename = sstr(f->d_name);
-            sstr_t _path = sstr(ppath);
+            sstr_t _path = sstr(ppath); 
             sstr_t _uri = sstr(uri);
-
+            
             sstr_t newuri;
             newuri.length = filename.length + _uri.length;
             newuri.ptr = alloca(newuri.length + 1);
             newuri = sstrncat(2, newuri, _uri, filename);
-
+            
             sstr_t newpath;
             newpath.length = _path.length + filename.length;
             newpath.ptr = alloca(newpath.length + 1);
             newpath = sstrncat(2, newpath, _path, filename);
-
-            davrq->path = newpath.ptr;
-            davrq->uri = newuri.ptr;
-            dav_create_response(davrq);
+            
+            /* child response */
+            dav_resource_response(davrq, newpath, newuri);
         }
     }
-    davrq->path = ppath;
-    davrq->uri = uri;
-    dav_create_response(davrq);
-
+    
+    /* create the response for the requested resource */
+    dav_resource_response(davrq, sstr(ppath), sstr(uri));
+    
+    /* end xml */
     sbuf_puts(davrq->out, "</D:multistatus>\n");
-
-    /* send buffer to client */
+    
+    /* 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);
-
-    protocol_status(sn, rq, 207, NULL);
+    
+    pblock_nvinsert("connection", "close", rq->srvhdrs);
     http_start_response(sn, rq);
-
+    
     net_write(sn->csd, davrq->out->ptr, davrq->out->length);
+    
+    
 
+    
     return REQ_PROCEED;
 }
 
-int dav_foreach_reqprop(UcxDlist *list, PropfindRequest *davrq) {
-    DavProperty *prop = list->data;
-    int error = 0;
+void dav_resource_response(PropfindRequest *davrq, sstr_t path, sstr_t uri) {
+    printf("dav_resource_response %s %s\n", sstrdub(path).ptr, sstrdub(uri).ptr);
+    
+    sbuf_puts(davrq->out, "<D:response>\n");
+    sbuf_puts(davrq->out, "<D:href>");
+    sbuf_append(davrq->out, uri);
+    sbuf_puts(davrq->out, "</D:href>\n");
     
-    char *str = davrq->propertyBackend->get_property(
-            davrq->propertyBackend,
-            davrq,
-            davrq->path,
-            prop->xmlns,
-            prop->name,
-            &error);
-    if(str == NULL) {
-        UcxDlist **dl = NULL;
-        if(error == 404) {
-            dl = &davrq->notFoundProps;
-        } else {
-            dl = &davrq->forbiddenProps;
-        }
-        *dl = ucx_dlist_append(*dl, prop);
-    } else {
-        //printf("dav property: {%s|%s::%s\n", prop->xmlns, prop->name, str);
-        sbuf_puts(davrq->out, "<D:");
-        sbuf_puts(davrq->out, prop->name);
-        sbuf_puts(davrq->out, ">");
-        sbuf_puts(davrq->out, str);
-        sbuf_puts(davrq->out, "</D:");
-        sbuf_puts(davrq->out, prop->name);
-        sbuf_puts(davrq->out, ">\n");
+    davrq->propertyBackend->propfind(davrq->propertyBackend, davrq, path.ptr);
+    
+    if(davrq->prop) {
+        /* 
+         * there are some properties written, so we close the
+         * prop and propstat tag
+         */
+        sbuf_puts(davrq->out, "</D:prop>\n");
+        sbuf_puts(davrq->out, "<D:status>HTTP/1.1 200 OK</D:status>\n");
+        sbuf_puts(davrq->out, "</D:propstat>\n");
     }
-    return 0;
-}
-
-void dav_create_response(PropfindRequest *davrq) {
-    sbuf_puts(davrq->out, "<D:response>\n");
-
-    sbuf_puts(davrq->out, "<D:href>");
-    sbuf_puts(davrq->out, davrq->uri);
-    sbuf_puts(davrq->out, "</D:href>\n");
-
-    sbuf_puts(davrq->out, "<D:propstat>\n<D:prop>\n");
     
-    ucx_dlist_foreach(
-            davrq->properties,
-            (ucx_callback)dav_foreach_reqprop,
-            davrq);
-
-    sbuf_puts(davrq->out, "</D:prop>\n<D:status>HTTP/1.1 200 OK</D:status>\n");
-    sbuf_puts(davrq->out, "</D:propstat>\n");
-
-    /* 404 props */
-    sbuf_puts(davrq->out, "<D:propstat>\n<D:prop>\n");
-    UcxDlist *dl = davrq->notFoundProps;
-    while(dl != NULL) {
-        DavProperty *nfp = dl->data;
-        sbuf_puts(davrq->out, "<D:");
-        sbuf_puts(davrq->out, nfp->name);
-        sbuf_puts(davrq->out, " />\n");
-        dl = dl->next;
+    if(davrq->notFoundProps != NULL) {
+        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_puts(davrq->out, prop->name);
+            sbuf_puts(davrq->out, " />\n");
+        }
+        sbuf_puts(davrq->out, "</D:prop>\n");
+        sbuf_puts(davrq->out, "<D:status>HTTP/1.1 404 Not Found</D:status>\n");
+        sbuf_puts(davrq->out, "</D:propstat>\n");
     }
-    sbuf_puts(davrq->out, "</D:prop>\n");
-    sbuf_puts(davrq->out, "<D:status>HTTP/1.1 404 Not Found</D:status>\n");
-    sbuf_puts(davrq->out, "</D:propstat>\n");
-
-    /* end */
+    
     sbuf_puts(davrq->out, "</D:response>\n");
     
+    /* reset */
+    davrq->prop = 0;
+    davrq->notFoundProps = NULL;
+    davrq->forbiddenProps = NULL;
+    
 }
 
-char* dav_get_property(
-        DAVPropertyBackend *b,
+void dav_propfind_add_str_prop(
         PropfindRequest *davrq,
-        char *path,
-        char *xmlns,
-        char *name,
-        int *error)
+        DavProperty* prop,
+        char *str,
+        size_t len)
 {
-    DAVDefaultBackend *be = (DAVDefaultBackend*)b;
-    *error = 200;
+    if(!davrq->prop) {
+        sbuf_puts(davrq->out, "<D:propstat>\n<D:prop>\n");
+        davrq->prop = 1;
+    }
+    
+    sbuf_puts(davrq->out, "<D:");
+    sbuf_puts(davrq->out, prop->name);
+    sbuf_puts(davrq->out, ">");
+    
+    sbuf_append(davrq->out, sstrn(str, len));
+    
+    sbuf_puts(davrq->out, "</D:");
+    sbuf_puts(davrq->out, prop->name);
+    sbuf_puts(davrq->out, ">\n");
+}
 
-    if(strcmp(name, "getcontentlength") == 0) {
-        struct stat s;
-        if(stat(davrq->path, &s) != 0) {
-            *error = 403; /* really? */
-            return NULL;
-        }
-        if(S_ISDIR(s.st_mode)) {
-            *error = 404;
-            return NULL;
-        }
-        char *buf = pool_malloc(davrq->sn->pool, 24);
-        sprintf(buf, "%d", s.st_size);
-        return buf;
-    }
-
-    *error = 404;
-    return NULL;
+void dav_propfind_add_prop_error(
+        PropfindRequest *davrq,
+        DavProperty *prop,
+        int error)
+{
+    davrq->notFoundProps = ucx_dlist_append(davrq->notFoundProps, prop);
 }
 
+
+
+
+/* WebDAV Default Backend */
 DAVPropertyBackend* create_property_backend() {
-    DAVDefaultBackend *backend = malloc(sizeof(DAVDefaultBackend));
-    backend->backend.get_property = dav_get_property;
-    backend->path = NULL;
-    backend->s = 0;
-    return (DAVPropertyBackend*)backend;
+    DAVPropertyBackend *pb = malloc(sizeof(DAVPropertyBackend));
+    if(pb == NULL) {
+        //
+    }
+    pb->propfind = dav_rq_propfind;
+    return pb;
 }
+
+void dav_rq_propfind(DAVPropertyBackend *b, PropfindRequest *rq ,char *path) {
+    struct stat st;
+    if(stat(path, &st) != 0) {
+        perror("dav_be_propfind");
+        fprintf(stderr, "Cannot get stat of file: %s\n", path);
+    }
+    
+    DAV_FOREACH(elm, rq->properties) {
+        DavProperty *prop = (DavProperty*)elm->data;
+        
+        char *s = prop->name;
+        if(!strcmp(s, "resourcetype")) {
+            if(S_ISDIR(st.st_mode)) {
+                dav_propfind_add_str_prop(rq, prop, "<D:collection/>", 15);
+            } else {
+                dav_propfind_add_str_prop(rq, prop, NULL, 0);
+            }
+        } else if(!strcmp(s, "getcontentlength") && !S_ISDIR(st.st_mode)) {
+            char buf[32];
+            size_t n = snprintf(buf, 32, "%d", st.st_size);
+            dav_propfind_add_str_prop(rq, prop, buf, n);
+        } else {
+            dav_propfind_add_prop_error(rq, prop, 404);
+        }
+    }
+}

mercurial