some fixes and new public APIs

Mon, 06 May 2013 13:44:27 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Mon, 06 May 2013 13:44:27 +0200
changeset 59
ab25c0a231d0
parent 58
66c22e54aa90
child 60
feb2f1e115c6

some fixes and new public APIs

src/server/daemon/acl.h file | annotate | diff | comparison | revisions
src/server/daemon/authdb.c file | annotate | diff | comparison | revisions
src/server/daemon/authdb.h file | annotate | diff | comparison | revisions
src/server/daemon/httprequest.c file | annotate | diff | comparison | revisions
src/server/daemon/ldap_auth.h file | annotate | diff | comparison | revisions
src/server/daemon/request.c file | annotate | diff | comparison | revisions
src/server/daemon/vfs.c file | annotate | diff | comparison | revisions
src/server/daemon/vfs.h file | annotate | diff | comparison | revisions
src/server/daemon/webserver.c file | annotate | diff | comparison | revisions
src/server/daemon/ws-fn.c file | annotate | diff | comparison | revisions
src/server/public/acl.h file | annotate | diff | comparison | revisions
src/server/public/auth.h file | annotate | diff | comparison | revisions
src/server/public/nsapi.h file | annotate | diff | comparison | revisions
src/server/public/vfs.h file | annotate | diff | comparison | revisions
src/server/public/webdav.h file | annotate | diff | comparison | revisions
src/server/safs/auth.c file | annotate | diff | comparison | revisions
src/server/safs/init.c file | annotate | diff | comparison | revisions
src/server/safs/service.c file | annotate | diff | comparison | revisions
src/server/util/pool.h file | annotate | diff | comparison | revisions
src/server/util/thrpool.h file | annotate | diff | comparison | revisions
src/server/util/util.c file | annotate | diff | comparison | revisions
src/server/webdav/davparser.cpp file | annotate | diff | comparison | revisions
src/server/webdav/objs.mk file | annotate | diff | comparison | revisions
src/server/webdav/persistence.c file | annotate | diff | comparison | revisions
src/server/webdav/persistence.h file | annotate | diff | comparison | revisions
src/server/webdav/saxhandler.cpp 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/acl.h	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/daemon/acl.h	Mon May 06 13:44:27 2013 +0200
@@ -29,164 +29,12 @@
 #ifndef ACL_H
 #define	ACL_H
 
-#include "../public/nsapi.h"
-#include "authdb.h"
+#include "../public/acl.h"
 
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
-// ACLListHandle typedef in nsapi.h
-typedef struct ACLListElm ACLListElm;
-typedef struct ACLList ACLList;
-
-typedef struct WSAcl WSAcl;
-typedef struct WSAce WSAce;
-
-/*
- * a wrapper struct for acls
- */
-struct ACLListHandle {
-    AuthDB     *defaultauthdb;
-    ACLListElm *listhead;
-    ACLListElm *listtail;
-};
-
-struct ACLListElm {
-    ACLList    *acl;
-    ACLListElm *next;
-};
-
-/*
- * abstract ACL
- */
-typedef int(*acl_check_f)(ACLList*, User*, int);
-struct ACLList {
-    AuthDB *authdb;
-    char   *authprompt;
-    int isextern;
-    /* int check(ACLList *acl, User *user, int access_mask) */
-    int(*check)(ACLList *acl, User *user, int access_mask);
-};
-
-/*
- * a webserver access control list
- * 
- * Access control is determined by the ace field. The ece field is a separat
- * list for audit and alarm entries.
- */
-struct WSAcl {
-    ACLList acl;
-    WSAce **ace; // access control entries
-    WSAce **ece; // event control entries (audit/alarm entries)
-    int acenum; // number of aces
-    int ecenum; // number of eces
-};
-
-
-struct WSAce {
-    char     *who; // user or group name
-    uint32_t access_mask;
-    uint16_t flags;
-    uint16_t type;
-};
-
-
-/*
- * access permissions
- */
-#define ACL_READ_DATA               0x0001
-#define ACL_WRITE_DATA              0x0002
-#define ACL_APPEND                  0x0002
-#define ACL_ADD_FILE                0x0004
-#define ACL_ADD_SUBDIRECTORY        0x0004
-#define ACL_READ_XATTR              0x0008
-#define ACL_WRITE_XATTR             0x0010
-#define ACL_EXECUTE                 0x0020
-#define ACL_DELETE_CHILD            0x0040
-#define ACL_DELETE                  0x0040
-#define ACL_READ_ATTRIBUTES         0x0080
-#define ACL_WRITE_ATTRIBUTES        0x0100
-#define ACL_LIST                    0x0200
-#define ACL_READ_ACL                0x0400
-#define ACL_WRITE_ACL               0x0800
-#define ACL_WRITE_OWNER             0x1000
-#define ACL_SYNCHRONIZE             0x2000
-#define ACL_READ \
-        (ACL_READ_DATA|ACL_READ_XATTR|ACL_READ_ATTRIBUTES)
-#define ACL_WRITE \
-        (ACL_WRITE_DATA|ACL_WRITE_XATTR|ACL_WRITE_ATTRIBUTES)
-
-/*
- * ace flags
- */
-#define ACL_FILE_INHERIT            0x0001
-#define ACL_DIR_INHERIT             0x0002
-#define ACL_NO_PROPAGATE            0x0004
-#define ACL_INHERIT_ONLY            0x0008
-#define ACL_SUCCESSFUL_ACCESS_FLAG  0x0010
-#define ACL_FAILED_ACCESS_ACE_FLAG  0x0020
-#define ACL_IDENTIFIER_GROUP        0x0040
-#define ACL_OWNER                   0x1000
-#define ACL_GROUP                   0x2000
-#define ACL_EVERYONE                0x4000
-
-/*
- * ace type
- */
-#define ACL_TYPE_ALLOWED 0x01
-#define ACL_TYPE_DENIED  0x02
-#define ACL_TYPE_AUDIT   0x03
-#define ACL_TYPE_ALARM   0x04
-
-
-/*
- * public API
- */
-
-// list
-void acllist_append(Session *sn, Request *rq, ACLList *acl);
-void acllist_prepend(Session *sn, Request *rq, ACLList *acl);
-
-/*
- * gets a access mask from open flags
- */
-uint32_t acl_oflag2mask(int oflags);
-
-/*
- * authenticates the user with the user database specified in the acl list
- */
-User* acllist_getuser(Session *sn, Request *rq, ACLListHandle *list);
-
-/*
- * sets the status to 403 or 401 and sets www-authenticate
- * 
- * use this only if a ACL denies access
- */
-void acl_set_error_status(Session *sn, Request *rq, ACLList *acl, User *user);
-
-/*
- * acl_evaluate
- * 
- * Evaluates all ACLs in rq->acllist. It combines rq->aclreqaccess and
- * access_mask. If access is denied and no user is authenticated it sets the
- * www-authenticate header and the status to 401 Unauthorized.
- * 
- * returns REQ_PROCEED if access is allowed or REQ_ABORTED if access is denied
- */
-int acl_evaluate(Session *sn, Request *rq, int access_mask);
-
-/*
- * acl_evallist
- * 
- * evalutes all ACLs in acllist
- * 
- * returns NULL if access is allowed or a pointer to the ACLList which
- * denied access
- */
-ACLList* acl_evallist(ACLListHandle *acllist, User *user, int access_mask);
-
-
 // private
 int wsacl_affects_user(WSAce *ace, User *user);
 int wsacl_check(WSAcl *acl, User *user, int access_mask);
--- a/src/server/daemon/authdb.c	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/daemon/authdb.c	Mon May 06 13:44:27 2013 +0200
@@ -30,5 +30,5 @@
 #include <stdlib.h>
 
 #include "../ucx/map.h"
-#include "authdb.h"
+#include "../public/auth.h"
 
--- a/src/server/daemon/authdb.h	Tue Mar 19 17:38:32 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2013 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 AUTHDB_H
-#define	AUTHDB_H
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-typedef struct auth_db AuthDB;
-typedef struct user    User;   
-
-/*
- * get a user from the authentication database
- * 
- * param1: authentication database
- * param2: user
- */
-typedef User*(*authdb_get_user_f)(AuthDB*, char*);
-
-struct auth_db {
-    char                *name;
-    /* User* get_user(AuthDB *db, char *username) */
-    authdb_get_user_f   get_user;
-};
-
-/*
- * verify the users password
- * 
- * param1: user
- * param2: password
- */
-typedef int(*user_verify_passwd_f)(User*, char*);
-
-/*
- * check if the user is a member of a given group
- * 
- * param1: user
- * param2: group
- */
-typedef int(*user_check_group_f)(User*, char*);
-
-/*
- * free the user object
- */
-typedef void(*user_free_f)(User*);
-
-struct user {
-    char                   *name;
-    /* int verify_password(User *user, char *password) */
-    user_verify_passwd_f   verify_password;
-    /* int check_group(User *user, char *group) */
-    user_check_group_f     check_group;
-    /* void free(User*) */
-    user_free_f            free;
-};
-
-
-
-
-#ifdef	__cplusplus
-}
-#endif
-
-#endif	/* AUTHDB_H */
-
--- a/src/server/daemon/httprequest.c	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/daemon/httprequest.c	Mon May 06 13:44:27 2013 +0200
@@ -121,7 +121,7 @@
             request->request_line.length,
             rq->rq.reqpb);
 
-    /* Pass method as "method" in reqpb, and also as method_num */
+    // Pass method as "method" in reqpb, and also as method_num
     pblock_kvinsert(
             pb_key_method,
             request->method.ptr,
@@ -131,7 +131,7 @@
     //rqRq.rq.method_num = rqHdr->GetMethodNumber();
     //PR_ASSERT(rqRq.rq.method_num != -1 || iStatus);
     
-    /* Pass protocol as "protocol" in reqpb, and also in protv_num */
+    // Pass protocol as "protocol" in reqpb, and also in protv_num
     pblock_kvinsert(
             pb_key_protocol,
             request->httpv.ptr,
@@ -156,7 +156,7 @@
             }
             absPath.length = i;
 
-            /* Pass any query as 'query' in reqpb */
+            // Pass any query as 'query' in reqpb
             pblock_kvinsert(
                     pb_key_query,
                     query.ptr,
@@ -167,25 +167,29 @@
         }
     }
     
-    /* Get abs_path part of request URI, and canonicalize the path */
+    // Get abs_path part of request URI, and canonicalize the path
     absPath.ptr = util_canonicalize_uri(
             pool,
             absPath.ptr,
             absPath.length,
             (int*)&absPath.length);
 
-    /* Decode the abs_path */
-    // TODO: decode abs_path (done?)
-
-    /* Pass the abs_path as 'uri' in reqpb */
-    pblock_kvinsert(
-            pb_key_uri,
-            absPath.ptr,
-            absPath.length,
-            rq->rq.reqpb);
+    // Decode the abs_path
+    if(util_uri_unescape_strict(absPath.ptr)) {
+        // Pass the abs_path as 'uri' in reqpb
+        pblock_kvinsert(
+                pb_key_uri,
+                absPath.ptr,
+                absPath.length,
+                rq->rq.reqpb);
+    } else {
+        // TODO: log error
+        printf("unescape failed\n");
+        pblock_kvinsert(pb_key_uri, "/", 1, rq->rq.reqpb);
+    }
 
     // pass http header to the NSAPI request structure
-    int         hlen = request->headers->len;
+    int hlen = request->headers->len;
     HeaderArray *ha  = request->headers;
     for(int i=0;i<=hlen;i++) {
         if(i == hlen) {
@@ -224,7 +228,7 @@
 
         netbuf *nb = request->netbuf;
 
-        /* create new netbuf */
+        // create new netbuf
         NetIOStream *net_io = (NetIOStream*)net_stream_from_fd(
                 pool,
                 request->connection->fd);
--- a/src/server/daemon/ldap_auth.h	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/daemon/ldap_auth.h	Mon May 06 13:44:27 2013 +0200
@@ -29,7 +29,7 @@
 #ifndef LDAP_AUTH_H
 #define	LDAP_AUTH_H
 
-#include "authdb.h"
+#include "../public/auth.h"
 #include <ldap.h>
 
 #ifdef	__cplusplus
--- a/src/server/daemon/request.c	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/daemon/request.c	Mon May 06 13:44:27 2013 +0200
@@ -99,6 +99,7 @@
     // new
     rq->status_num = -1;
     rq->vfs = NULL;
+    rq->davCollection = NULL;
 
     return 0;
 }
--- a/src/server/daemon/vfs.c	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/daemon/vfs.c	Mon May 06 13:44:27 2013 +0200
@@ -32,8 +32,11 @@
 #include <sys/types.h>
 
 #include "../util/pool.h"
+#include "../ucx/map.h"
 #include "vfs.h"
 
+static UcxMap *vfs_map;
+
 static VFS_IO sys_file_io = {
     sys_file_read,
     sys_file_write,
@@ -45,6 +48,21 @@
     sys_dir_close
 };
 
+int vfs_init() {
+    vfs_map = ucx_map_new(16);
+    if(!vfs_map) {
+        return -1;
+    }
+    return 0;
+}
+
+void vfs_add(char *name, VFS *vfs) {
+    if(!vfs_map) {
+        vfs_init();
+    }
+    ucx_map_cstr_put(vfs_map, name, vfs);
+}
+
 VFSContext* vfs_request_context(Session *sn, Request *rq) {
     VFSContext *ctx = pool_malloc(sn->pool, sizeof(VFSContext));
     ctx->sn = sn;
--- a/src/server/daemon/vfs.h	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/daemon/vfs.h	Mon May 06 13:44:27 2013 +0200
@@ -29,95 +29,15 @@
 #ifndef VFS_H
 #define	VFS_H
 
-#include "../public/nsapi.h"
-#include "acl.h"
+#include "../public/vfs.h"
 
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
-typedef struct VFS_IO     VFS_IO;
-typedef struct VFS_DIRIO  VFS_DIRIO;
-typedef struct VFSFile    VFSFile;
-typedef struct VFSDir     VFSDir;
-typedef struct VFSEntry   VFSEntry;
-
-#define VFS_DIR           VFSDir*
-#define VFS_ENTRY         VFSEntry
-
-struct VFS {
-    SYS_FILE (*open)(VFSContext *ctx, char *path, int oflags);
-    int (*stat)(VFSContext *ctx, char *path, struct stat *buf);
-    int (*fstat)(VFSContext *ctx, SYS_FILE fd, struct stat *buf);
-    VFS_DIR (*opendir)(VFSContext *ctx, char *path);
-    int (*mkdir)(VFSContext *ctx, char *path);
-    int (*unlink)(VFSContext *ctx, char *path);
-};
-
-struct VFSContext {
-    Session *sn;
-    Request *rq;
-    VFS *vfs;
-    pool_handle_t *pool;
-    User *user;
-    ACLListHandle *acllist;
-    uint32_t aclreqaccess;
-    int vfs_errno;
-};
-
-struct VFSFile {
-    VFSContext *ctx;
-    VFS_IO *io; // IO functions
-    void *data; // private data used by the VFSFile implementation
-    int fd; // native file descriptor if available, or -1
-};
+// private
+int vfs_init();
 
-struct VFSDir {
-    VFSContext *ctx;
-    VFS_DIRIO *io;
-    void *data; // private data used by the VFSDir implementation
-    int fd; // native file descriptor if available, or -1
-};
-
-struct VFSEntry {
-    char *name;
-    struct stat stat;
-    void *stat_extra;
-    int stat_errno;
-};
-
-struct VFS_IO {
-    ssize_t (*read)(SYS_FILE fd, void *buf, size_t nbyte);
-    ssize_t (*write)(SYS_FILE fd, const void *buf, size_t nbyte);
-    void (*close)(SYS_FILE fd);
-};
-
-struct VFS_DIRIO {
-    int (*readdir)(VFS_DIR dir, VFS_ENTRY *entry, int getstat);
-    void (*close)(VFS_DIR dir);
-};
-
-/*
- * creates a VFSContext for a Request
- * vfs calls will do ACL checks
- */
-VFSContext* vfs_request_context(Session *sn, Request *rq);
-
-SYS_FILE vfs_open(VFSContext *ctx, char *path, int oflags);
-SYS_FILE vfs_openRO(VFSContext *ctx, char *path);
-SYS_FILE vfs_openWO(VFSContext *ctx, char *path);
-SYS_FILE vfs_openRW(VFSContext *ctx, char *path);
-int vfs_stat(VFSContext *ctx, char *path, struct stat *buf);
-int vfs_fstat(VFSContext *ctx, SYS_FILE fd, struct stat *buf);
-void vfs_close(SYS_FILE fd);
-VFS_DIR vfs_opendir(VFSContext *ctx, char *path);
-int vfs_readdir(VFS_DIR dir, VFS_ENTRY *entry);
-int vfs_readdir_stat(VFS_DIR dir, VFS_ENTRY *entry);
-void vfs_closedir(VFS_DIR dir);
-int vfs_mkdir(VFSContext *ctx, char *path);
-int vfs_unlink(VFSContext *ctx, char *path);
-
-// private
 typedef int(*vfs_op_f)(VFSContext *, char *);
 int vfs_path_op(VFSContext *ctx, char *path, vfs_op_f op, uint32_t access);
 
--- a/src/server/daemon/webserver.c	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/daemon/webserver.c	Mon May 06 13:44:27 2013 +0200
@@ -39,6 +39,7 @@
 #include <sys/stat.h>
 
 #include "../public/nsapi.h"
+#include "../public/auth.h"
 #include "../util/systhr.h"
 #include "../util/io.h"
 #include "../util/util.h"
@@ -47,7 +48,6 @@
 #include "config.h"
 #include "configmanager.h"
 #include "httplistener.h"
-#include "authdb.h"
 #include "webserver.h"
 #include "log.h"
 
--- a/src/server/daemon/ws-fn.c	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/daemon/ws-fn.c	Mon May 06 13:44:27 2013 +0200
@@ -50,6 +50,8 @@
     { "common-index", service_index, NULL, 0},
     { "service-hello", service_hello, NULL, 0},
     { "send-options", send_options, NULL, 0},
+    { "webdav-init", webdav_init, NULL, 0},
+    { "webdav-setcollection", webdav_setcollection, NULL, 0},
     { "webdav-service", webdav_service, NULL, 0},
     { "admin-index", adm_index, NULL, 0},
     { "auth-basic", auth_basic, NULL, 0 },
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/public/acl.h	Mon May 06 13:44:27 2013 +0200
@@ -0,0 +1,194 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 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 WS_ACL_H
+#define	WS_ACL_H
+
+#include "nsapi.h"
+#include "auth.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+// ACLListHandle typedef in nsapi.h
+typedef struct ACLListElm ACLListElm;
+typedef struct ACLList ACLList;
+
+typedef struct WSAcl WSAcl;
+typedef struct WSAce WSAce;
+
+/*
+ * a wrapper struct for acls
+ */
+struct ACLListHandle {
+    AuthDB     *defaultauthdb;
+    ACLListElm *listhead;
+    ACLListElm *listtail;
+};
+
+struct ACLListElm {
+    ACLList    *acl;
+    ACLListElm *next;
+};
+
+/*
+ * abstract ACL
+ */
+typedef int(*acl_check_f)(ACLList*, User*, int);
+struct ACLList {
+    AuthDB *authdb;
+    char   *authprompt;
+    int isextern;
+    /* int check(ACLList *acl, User *user, int access_mask) */
+    int(*check)(ACLList *acl, User *user, int access_mask);
+};
+
+/*
+ * a webserver access control list
+ * 
+ * Access control is determined by the ace field. The ece field is a separat
+ * list for audit and alarm entries.
+ */
+struct WSAcl {
+    ACLList acl;
+    WSAce **ace; // access control entries
+    WSAce **ece; // event control entries (audit/alarm entries)
+    int acenum; // number of aces
+    int ecenum; // number of eces
+};
+
+
+struct WSAce {
+    char     *who; // user or group name
+    uint32_t access_mask;
+    uint16_t flags;
+    uint16_t type;
+};
+
+
+/*
+ * access permissions
+ */
+#define ACL_READ_DATA               0x0001
+#define ACL_WRITE_DATA              0x0002
+#define ACL_APPEND                  0x0002
+#define ACL_ADD_FILE                0x0004
+#define ACL_ADD_SUBDIRECTORY        0x0004
+#define ACL_READ_XATTR              0x0008
+#define ACL_WRITE_XATTR             0x0010
+#define ACL_EXECUTE                 0x0020
+#define ACL_DELETE_CHILD            0x0040
+#define ACL_DELETE                  0x0040
+#define ACL_READ_ATTRIBUTES         0x0080
+#define ACL_WRITE_ATTRIBUTES        0x0100
+#define ACL_LIST                    0x0200
+#define ACL_READ_ACL                0x0400
+#define ACL_WRITE_ACL               0x0800
+#define ACL_WRITE_OWNER             0x1000
+#define ACL_SYNCHRONIZE             0x2000
+#define ACL_READ \
+        (ACL_READ_DATA|ACL_READ_XATTR|ACL_READ_ATTRIBUTES)
+#define ACL_WRITE \
+        (ACL_WRITE_DATA|ACL_WRITE_XATTR|ACL_WRITE_ATTRIBUTES)
+
+/*
+ * ace flags
+ */
+#define ACL_FILE_INHERIT            0x0001
+#define ACL_DIR_INHERIT             0x0002
+#define ACL_NO_PROPAGATE            0x0004
+#define ACL_INHERIT_ONLY            0x0008
+#define ACL_SUCCESSFUL_ACCESS_FLAG  0x0010
+#define ACL_FAILED_ACCESS_ACE_FLAG  0x0020
+#define ACL_IDENTIFIER_GROUP        0x0040
+#define ACL_OWNER                   0x1000
+#define ACL_GROUP                   0x2000
+#define ACL_EVERYONE                0x4000
+
+/*
+ * ace type
+ */
+#define ACL_TYPE_ALLOWED 0x01
+#define ACL_TYPE_DENIED  0x02
+#define ACL_TYPE_AUDIT   0x03
+#define ACL_TYPE_ALARM   0x04
+
+
+/*
+ * public API
+ */
+
+// list
+void acllist_append(Session *sn, Request *rq, ACLList *acl);
+void acllist_prepend(Session *sn, Request *rq, ACLList *acl);
+
+/*
+ * gets a access mask from open flags
+ */
+uint32_t acl_oflag2mask(int oflags);
+
+/*
+ * authenticates the user with the user database specified in the acl list
+ */
+User* acllist_getuser(Session *sn, Request *rq, ACLListHandle *list);
+
+/*
+ * sets the status to 403 or 401 and sets www-authenticate
+ * 
+ * use this only if a ACL denies access
+ */
+void acl_set_error_status(Session *sn, Request *rq, ACLList *acl, User *user);
+
+/*
+ * acl_evaluate
+ * 
+ * Evaluates all ACLs in rq->acllist. It combines rq->aclreqaccess and
+ * access_mask. If access is denied and no user is authenticated it sets the
+ * www-authenticate header and the status to 401 Unauthorized.
+ * 
+ * returns REQ_PROCEED if access is allowed or REQ_ABORTED if access is denied
+ */
+int acl_evaluate(Session *sn, Request *rq, int access_mask);
+
+/*
+ * acl_evallist
+ * 
+ * evalutes all ACLs in acllist
+ * 
+ * returns NULL if access is allowed or a pointer to the ACLList which
+ * denied access
+ */
+ACLList* acl_evallist(ACLListHandle *acllist, User *user, int access_mask);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* WS_ACL_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/public/auth.h	Mon May 06 13:44:27 2013 +0200
@@ -0,0 +1,92 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 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 WS_AUTH_H
+#define	WS_AUTH_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct auth_db AuthDB;
+typedef struct user    User;   
+
+/*
+ * get a user from the authentication database
+ * 
+ * param1: authentication database
+ * param2: user
+ */
+typedef User*(*authdb_get_user_f)(AuthDB*, char*);
+
+struct auth_db {
+    char                *name;
+    /* User* get_user(AuthDB *db, char *username) */
+    authdb_get_user_f   get_user;
+};
+
+/*
+ * verify the users password
+ * 
+ * param1: user
+ * param2: password
+ */
+typedef int(*user_verify_passwd_f)(User*, char*);
+
+/*
+ * check if the user is a member of a given group
+ * 
+ * param1: user
+ * param2: group
+ */
+typedef int(*user_check_group_f)(User*, char*);
+
+/*
+ * free the user object
+ */
+typedef void(*user_free_f)(User*);
+
+struct user {
+    char                   *name;
+    /* int verify_password(User *user, char *password) */
+    user_verify_passwd_f   verify_password;
+    /* int check_group(User *user, char *group) */
+    user_check_group_f     check_group;
+    /* void free(User*) */
+    user_free_f            free;
+};
+
+
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* WS_AUTH_H */
+
--- a/src/server/public/nsapi.h	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/public/nsapi.h	Mon May 06 13:44:27 2013 +0200
@@ -1001,6 +1001,8 @@
     uint32_t aclreqaccess; /* new - required access rights */
     
     VFS *vfs; /* new - virtual file system */
+    
+    void *davCollection;
 
     int request_is_cacheable;   /* */
     int directive_is_cacheable; /* set by SAFs with no external side effects that make decisions based solely on URI and path */
@@ -1083,6 +1085,11 @@
 #define ISMOPTIONS(r)   ((r)->method_num == METHOD_OPTIONS)
 
 
+// new type
+typedef struct _thread_pool       threadpool_t;
+typedef struct  _threadpool_job   threadpool_job;
+typedef void*(*job_callback_f)(void *data);
+
 /* --- End type definitions --- */
 
 /* --- Begin dispatch vector table definition --- */
@@ -1259,6 +1266,42 @@
 #define pblock_fr INTpblock_fr
 #define pblock_replace INTpblock_replace
 
+
+// pool
+NSAPI_PUBLIC pool_handle_t *INTpool_create(void);
+
+NSAPI_PUBLIC void *INTpool_mark(pool_handle_t *pool_handle);
+
+NSAPI_PUBLIC void INTpool_recycle(pool_handle_t *pool_handle, void *mark);
+
+NSAPI_PUBLIC void INTpool_destroy(pool_handle_t *pool_handle);
+
+NSAPI_PUBLIC int INTpool_enabled(void);
+
+NSAPI_PUBLIC void *INTpool_malloc(pool_handle_t *pool_handle, size_t size );
+
+NSAPI_PUBLIC void INTpool_free(pool_handle_t *pool_handle, void *ptr );
+
+NSAPI_PUBLIC 
+void *INTpool_calloc(pool_handle_t *pool_handle, size_t nelem, size_t elsize);
+
+NSAPI_PUBLIC 
+void *INTpool_realloc(pool_handle_t *pool_handle, void *ptr, size_t size );
+
+NSAPI_PUBLIC
+char *INTpool_strdup(pool_handle_t *pool_handle, const char *orig_str );
+
+#define pool_create INTpool_create
+#define pool_mark INTpool_mark
+#define pool_recycle INTpool_recycle
+#define pool_destroy INTpool_destroy
+#define pool_enabled INTpool_enabled
+#define pool_malloc INTpool_malloc
+#define pool_free INTpool_free
+#define pool_calloc INTpool_calloc
+#define pool_realloc INTpool_realloc
+#define pool_strdup INTpool_strdup
+
 // func util functions
 FuncStruct* func_resolve(pblock *pb, Session *sn, Request *rq);
 int func_exec (pblock *pb, Session *sn, Request *rq);
@@ -1324,6 +1367,12 @@
 #define util_errno2status util_errno2status
 
 
+// threadpool
+threadpool_t* threadpool_new(int n);
+void* threadpool_func(void *data);
+threadpool_job* threadpool_get_job(threadpool_t *pool);
+void threadpool_run(threadpool_t *pool, job_callback_f func, void *data);
+
 /* end new macro and function definitions */
 
 #define SYS_STDERR STDERR_FILENO
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/public/vfs.h	Mon May 06 13:44:27 2013 +0200
@@ -0,0 +1,130 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 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 WS_VFS_H
+#define	WS_VFS_H
+
+#include "nsapi.h"
+#include "acl.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct VFS_IO     VFS_IO;
+typedef struct VFS_DIRIO  VFS_DIRIO;
+typedef struct VFSFile    VFSFile;
+typedef struct VFSDir     VFSDir;
+typedef struct VFSEntry   VFSEntry;
+
+#define VFS_DIR           VFSDir*
+#define VFS_ENTRY         VFSEntry
+
+struct VFS {
+    SYS_FILE (*open)(VFSContext *ctx, char *path, int oflags);
+    int (*stat)(VFSContext *ctx, char *path, struct stat *buf);
+    int (*fstat)(VFSContext *ctx, SYS_FILE fd, struct stat *buf);
+    VFS_DIR (*opendir)(VFSContext *ctx, char *path);
+    int (*mkdir)(VFSContext *ctx, char *path);
+    int (*unlink)(VFSContext *ctx, char *path);
+};
+
+struct VFSContext {
+    Session *sn;
+    Request *rq;
+    VFS *vfs;
+    pool_handle_t *pool;
+    User *user;
+    ACLListHandle *acllist;
+    uint32_t aclreqaccess;
+    int vfs_errno;
+};
+
+struct VFSFile {
+    VFSContext *ctx;
+    VFS_IO *io; // IO functions
+    void *data; // private data used by the VFSFile implementation
+    int fd; // native file descriptor if available, or -1
+};
+
+struct VFSDir {
+    VFSContext *ctx;
+    VFS_DIRIO *io;
+    void *data; // private data used by the VFSDir implementation
+    int fd; // native file descriptor if available, or -1
+};
+
+struct VFSEntry {
+    char *name;
+    struct stat stat;
+    void *stat_extra;
+    int stat_errno;
+};
+
+struct VFS_IO {
+    ssize_t (*read)(SYS_FILE fd, void *buf, size_t nbyte);
+    ssize_t (*write)(SYS_FILE fd, const void *buf, size_t nbyte);
+    void (*close)(SYS_FILE fd);
+};
+
+struct VFS_DIRIO {
+    int (*readdir)(VFS_DIR dir, VFS_ENTRY *entry, int getstat);
+    void (*close)(VFS_DIR dir);
+};
+
+/*
+ * registers a new VFS
+ */
+void vfs_add(char *name, VFS *vfs);
+
+/*
+ * creates a VFSContext for a Request
+ * vfs calls will do ACL checks
+ */
+VFSContext* vfs_request_context(Session *sn, Request *rq);
+
+SYS_FILE vfs_open(VFSContext *ctx, char *path, int oflags);
+SYS_FILE vfs_openRO(VFSContext *ctx, char *path);
+SYS_FILE vfs_openWO(VFSContext *ctx, char *path);
+SYS_FILE vfs_openRW(VFSContext *ctx, char *path);
+int vfs_stat(VFSContext *ctx, char *path, struct stat *buf);
+int vfs_fstat(VFSContext *ctx, SYS_FILE fd, struct stat *buf);
+void vfs_close(SYS_FILE fd);
+VFS_DIR vfs_opendir(VFSContext *ctx, char *path);
+int vfs_readdir(VFS_DIR dir, VFS_ENTRY *entry);
+int vfs_readdir_stat(VFS_DIR dir, VFS_ENTRY *entry);
+void vfs_closedir(VFS_DIR dir);
+int vfs_mkdir(VFSContext *ctx, char *path);
+int vfs_unlink(VFSContext *ctx, char *path);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* WS_VFS_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/public/webdav.h	Mon May 06 13:44:27 2013 +0200
@@ -0,0 +1,319 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 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 WS_WEBDAV_H
+#define	WS_WEBDAV_H
+
+#include "nsapi.h"
+
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <inttypes.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct DavCollection          DavCollection;
+    
+typedef struct PropfindResponse       PropfindResponse;
+typedef struct PersistenceManager     PersistenceManager;
+
+typedef struct PropfindRequest        PropfindRequest;
+typedef struct ProppatchRequest       ProppatchRequest;
+typedef struct DavProperty            DavProperty;
+
+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;
+
+typedef struct UcxDlist               List;
+typedef struct UcxMap                 Map;
+
+typedef struct _strbuf                Buffer;
+
+struct DavCollection {
+    PersistenceManager *mgr;
+    // callbacks
+};
+
+struct PropfindRequest {
+    Session            *sn;
+    Request            *rq;
+    
+    XmlNsMap           *nsmap;
+    
+    List               *properties; /* DavProperty list, requested props */
+    int8_t             allprop;
+    int8_t             propname;
+    
+    int8_t             prop;
+    int8_t             isdir;
+    List               *notFoundProps;
+    List               *forbiddenProps;
+    PersistenceManager *persistencemgr;
+    void               *mgrdata;
+
+    char               *path;
+    char               *uri;
+
+    Buffer             *out;
+};
+
+struct ProppatchRequest {
+    Session            *sn;
+    Request            *rq;
+    
+    List               *setProps;    /* XmlElement list, set props */
+    List               *removeProps; /* DavProperty list, remove props */
+    
+    Propstat           *propstat;
+    XmlNsMap           *nsmap;
+    
+    PersistenceManager *backend;
+    
+    char               *path;
+    
+    Buffer             *out;
+};
+
+struct Propstat {
+    List           *okprop; /* properties with status 200 OK */
+    Map            *map;    /* all other properties */
+    pool_handle_t  *pool;
+};
+
+struct DavProperty {
+    XmlNs *xmlns;
+    char  *name;
+};
+
+struct XmlData {
+    XmlNsMap   *nsmap;
+    XmlElement *elm;
+};
+
+struct XmlElement {
+    XmlNs  *xmlns;
+    char   *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 {
+    Map           *map;
+    pool_handle_t *pool;
+    int num;
+};
+
+typedef void(*dav_propfind_begin_f)(PersistenceManager*, PropfindRequest*);
+typedef void(*dav_propfind_end_f)(PersistenceManager*, PropfindRequest*);
+typedef void(*dav_propfind_f)(PersistenceManager*,PropfindRequest*,char*);
+typedef void(*dav_proppatch_f)(PersistenceManager*,ProppatchRequest*);
+struct PersistenceManager {
+    void(*propfind_begin)(PersistenceManager *mgr, PropfindRequest *rq);
+    void(*propfind_end)(PersistenceManager *mgr, PropfindRequest *rq);
+    
+    /*
+     * void propfind(PersistenceManager *mgr, PropfindRequest *rq, char *path)
+     * 
+     * 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
+     * 
+     * 
+     * mgr:  WebDAV Persistence Manager
+     * rq:   current PropfindRequest object
+     * path: the webdav resource path
+     */
+    void(*propfind)(PersistenceManager *mgr, PropfindRequest *rq, char *path);
+    
+    /*
+     * void proppatch(PersistenceManager *mgr, ProppatchRequest *rq)
+     * 
+     * Sets properties for a WebDAV resource. It should add all properties to
+     * the propstat object (member of the ProppatchRequest).
+     * 
+     * mgr:  WebDAV backend
+     * path: current ProppatchRequest object
+     */
+    void(*proppatch)(PersistenceManager *mgr, ProppatchRequest *rq);
+    
+    /*
+     * bool
+     * if true, some properties are get from the VFS and not from this
+     * persistence manager
+     */
+    int vfs_props;
+};
+
+void webdav_add_persistence_manager(char *name, PersistenceManager *mgr);
+
+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);
+
+
+/*
+ * dav_propfind_add_str_prop
+ * 
+ * Adds a string property to the current WebDAV resource response
+ */
+void dav_propfind_add_str_prop(
+        PropfindRequest *rq,
+        DavProperty* prop,
+        char *str,
+        size_t len);
+
+//void dav_propfind_add_xml_prop();
+
+/*
+ * dav_propfind_add_prop_error
+ * 
+ * Adds a unavailable property to the response
+ * 
+ * rq:    propfind request object
+ * prop:  unavailable property
+ * error: HTTP status code
+ */
+void dav_propfind_add_prop_error(
+        PropfindRequest *rq,
+        DavProperty *prop,
+        int error);
+
+
+
+/*---------------------------------- utils ----------------------------------*/
+
+/*
+ * XmlNsMap
+ * 
+ * a map containing xml namespaces
+ * 
+ * key:    namespace uri
+ * value:  XmlNs object, containing namespace uri and the prefix
+ */
+
+XmlNsMap* xmlnsmap_create(pool_handle_t *pool);
+
+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, Buffer *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, Buffer *out, int wv);
+
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* WS_WEBDAV_H */
+
--- a/src/server/safs/auth.c	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/safs/auth.c	Mon May 06 13:44:27 2013 +0200
@@ -33,7 +33,7 @@
 
 #include <strings.h>
 
-#include "../daemon/authdb.h"
+#include "../public/auth.h"
 #include "../daemon/config.h"
 #include "../daemon/session.h"
 
--- a/src/server/safs/init.c	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/safs/init.c	Mon May 06 13:44:27 2013 +0200
@@ -50,7 +50,8 @@
     /* load lib */
     void *lib = dlopen(shlib, RTLD_GLOBAL | RTLD_NOW);
     if(lib == NULL) {
-        fprintf(stderr, "Cannot load library %s\n", shlib);
+        fprintf(stderr, "Cannot load library %s %s\n", shlib, dlerror());
+        
         return REQ_ABORTED;
     }
 
--- a/src/server/safs/service.c	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/safs/service.c	Mon May 06 13:44:27 2013 +0200
@@ -61,11 +61,28 @@
     }
 
     /* get stat */
-    if (vfs_fstat(vfs, fd, s) != 0) {
+    if(vfs_fstat(vfs, fd, s) != 0) {
         //perror("prepare_service_file: stat");
         protocol_status(sn, rq, 500, NULL);
         return NULL;
     }
+    
+    // check if the file is a directory
+    if(S_ISDIR(s->st_mode)) {
+        pblock_nvinsert("content-length", "0", rq->srvhdrs);
+        pblock_removekey(pb_key_content_type, rq->srvhdrs);
+        char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
+        size_t urilen = strlen(uri);
+        char *location = pool_malloc(sn->pool, urilen + 2);
+        memcpy(location, uri, urilen);
+        location[urilen] = '/';
+        location[urilen+1] = '\0';
+        pblock_kvinsert(pb_key_location, location, urilen + 1, rq->srvhdrs);
+        protocol_status(sn, rq, 302, NULL);
+        http_start_response(sn, rq);
+        vfs_close(fd);
+        return fd;
+    }
 
     /* add content-length header*/
     char contentLength[32];
@@ -89,14 +106,16 @@
         return REQ_ABORTED;
     }
     
-    // send file
-    sendfiledata sfd;
-    sfd.fd = fd;
-    sfd.len = s.st_size;
-    sfd.offset = 0;
-    sfd.header = NULL;
-    sfd.trailer = NULL;
-    net_sendfile(sn->csd, &sfd);
+    if(!S_ISDIR(s.st_mode)) {
+        // send file
+        sendfiledata sfd;
+        sfd.fd = fd;
+        sfd.len = s.st_size;
+        sfd.offset = 0;
+        sfd.header = NULL;
+        sfd.trailer = NULL;
+        net_sendfile(sn->csd, &sfd);
+    }
     
     vfs_close(fd);
 
--- a/src/server/util/pool.h	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/util/pool.h	Mon May 06 13:44:27 2013 +0200
@@ -84,6 +84,7 @@
 NSAPI_PUBLIC int INTpool_service_debug(pblock *pb, Session *sn, Request *rq);
 #endif
 
+/*
 NSAPI_PUBLIC pool_handle_t *INTpool_create(void);
 
 NSAPI_PUBLIC void *INTpool_mark(pool_handle_t *pool_handle);
@@ -107,6 +108,8 @@
 NSAPI_PUBLIC
 char *INTpool_strdup(pool_handle_t *pool_handle, const char *orig_str );
 
+*/
+
 #ifdef DEBUG
 NSAPI_PUBLIC void INTpool_assert(pool_handle_t *pool_handle, const void *ptr);
 #endif
@@ -127,17 +130,6 @@
 #define POOL_ASSERT(pool, ptr)
 #endif
 
-#define pool_create INTpool_create
-#define pool_mark INTpool_mark
-#define pool_recycle INTpool_recycle
-#define pool_destroy INTpool_destroy
-#define pool_enabled INTpool_enabled
-#define pool_malloc INTpool_malloc
-#define pool_free INTpool_free
-#define pool_calloc INTpool_calloc
-#define pool_realloc INTpool_realloc
-#define pool_strdup INTpool_strdup
-
 #endif /* INTNSAPI */
 
 #endif /* !BASE_POOL_H_ */
--- a/src/server/util/thrpool.h	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/util/thrpool.h	Mon May 06 13:44:27 2013 +0200
@@ -29,6 +29,7 @@
 #ifndef THREADPOOL_H
 #define	THREADPOOL_H
 
+#include "../public/nsapi.h"
 #include <pthread.h>
 
 #ifdef	__cplusplus
@@ -36,34 +37,24 @@
 #endif
 
 typedef struct _pool_queue pool_queue_t;
-typedef struct _thread_pool {
+struct _thread_pool {
     pthread_mutex_t queue_lock;
     pthread_mutex_t avlbl_lock;
     pthread_cond_t  available;
+    pool_queue_t    *queue;
     int             queue_len;
-    pool_queue_t    *queue;
-} threadpool_t;
+};
 
-typedef void*(*job_callback_f)(void *data);
-typedef struct _threadpool_job {
+struct _threadpool_job {
     job_callback_f  callback;
     void            *data;
-} threadpool_job;
+};
 
 struct _pool_queue {
     threadpool_job   *job;
     pool_queue_t     *next;
 };
 
-
-threadpool_t* threadpool_new(int n);
-
-void* threadpool_func(void *data);
-
-threadpool_job* threadpool_get_job(threadpool_t *pool);
-
-void threadpool_run(threadpool_t *pool, job_callback_f func, void *data);
-
 #ifdef	__cplusplus
 }
 #endif
--- a/src/server/util/util.c	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/util/util.c	Mon May 06 13:44:27 2013 +0200
@@ -192,6 +192,32 @@
     return 500;
 }
 
+NSAPI_PUBLIC int util_uri_unescape_strict(char *s)
+{
+    char *t, *u, t1, t2;
+    int rv = 1;
+
+    for(t = s, u = s; *t; ++t, ++u) {
+        if (*t == '%') {
+            t1 = t[1] & 0xdf; /* [a-f] -> [A-F] */
+            if ((t1 < 'A' || t1 > 'F') && (t[1] < '0' || t[1] > '9'))
+                rv = 0;
+
+            t2 = t[2] & 0xdf; /* [a-f] -> [A-F] */
+            if ((t2 < 'A' || t2 > 'F') && (t[2] < '0' || t[2] > '9'))
+                rv = 0;
+
+            *u = ((t[1] >= 'A' ? ((t[1] & 0xdf) - 'A')+10 : (t[1] - '0'))*16) +
+                  (t[2] >= 'A' ? ((t[2] & 0xdf) - 'A')+10 : (t[2] - '0'));
+            t += 2;
+        }
+        else if (u != t)
+            *u = *t;
+    }
+    *u = *t;
+
+    return rv;
+}
 
 NSAPI_PUBLIC
 sstr_t util_path_append(pool_handle_t *pool, char *path, char *ch) {
@@ -211,6 +237,7 @@
     newstr.ptr = pool_malloc(pool, newstr.length + 1);
     if(!newstr.ptr) {
         // TODO: error
+        newstr.length = 0;
         return newstr;
     }
     if(s.length == 1) {
--- a/src/server/webdav/davparser.cpp	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/webdav/davparser.cpp	Mon May 06 13:44:27 2013 +0200
@@ -58,12 +58,15 @@
             sn->pool,
             1,
             sizeof(PropfindRequest));
+    davrq->nsmap = xmlnsmap_create(sn->pool);
+    xmlnsmap_put(davrq->nsmap, (char*)"DAV:");
     davrq->allprop = 0;
     davrq->propname = 0;
     davrq->prop = 0;
     davrq->properties = NULL;
     davrq->forbiddenProps = NULL;
     davrq->notFoundProps = NULL;
+    davrq->mgrdata = NULL;
     // create xml parser
     SAX2XMLReader* parser = XMLReaderFactory::createXMLReader();
     parser->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);
@@ -117,7 +120,7 @@
             1,
             sizeof(PropfindRequest));
     davrq->nsmap = xmlnsmap_create(sn->pool);
-    
+    xmlnsmap_put(davrq->nsmap, (char*)"DAV:");
     
     
     // create xml parser
--- a/src/server/webdav/objs.mk	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/webdav/objs.mk	Mon May 06 13:44:27 2013 +0200
@@ -31,6 +31,7 @@
 DAV_OBJPRE = $(OBJ_DIR)$(DAV_SRC_DIR)
 
 DAVOBJ = webdav.o
+DAVOBJ += persistence.o
 
 DAVOBJS = $(DAVOBJ:%=$(DAV_OBJPRE)%)
 DAVSOURCE = $(DAVOBJ:%.o=webdav/%.c)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/webdav/persistence.c	Mon May 06 13:44:27 2013 +0200
@@ -0,0 +1,59 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 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 <unistd.h>
+#include <sys/types.h>
+
+#include "persistence.h"
+
+PersistenceManager* create_property_database() {
+    PropertyDatabase *mgr = malloc(sizeof(PropertyDatabase));
+    mgr->mgr.propfind_begin = (dav_propfind_begin_f)pdb_propfind_begin;
+    mgr->mgr.propfind_end = (dav_propfind_end_f)pdb_propfind_end;
+    mgr->mgr.propfind = (dav_propfind_f)pdb_propfind;
+    mgr->mgr.proppatch = (dav_proppatch_f)pdb_proppatch;
+    return (PersistenceManager*)mgr;
+}
+
+void pdb_propfind_begin(PropertyDatabase *mgr, PropfindRequest *rq) {
+    
+}
+
+void pdb_propfind_end(PropertyDatabase *mgr, PropfindRequest *rq) {
+    
+}
+
+void pdb_propfind(PropertyDatabase *mgr, PropfindRequest *rq, char *path) {
+    
+}
+
+void pdb_proppatch(PropertyDatabase *mgr, ProppatchRequest *rq) {
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/webdav/persistence.h	Mon May 06 13:44:27 2013 +0200
@@ -0,0 +1,53 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 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 PERSISTENCE_H
+#define	PERSISTENCE_H
+
+#include "webdav.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct PropertyDatabase {
+    PersistenceManager mgr;
+} PropertyDatabase;
+
+PersistenceManager* create_property_database();
+void pdb_propfind_begin(PropertyDatabase *mgr, PropfindRequest *rq);
+void pdb_propfind_end(PropertyDatabase *mgr, PropfindRequest *rq);
+void pdb_propfind(PropertyDatabase *mgr, PropfindRequest *rq, char *path);
+void pdb_proppatch(PropertyDatabase *mgr, ProppatchRequest *rq);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* PERSISTENCE_H */
+
--- a/src/server/webdav/saxhandler.cpp	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/webdav/saxhandler.cpp	Mon May 06 13:44:27 2013 +0200
@@ -88,9 +88,10 @@
         size_t nslen = strlen(ns);
         size_t namelen = strlen(name);
         if(nslen > 0) {
-            property->xmlns = (char*)pool_malloc(pool, nslen + 1);
-            property->xmlns[nslen] = 0;
-            memcpy(property->xmlns, ns, nslen);
+            //property->xmlns = (char*)pool_malloc(pool, nslen + 1);
+            //property->xmlns[nslen] = 0;
+            property->xmlns = xmlnsmap_put(davrq->nsmap, ns);
+            //memcpy(property->xmlns, ns, nslen);
         } else {
             property->xmlns = NULL;
         }
@@ -118,7 +119,7 @@
     char *name = XMLString::transcode(localname);
 
     if(property != NULL) {
-        const char *xmlns = (property->xmlns) ? property->xmlns : "";
+        const char *xmlns = (property->xmlns) ? property->xmlns->xmlns : "";
         
         if(!strcmp(ns, xmlns) && !strcmp(name, property->name)) {
             // add property to DavRequest
@@ -181,7 +182,7 @@
         davPropTag = true;
     } else if(davPropTag) {
         newElement = (XmlElement*)pool_calloc(pool, 1, sizeof(XmlElement));
-        newElement->name = sstr(pool_strdup(pool, name));
+        newElement->name = pool_strdup(pool, name);
         newElement->xmlns = xmlnsmap_put(davrq->nsmap, ns);
         
         /*
@@ -276,6 +277,7 @@
         for(int i=0;i<length;i++) {
             str[i] = chars[i];
         }
+        str[length] = 0;
         
         currentElm->content = str;
         currentElm->ctlen = length;
--- 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");
         
--- a/src/server/webdav/webdav.h	Tue Mar 19 17:38:32 2013 +0100
+++ b/src/server/webdav/webdav.h	Mon May 06 13:44:27 2013 +0200
@@ -29,12 +29,7 @@
 #ifndef WEBDAV_H
 #define	WEBDAV_H
 
-#include "../public/nsapi.h"
-
-#include <sys/file.h>
-#include <sys/stat.h>
-
-#include <inttypes.h>
+#include "../public/webdav.h"
 
 #include "../ucx/map.h"
 #include "../ucx/dlist.h"
@@ -46,251 +41,18 @@
 
 #define DAV_FOREACH(elem, list) \
         for (UcxDlist *elem = list ; elem != NULL ; elem = elem->next)
-    
-typedef struct PropfindResponse     PropfindResponse;
-typedef struct DAVPropertyBackend   DAVPropertyBackend;
 
-typedef struct PropfindRequest      PropfindRequest;
-typedef struct ProppatchRequest     ProppatchRequest;
-typedef struct DavProperty          DavProperty;
-
-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;
-
-    UcxDlist           *properties; /* DavProperty list, requested props */
-    int8_t             allprop;
-    int8_t             propname;
-    
-    int8_t             prop;
-    UcxDlist           *notFoundProps;
-    UcxDlist           *forbiddenProps;
-    DAVPropertyBackend *propertyBackend;
-
-    char               *path;
-    char               *uri;
-
-    sbuf_t             *out;
-};
-
-struct ProppatchRequest {
-    Session            *sn;
-    Request            *rq;
-    
-    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 {
-    char *xmlns;
-    char *name;
-};
-
-struct XmlData {
-    XmlNsMap   *nsmap;
-    XmlElement *elm;
-};
-
-struct XmlElement {
-    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;
-    pool_handle_t *pool;
-};
-
-/*
- * dav_propfind_f
- * 
- * 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_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_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);
+int webdav_init(pblock *pb, Session *sn, Request *rq);
+int webdav_setcollection(pblock *pb, Session *sn, Request *rq);
 
 void dav_resource_response(PropfindRequest *rq, sstr_t path, sstr_t uri);
 
-/*
- * dav_propfind_add_str_prop
- * 
- * Adds a string property to the current WebDAV resource response
- */
-void dav_propfind_add_str_prop(
-        PropfindRequest *rq,
-        DavProperty* prop,
-        char *str,
-        size_t len);
-
-//void dav_propfind_add_xml_prop();
-
-/*
- * dav_propfind_add_prop_error
- * 
- * Adds a unavailable property to the response
- * 
- * rq:    propfind request object
- * prop:  unavailable property
- * error: HTTP status code
- */
-void dav_propfind_add_prop_error(
-        PropfindRequest *rq,
-        DavProperty *prop,
-        int error);
-
 
 
-DAVPropertyBackend* create_property_backend();
-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(pool_handle_t *pool);
-
-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
- */
+PersistenceManager* create_property_backend();
+void dav_rq_propfind(PersistenceManager *b, PropfindRequest *rq, char *path);
+void dav_rq_proppatch(PersistenceManager *b, ProppatchRequest *rq);
 
-/*
- * 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