src/server/webdav/webdav.c

changeset 27
05b7576dca2b
parent 26
37ff8bf54b89
child 29
e8619defde14
--- a/src/server/webdav/webdav.c	Sun Feb 26 19:51:14 2012 +0100
+++ b/src/server/webdav/webdav.c	Mon Feb 27 17:20:42 2012 +0100
@@ -34,11 +34,74 @@
 #include "../ucx/string.h"
 #include "../util/pool.h"
 #include "../util/pblock.h"
+#include "../util/date.h"
 
 #include "davparser.h"
 
 int webdav_service(pblock *pb, Session *sn, Request *rq) {
-    return webdav_propfind(pb, sn, rq);
+    char *method = pblock_findkeyval(pb_key_method, rq->reqpb);
+    if(method == NULL) {
+        return REQ_ABORTED;
+    }
+    
+    if(!strcmp(method, "PROPFIND")) {
+        return webdav_propfind(pb, sn, rq);
+    } else if(!strcmp(method, "PUT")) {
+        return webdav_put(pb, sn, rq);
+    }
+    
+    return REQ_NOACTION;
+}
+
+int webdav_put(pblock *pb, Session *sn, Request *rq) {
+    int length = 0;
+    
+    char *ctlen = pblock_findkeyval(pb_key_content_length, rq->headers);
+    if(ctlen) {
+        length = atoi(ctlen);
+    } else {
+        /* invalid request */
+        printf("invalid request\n");
+        return REQ_ABORTED;
+    }
+    
+    printf("PUT length: %d\n", length);
+    
+    int status = 204;
+    if(length >= 0) {
+        char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars);
+        
+        FILE *out = fopen(ppath, "w");
+        if(out == NULL) {
+            fprintf(stderr, "fopen(%s, \"w\") failed\n", ppath);
+            return REQ_ABORTED;
+        }
+        setvbuf(out, NULL, _IONBF, 0);
+        
+        size_t l = (length > 4096) ? (4096) : (length);
+        char *buffer = malloc(l);
+        
+        int r;
+        int r2 = 0;
+        while(r2 < length) {
+            r = netbuf_getbytes(sn->inbuf, buffer, l);
+            if(r == NETBUF_EOF) {
+                break;
+            }
+            fwrite(buffer, 1, r, out);
+            
+            r2 += r;
+        }
+        
+        fclose(out);
+    }
+    
+    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_propfind(pblock *pb, Session *sn, Request *rq) {
@@ -68,13 +131,13 @@
         return REQ_ABORTED;
     }
 
-    /* TODO: bug with multiple reads */
+    /* get request body */
     int r = 0;
     char *xb = xml_body;
     size_t xl = xml_len;
     while((r = netbuf_getbytes(sn->inbuf, xb, xl)) != NETBUF_EOF) {
         xb += r;
-        xl -= xml_len;
+        xl -= r;
     }
 
     /*
@@ -91,7 +154,6 @@
     sbuf_puts(davrq->out, "<D:multistatus xmlns:D=\"DAV:\">\n");
     
     /* 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);
     
@@ -122,16 +184,36 @@
             sstr_t filename = sstr(f->d_name);
             sstr_t _path = sstr(ppath); 
             sstr_t _uri = sstr(uri);
+            sstr_t ps;
+            sstr_t us;
+            ps.length = 0;
+            ps.ptr = NULL;
+            us.length = 0;
+            us.ptr = NULL;
+            if(_path.ptr[_path.length - 1] != '/') {
+                ps = sstrn("/", 1);
+            }
+            if(_uri.ptr[_uri.length - 1] != '/') {
+                us = sstrn("/", 1);
+            }
             
             sstr_t newuri;
-            newuri.length = filename.length + _uri.length;
+            newuri.length = filename.length + _uri.length + us.length;
             newuri.ptr = alloca(newuri.length + 1);
-            newuri = sstrncat(2, newuri, _uri, filename);
+            if(us.length == 1) {
+                newuri = sstrncat(3, newuri, _uri, us, filename);
+            } else {
+                newuri = sstrncat(2, newuri, _uri, filename);
+            }
             
             sstr_t newpath;
-            newpath.length = _path.length + filename.length;
+            newpath.length = _path.length + filename.length + ps.length;
             newpath.ptr = alloca(newpath.length + 1);
-            newpath = sstrncat(2, newpath, _path, filename);
+            if(ps.length == 1) {
+                newpath = sstrncat(3, newpath, _path, ps, filename);
+            } else {
+                newpath = sstrncat(2, newpath, _path, filename);
+            }
             
             /* child response */
             dav_resource_response(davrq, newpath, newuri);
@@ -267,6 +349,12 @@
             char buf[32];
             size_t n = snprintf(buf, 32, "%d", st.st_size);
             dav_propfind_add_str_prop(rq, prop, buf, n);
+        } else if(!strcmp(s, "getlastmodified")) {
+            sstr_t s = date_format_http(st.st_mtim.tv_sec, rq->sn->pool);
+            dav_propfind_add_str_prop(rq, prop, s.ptr, s.length);
+        } else if(!strcmp(s, "creationdate")) {
+            sstr_t s = date_format_iso8601(st.st_ctim.tv_sec, rq->sn->pool);
+            dav_propfind_add_str_prop(rq, prop, s.ptr, s.length);
         } else {
             dav_propfind_add_prop_error(rq, prop, 404);
         }

mercurial