new proppatch, mkcol and delete method

Thu, 24 May 2012 12:51:52 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Thu, 24 May 2012 12:51:52 +0200
changeset 30
27c7511c0e34
parent 29
e8619defde14
child 31
280250e45ba6

new proppatch, mkcol and delete method

src/server/daemon/config.c file | annotate | diff | comparison | revisions
src/server/daemon/config.h file | annotate | diff | comparison | revisions
src/server/daemon/event.c file | annotate | diff | comparison | revisions
src/server/daemon/event.h file | annotate | diff | comparison | revisions
src/server/daemon/event_solaris.c file | annotate | diff | comparison | revisions
src/server/daemon/objs.mk file | annotate | diff | comparison | revisions
src/server/daemon/threadpools.c file | annotate | diff | comparison | revisions
src/server/daemon/threadpools.h file | annotate | diff | comparison | revisions
src/server/ucx/dlist.c file | annotate | diff | comparison | revisions
src/server/ucx/dlist.h file | annotate | diff | comparison | revisions
src/server/ucx/string.c file | annotate | diff | comparison | revisions
src/server/webdav/davparser.cpp file | annotate | diff | comparison | revisions
src/server/webdav/saxhandler.cpp file | annotate | diff | comparison | revisions
src/server/webdav/saxhandler.h file | annotate | diff | comparison | revisions
src/server/webdav/webdav.c file | annotate | diff | comparison | revisions
src/server/webdav/webdav.h file | annotate | diff | comparison | revisions
--- a/src/server/daemon/config.c	Wed May 16 12:47:28 2012 +0200
+++ b/src/server/daemon/config.c	Thu May 24 12:51:52 2012 +0200
@@ -43,10 +43,13 @@
 #include "config.h"
 #include "func.h"
 #include "log.h"
+#include "event.h"
+#include "threadpools.h"
 #include "configmanager.h"
 
 #include "vserver.h"
 #include "../util/pblock.h"
+#include "../util/util.h"
 
 pool_handle_t *cfg_pool;
 
@@ -145,8 +148,8 @@
                 int hr = 0;
                 if(!sstrcmp(scfgobj->type, sstr("Runtime"))) {
                     hr = cfg_handle_runtime(serverconfig, scfgobj);
-                } else if(!sstrcmp(scfgobj->type, sstr("LogFile"))) {
-                    //hr = cfg_handle_logfile(serverconfig, scfgobj);
+                } else if(!sstrcmp(scfgobj->type, sstr("EventHandler"))) {
+                    hr = cfg_handle_eventhandler(serverconfig, scfgobj);
                 } else if(!sstrcmp(scfgobj->type, sstr("AuthDB"))) {
                     hr = cfg_handle_authdb(serverconfig, scfgobj);
                 } else if(!sstrcmp(scfgobj->type, sstr("Listener"))) {
@@ -164,7 +167,17 @@
         }
     }
 
-
+    /* check event handler config */
+    if(check_event_handler_cfg() != 0) {
+        /* critical error */
+        return NULL;
+    }
+    
+    /* check thread pool config */
+    if(check_thread_pool_cfg() != 0) {
+        /* critical error */
+        return NULL;
+    }
 
     /* set VirtualServer for all listeners */
     UcxList *ls = serverconfig->listeners;
@@ -237,6 +250,30 @@
     return ret;
 }
 
+int cfg_handle_eventhandler(ServerConfiguration *c, ServerConfigObject *obj) {
+    EventHandlerConfig evcfg;
+    
+    sstr_t name      = cfg_directivelist_get_str(obj->directives, sstr("Name"));
+    sstr_t threads   = cfg_directivelist_get_str(
+            obj->directives,
+            sstr("Threads"));
+    sstr_t isdefault = cfg_directivelist_get_str(
+            obj->directives,
+            sstr("Default"));
+    
+    evcfg.name = name;
+    
+    sstr_t s = sstrdup(threads);
+    evcfg.nthreads = atoi(s.ptr);
+    free(s.ptr);
+    
+    evcfg.isdefault = util_getboolean(isdefault.ptr, 0);
+    
+    int ret = create_event_handler(&evcfg);
+    
+    return ret;
+}
+
 int cfg_handle_authdb(ServerConfiguration *cfg, ServerConfigObject *obj) {
     /* TODO: authdb*/
 
--- a/src/server/daemon/config.h	Wed May 16 12:47:28 2012 +0200
+++ b/src/server/daemon/config.h	Thu May 24 12:51:52 2012 +0200
@@ -77,6 +77,8 @@
 
 int cfg_handle_logfile(ServerConfiguration *cfg, ServerConfigObject *obj);
 
+int cfg_handle_eventhandler(ServerConfiguration *cfg, ServerConfigObject *obj);
+
 int cfg_handle_authdb(ServerConfiguration *cfg, ServerConfigObject *obj);
 
 int cfg_handle_listener(ServerConfiguration *cfg, ServerConfigObject *obj);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/daemon/event.c	Thu May 24 12:51:52 2012 +0200
@@ -0,0 +1,96 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "../ucx/map.h"
+
+#include "event.h"
+
+UcxMap *event_handler_map = NULL;
+int numevhandlers = 0;
+
+event_handler_t *default_event_handler = NULL;
+
+event_handler_t *last_handler_c = NULL;
+
+int create_event_handler(EventHandlerConfig *cfg) {
+    if(event_handler_map == NULL) {
+        event_handler_map = ucx_map_new(16);
+    }
+    
+    /* if the event handler already exists, we don't modify it */
+    if(ucx_map_sstr_get(event_handler_map, cfg->name)) {
+        /* TODO: log message */
+        /* TODO: set reload status */
+        return 1;
+    }
+    
+    /* create new handler */
+    event_handler_t *e = evhandler_create(cfg->nthreads);
+    if(e == NULL) {
+        return 1;
+    }
+    
+    if(cfg->isdefault) {
+        if(default_event_handler) {
+            /* there can be only one default event handler  */
+            /* TODO: log warning */
+        }
+        default_event_handler = e;
+    }
+    
+    int ret = ucx_map_sstr_put(event_handler_map, cfg->name, e);
+    if(ret == 0) {
+        last_handler_c = e;
+        numevhandlers++;
+    }
+    
+    return ret;
+}
+
+/*
+ * checks if there is at least one event handler and a default handler
+ * if necessary, check_event_handler_cfg() creates a default event handler
+ */
+int check_event_handler_cfg() {
+    if(numevhandlers > 0 ) {
+        if(default_event_handler) {
+            return 0;
+        } else {
+            default_event_handler = last_handler_c;
+            return 0;
+        }
+    }
+    
+    EventHandlerConfig cfg;
+    cfg.name = sstr("default");
+    cfg.nthreads = 1;
+    cfg.isdefault = 1;
+    
+    return create_event_handler(&cfg);
+}
+
--- a/src/server/daemon/event.h	Wed May 16 12:47:28 2012 +0200
+++ b/src/server/daemon/event.h	Thu May 24 12:51:52 2012 +0200
@@ -30,6 +30,7 @@
 #define	EVENT_H
 
 #include "../public/nsapi.h"
+#include "../ucx/string.h"
 
 #ifdef	__cplusplus
 extern "C" {
@@ -49,6 +50,22 @@
     void         *cookie;
 };
 
+typedef struct event_handler_conf {
+    sstr_t   name;
+    int      nthreads;
+    int      isdefault;
+} EventHandlerConfig;
+
+typedef struct event_handler_object {
+    event_handler_t   *handler;
+    int               nthreads;
+} EventHandlerObject;
+
+int create_event_handler(EventHandlerConfig *cfg);
+
+int check_event_handler_cfg();
+
+/* implementation in event_$platform */
 event_handler_t* evhandler_create(int numthreads);
 
 int ev_pollin(event_handler_t *h, int fd, event_t *event);
--- a/src/server/daemon/event_solaris.c	Wed May 16 12:47:28 2012 +0200
+++ b/src/server/daemon/event_solaris.c	Thu May 24 12:51:52 2012 +0200
@@ -97,7 +97,7 @@
         }
         
         for(int i=0;i<nev;i++) {
-            event_t *event = events[i]->portev_user;
+            event_t *event = events[i].portev_user;
             if(event->fn) {
                 event->fn(ev, event);
             }
@@ -107,9 +107,15 @@
 
 /* returns a event handler port */
 int ev_get_port(event_handler_t *h) {
-    int cp = h->lp % h->nports;
+    int nps = h->nports;
+    if(nps == 1) {
+        return 0;
+    }
+    
+    int cp = h->lp % nps;
     atomic_inc_32(&h->lp);
-    return cp;
+    
+    return h->ports[cp];
 }
 
 int ev_pollin(event_handler_t *h, int fd, event_t *event) {
--- a/src/server/daemon/objs.mk	Wed May 16 12:47:28 2012 +0200
+++ b/src/server/daemon/objs.mk	Thu May 24 12:51:52 2012 +0200
@@ -45,6 +45,8 @@
 DAEMONOBJ += ws-fn.o
 DAEMONOBJ += configmanager.o
 DAEMONOBJ += log.o
+DAEMONOBJ += event.o
+DAEMONOBJ += threadpools.o
 
 #ifeq ($(OS), SunOS)
 DAEMONOBJ += event_solaris.o
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/daemon/threadpools.c	Thu May 24 12:51:52 2012 +0200
@@ -0,0 +1,89 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../ucx/map.h"
+
+#include "threadpools.h"
+
+
+UcxMap *thread_pool_map = NULL;
+int numthrpools = 0;
+
+threadpool_t *default_thread_pool = NULL;
+
+threadpool_t *last_thrpool_c = NULL;
+
+int create_threadpool(sstr_t name, ThreadPoolConfig *cfg) {
+    if(thread_pool_map == NULL) {
+        thread_pool_map = ucx_map_new(16);
+    }
+    
+    threadpool_t *pool = ucx_map_sstr_get(thread_pool_map, name);
+    if(pool) {
+        /* TODO: reconfig thread pool */
+        return 0;
+    } else {
+        threadpool_t *tp = threadpool_new(cfg->min_threads);
+        
+        int ret = ucx_map_sstr_put(thread_pool_map, name, tp);
+        
+        if(ret == 0) {
+            numthrpools++;
+            last_thrpool_c = tp;
+        }
+        
+        return ret;
+    }
+}
+
+int check_thread_pool_cfg() {
+    if(numthrpools > 0 ) {
+        if(default_thread_pool) {
+            return 0;
+        } else {
+            default_thread_pool = last_thrpool_c;
+            return 0;
+        }
+    }
+    
+    ThreadPoolConfig cfg;
+    cfg.min_threads = 4;
+    cfg.max_threads = 8;
+    cfg.queue_size = 64;
+    cfg.stack_size = 262144;
+    
+    return create_threadpool(sstr("default"), &cfg);
+}
+
+threadpool_t* get_default_threadpool() {
+    return default_thread_pool;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/daemon/threadpools.h	Thu May 24 12:51:52 2012 +0200
@@ -0,0 +1,58 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef THREADPOOLS_H
+#define	THREADPOOLS_H
+
+#include "../public/nsapi.h"
+#include "../util/thrpool.h"
+#include "../ucx/string.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct thread_pool_config {
+    int min_threads;
+    int max_threads;
+    int stack_size;
+    int queue_size;
+} ThreadPoolConfig;
+
+int create_threadpool(sstr_t name, ThreadPoolConfig *cfg);
+
+int check_thread_pool_cfg();
+
+threadpool_t* get_default_threadpool();
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* THREADPOOLS_H */
+
--- a/src/server/ucx/dlist.c	Wed May 16 12:47:28 2012 +0200
+++ b/src/server/ucx/dlist.c	Thu May 24 12:51:52 2012 +0200
@@ -45,6 +45,7 @@
     nl->data = data;
     nl->next = NULL;
     if (l == NULL) {
+        nl->prev = NULL;
         return nl;
     } else {
         UcxDlist *t = ucx_dlist_last(l);
@@ -111,14 +112,6 @@
     return s;
 }
 
-void ucx_dlist_foreach(UcxDlist *l, ucx_callback fnc, void* data) {
-    UcxDlist *e = l;
-    while (e != NULL) {
-        fnc(e, data);
-        e = e->next;
-    }
-}
-
 /* dlist specific functions */
 UcxDlist *ucx_dlist_first(UcxDlist *l) {
     if (l == NULL) return NULL;
@@ -129,3 +122,20 @@
     }
     return e;
 }
+
+UcxDlist *ucx_dlist_remove(UcxDlist *l, UcxDlist *e) {
+    if (e->prev == NULL) {
+        if(e->next != NULL) {
+            e->next->prev = NULL;
+            l = e->next;
+        } else {
+            l = NULL;
+        }
+        
+    } else {
+        e->prev->next = e->next;
+        e->next->prev = e->prev;
+    }
+    free(e);
+    return l;
+}
--- a/src/server/ucx/dlist.h	Wed May 16 12:47:28 2012 +0200
+++ b/src/server/ucx/dlist.h	Thu May 24 12:51:52 2012 +0200
@@ -29,10 +29,10 @@
 UcxDlist *ucx_dlist_last(UcxDlist *l);
 UcxDlist *ucx_dlist_get(UcxDlist *l, int index);
 size_t ucx_dlist_size(UcxDlist *l);
-void ucx_dlist_foreach(UcxDlist *l, ucx_callback fnc, void* data);
 
 /* dlist specific functions */
 UcxDlist *ucx_dlist_first(UcxDlist *l);
+UcxDlist *ucx_dlist_remove(UcxDlist *l, UcxDlist *e);
 
 #ifdef	__cplusplus
 }
--- a/src/server/ucx/string.c	Wed May 16 12:47:28 2012 +0200
+++ b/src/server/ucx/string.c	Thu May 24 12:51:52 2012 +0200
@@ -146,3 +146,4 @@
 
     return newstring;
 }
+
--- a/src/server/webdav/davparser.cpp	Wed May 16 12:47:28 2012 +0200
+++ b/src/server/webdav/davparser.cpp	Thu May 24 12:51:52 2012 +0200
@@ -105,6 +105,7 @@
     ProppatchRequest *davrq = (ProppatchRequest*)pool_malloc(
             sn->pool,
             sizeof(PropfindRequest));
+    davrq->nsmap = xmlnsmap_create();
     
     
     
--- a/src/server/webdav/saxhandler.cpp	Wed May 16 12:47:28 2012 +0200
+++ b/src/server/webdav/saxhandler.cpp	Thu May 24 12:51:52 2012 +0200
@@ -38,6 +38,22 @@
 
 using namespace std;
 
+void xstack_push(UcxDlist **stack, XmlElement *elm) {
+    *stack = ucx_dlist_prepend(*stack, elm);
+}
+
+XmlElement* xstack_pop(UcxDlist **stack) {
+    if(*stack == NULL) {
+        return NULL;
+    }
+    XmlElement* ret = (XmlElement*)(*stack)->data;
+    UcxDlist *newstack = ucx_dlist_remove(*stack, *stack);
+    *stack = newstack;
+    return ret;
+}
+
+
+
 PropfindHandler::PropfindHandler(PropfindRequest *rq, pool_handle_t *p) {
     davrq = rq;
     pool  = p;
@@ -132,6 +148,13 @@
 ProppatchHandler::ProppatchHandler(ProppatchRequest *rq, pool_handle_t *p) {
     davrq = rq;
     pool  = p;
+    
+    davPropTag = false;
+    rootElement = NULL;
+    xmlStack = NULL;
+    newElement = NULL;
+    
+    updateMode = -1;
 }
 
 ProppatchHandler::~ProppatchHandler() {
@@ -147,10 +170,34 @@
     char *ns  = XMLString::transcode(uri);
     char *name = XMLString::transcode(localname);
     
-    if(!strcmp(ns, "DAV:") && !strcmp(name, "prop")) {
+    if(!strcmp(ns, "DAV:") && !strcmp(name, "set")) {
+        updateMode = 0;
+    } else if(!strcmp(ns, "DAV:") && !strcmp(name, "remove")) {
+        updateMode = 1;
+    } else if(!strcmp(ns, "DAV:") && !strcmp(name, "prop")) {
         davPropTag = true;
     } else if(davPropTag) {
+        newElement = (XmlElement*)pool_calloc(pool, 1, sizeof(XmlElement));
+        newElement->name = sstr(pool_strdup(pool, name));
+        newElement->xmlns = xmlnsmap_put(davrq->nsmap, ns);
         
+        /*
+         * the xml stack manages the xml hierarchy
+         * new elements will be added to the top element on the stack
+         */
+        
+        XmlElement *currentElm = XSTACK_CUR();
+        if(currentElm) {
+            xmlelm_add_child(currentElm, newElement);
+        }
+        
+        /* newElement is now the parent for future elements */
+        XSTACK_PUSH(newElement);
+        
+        /* if the root element isn't set, the first new element is the root */
+        if(!rootElement) {
+            rootElement = newElement;
+        }
     }
 
     XMLString::release(&ns);
@@ -167,11 +214,42 @@
     char *name = XMLString::transcode(localname);
 
     if(!strcmp(ns, "DAV:") && !strcmp(name, "set")) {
-        updateMode = 0;
+        updateMode = -1;
     } else if(!strcmp(ns, "DAV:") && !strcmp(name, "remove")) {
-        updateMode = 1;
+        updateMode = -1;
     } else if(!strcmp(ns, "DAV:") && !strcmp(name, "prop")) {
-        
+        davPropTag = false;
+    } else if(davPropTag) {
+        XmlElement *elm = XSTACK_POP();
+        if(xmlStack == NULL) {
+            /* property complete */
+            
+            /*
+            XmlElement *r = rootElement;
+            printf("<%s>\n", sstrdup(r->name).ptr);
+            printf("%s\n", r->content);
+            printf("</%s>\n", sstrdup(r->name).ptr);
+            */
+            
+            /* add the property to the proppatch request */
+            switch(updateMode) {
+                case 0: {
+                    davrq->setProps = ucx_dlist_append(
+                            davrq->setProps,
+                            rootElement);
+                    break;
+                }
+                case 1: {
+                    davrq->removeProps = ucx_dlist_append(
+                            davrq->removeProps,
+                            rootElement);
+                    break;
+                }
+            }
+            
+            rootElement = NULL;
+            
+        }
     }
     
 
@@ -184,6 +262,21 @@
         const XMLSize_t length)
 {
     
+    XMLString::trim((XMLCh *const)chars);
+    if(chars[0] == 0) {
+        return;
+    }
+    
+    XmlElement *currentElm = XSTACK_CUR();
+    if(currentElm) {
+        xmlch_t *str = (xmlch_t*)pool_calloc(pool, sizeof(xmlch_t), length + 1);
+        for(int i=0;i<length;i++) {
+            str[i] = chars[i];
+        }
+        
+        currentElm->content = str;
+        currentElm->ctlen = length;
+    }
 }
 
 void ProppatchHandler::startDocument() {
--- a/src/server/webdav/saxhandler.h	Wed May 16 12:47:28 2012 +0200
+++ b/src/server/webdav/saxhandler.h	Thu May 24 12:51:52 2012 +0200
@@ -35,6 +35,13 @@
 
 using namespace xercesc;
 
+/* stack */
+#define XSTACK_PUSH(elm) xstack_push(&xmlStack, elm)
+#define XSTACK_POP() xstack_pop(&xmlStack)
+#define XSTACK_CUR() (xmlStack) ? (XmlElement*)xmlStack->data : NULL;
+void xstack_push(UcxDlist **stack, XmlElement *elm);
+XmlElement* xstack_pop(UcxDlist **stack);
+
 class PropfindHandler : public DefaultHandler {
 public:
     PropfindHandler(PropfindRequest *rq, pool_handle_t *p);
@@ -91,10 +98,12 @@
     pool_handle_t    *pool;
 
     bool             davPropTag;
-    XmlElement       *rxprop; /* root of xml property */
-    XmlElement       *cxprop; /* current element */
-    DavProperty      *property;
-    int              updateMode; /* 0 = set, 1 = remove */
+    XmlElement       *rootElement;
+    XmlElement       *newElement; 
+    UcxDlist         *xmlStack;
+    
+    //DavProperty      *property;
+    int              updateMode; /* 0 = set, 1 = remove, -1 = undefined */
 };
 
 #endif	/* SAXHANDLER_H */
--- 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, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
+    sbuf_puts(davrq->out, "<D:multistatus xmlns:D=\"DAV:\">\n");
+    
+    sbuf_puts(davrq->out, "<D:response>\n<D:href>");
+    sbuf_puts(davrq->out, uri);
+    sbuf_puts(davrq->out, "</D:href>\n");
+    
+    /* do proppatch operation */
+    davrq->backend->proppatch(davrq->backend, davrq);
+    
+    propstat_write(davrq->propstat, davrq->out, 0);
+    
+    sbuf_puts(davrq->out, "</D:response>\n");
+    sbuf_puts(davrq->out, "</D:multistatus>\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, "<D:propstat>\n<D:prop>\n");
+        
+        DAV_FOREACH(prop, propstat->okprop) {    
+            xmlelm_write((XmlElement*)prop->data, out, wv);
+        }
+        
+        sbuf_puts(out, "\n</D:prop>\n<D:status>HTTP/1.1 200 OK</D:status>\n");
+        sbuf_puts(out, "</D:propstat>\n");
+    }
+    
+    for(int i=0;i<propstat->map->size;i++) {
+        UcxMapElement *elm = &propstat->map->map[i];
+        while(elm) {
+            UcxDlist *proplist = (UcxDlist*)elm->data;
+            
+            if(proplist) {
+                sbuf_puts(out, "<D:propstat>\n<D:prop>\n");
+                
+                DAV_FOREACH(prop, proplist) {
+                    xmlelm_write((XmlElement*)prop->data, out, wv);
+                }
+                
+                sbuf_puts(out, "\n</D:prop>\n<D:status>");
+                
+                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, "</D:status>\n</D:propstat>\n");
+            }
+            
+            elm = elm->next;
+        }
+    }
+}
--- a/src/server/webdav/webdav.h	Wed May 16 12:47:28 2012 +0200
+++ b/src/server/webdav/webdav.h	Thu May 24 12:51:52 2012 +0200
@@ -34,6 +34,8 @@
 #include <sys/file.h>
 #include <sys/stat.h>
 
+#include <inttypes.h>
+
 #include "../ucx/map.h"
 #include "../ucx/dlist.h"
 #include "../util/strbuf.h"
@@ -51,10 +53,18 @@
 typedef struct PropfindRequest      PropfindRequest;
 typedef struct ProppatchRequest     ProppatchRequest;
 typedef struct DavProperty          DavProperty;
-typedef struct DavPropertyCt        DavPropertyCt;
+
+typedef struct Propstat             Propstat;
+
+typedef struct XmlNs                XmlNs;
+typedef struct XmlNsMap             XmlNsMap;
 
+typedef struct XmlData              XmlData;
 typedef struct XmlElement           XmlElement;
 
+typedef uint8_t                     xmlch_t;
+
+
 struct PropfindRequest {
     Session            *sn;
     Request            *rq;
@@ -81,7 +91,19 @@
     UcxDlist           *setProps;    /* XmlElement list, set props */
     UcxDlist           *removeProps; /* DavProperty list, remove props */
     
+    Propstat           *propstat;
+    XmlNsMap           *nsmap;
     
+    DAVPropertyBackend *backend;
+    
+    
+    sbuf_t             *out;
+};
+
+struct Propstat {
+    UcxDlist           *okprop; /* properties with status 200 OK */
+    UcxMap             *map;    /* all other properties */
+    pool_handle_t      *pool;
 };
 
 struct DavProperty {
@@ -89,42 +111,66 @@
     char *name;
 };
 
-struct DavPropertyCt {
-    char           *xmlns;
-    char           *name;
-    DavPropertyCt  **props;
-    int            npr;
+struct XmlData {
+    XmlNsMap   *nsmap;
+    XmlElement *elm;
 };
 
 struct XmlElement {
-    char           *xmlns;
-    char           *name;
-    char           *content;
-    int            *ctlen;
-    int            *numelm;
-    XmlElement     **elms;
+    XmlNs  *xmlns;
+    sstr_t name;
+    void   *content; /* xmlch* or UcxDlist* */
+    size_t ctlen;    /* content string length. If 0, content is a UcxDlist */
+};
+
+struct XmlNs {
+    char *xmlns;
+    char *prefix;
+    int  nslen;
+    int  prelen;
+};
+
+struct XmlNsMap {
+    UcxMap *map;
 };
 
 /*
- * dav_res_propfind_f
+ * dav_propfind_f
  * 
- * Gets all requested properties of a WebDAV resource(file). This function
+ * Gets all requested properties for a WebDAV resource(file). This function
  * should add properties with dav_propfind_add_str_prop or
  * dav_prop_add_xml_prop. Unavailable properties should be added with
+ * dav_propfind_add_prop_error
  * 
  * 
  * arg0: property backend
  * arg1: current PropfindRequest object
  * arg2: the webdav resource path
  */
-typedef void(*dav_res_propfind_f)(DAVPropertyBackend*,PropfindRequest*,char*);
+typedef void(*dav_propfind_f)(DAVPropertyBackend*,PropfindRequest*,char*);
+
+/*
+ * dav_proppatch_f
+ * 
+ * Sets properties for a WebDAV resource. It should add all properties to the
+ * propstat object (member of the ProppatchRequest).
+ * 
+ * arg0: WebDAV backend
+ * arg1: current ProppatchRequest object
+ */
+typedef void(*dav_proppatch_f)(DAVPropertyBackend*,ProppatchRequest*);
 
 struct DAVPropertyBackend {
-    dav_res_propfind_f propfind;
+    dav_propfind_f     propfind;
+    dav_proppatch_f    proppatch;
 };
 
 int webdav_service(pblock *pb, Session *sn, Request *rq);
 int webdav_put(pblock *pb, Session *sn, Request *rq);
+int webdav_delete(pblock *pb, Session *sn, Request *rq);
+int webdav_mkcol(pblock *pb, Session *sn, Request *rq);
+int webdav_copy(pblock *pb, Session *sn, Request *rq);
+int webdav_move(pblock *pb, Session *sn, Request *rq);
 int webdav_propfind(pblock *pb, Session *sn, Request *rq);
 int webdav_proppatch(pblock *pb, Session *sn, Request *rq);
 
@@ -160,7 +206,90 @@
 
 
 DAVPropertyBackend* create_property_backend();
-void dav_rq_propfind(DAVPropertyBackend *b,PropfindRequest *rq ,char *path);
+void dav_rq_propfind(DAVPropertyBackend *b, PropfindRequest *rq, char *path);
+void dav_rq_proppatch(DAVPropertyBackend *b, ProppatchRequest *rq);
+
+/*---------------------------------- utils ----------------------------------*/
+
+/*
+ * XmlNsMap
+ * 
+ * a map containing xml namespaces
+ * 
+ * key:    namespace uri
+ * value:  XmlNs object, containing namespace uri and the prefix
+ */
+
+XmlNsMap* xmlnsmap_create();
+
+void xmlnsmap_free(XmlNsMap *map);
+
+/*
+ * Puts a namespace in the map. If the namespace is already in the map, the
+ * available XmlNs object is returned
+ */
+XmlNs* xmlnsmap_put(XmlNsMap *map, char *ns);
+
+/*
+ * Gets a namespace from the map. Returns NULL if the namespace is not in the
+ * map
+ */
+XmlNs* xmlnsmap_get(XmlNsMap *map, char *ns);
+
+
+
+/*
+ * XmlElement
+ * 
+ * representing a xml element
+ */
+
+/*
+ * adds a xml element to a parent element
+ */
+void xmlelm_add_child(XmlElement *parent, XmlElement *child);
+
+/*
+ * writes an xml element to an output buffer
+ * if wv is true, it writes the complete value of the element
+ */
+void xmlelm_write(XmlElement *elm, sbuf_t *out, int wv);
+
+
+/*
+ * PropstatMap
+ * 
+ * A map containing multiple propstat objects
+ * 
+ * key:    status code:  int
+ * value:  prop list:    UcxDlist* (list of XmlElement*)
+ */
+
+
+/*
+ * creates a new Propstat
+ */
+Propstat* propstat_create(pool_handle_t *pool);
+
+
+/*
+ * adds a property to the propstat map
+ * 
+ * propstat:  propstat object
+ * status:    http status code
+ * prop:      WebDAV property
+ */
+void propstat_add(Propstat *propstat, int status, XmlElement *prop);
+
+/*
+ * writes the propstat object to an output buffer
+ * if wv is true, it writes the values of the 'OK' properties
+ * 
+ * propstat:  propstat object
+ * out:       output buffer
+ * wv:        property output mode
+ */
+void propstat_write(Propstat *propstat, sbuf_t *out, int wv);
 
 #ifdef	__cplusplus
 }

mercurial