src/server/webdav/webdav.c

changeset 107
7e81699d1f77
parent 94
6b15a094d996
child 211
2160585200ac
--- a/src/server/webdav/webdav.c	Sat Oct 31 15:01:07 2015 +0100
+++ b/src/server/webdav/webdav.c	Sat Oct 31 16:39:12 2015 +0100
@@ -31,788 +31,5 @@
 #include <string.h>
 
 #include "webdav.h"
-#include <ucx/list.h>
-#include <ucx/string.h>
-#include "../util/pool.h"
-#include "../util/pblock.h"
-#include "../util/date.h"
-#include "../util/util.h"
-
-#include "../daemon/vfs.h"
-#include "../daemon/protocol.h"
-
-#include "davparser.h"
-#include "parser.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);
-    if(method == NULL) {
-        return REQ_ABORTED;
-    }
-    
-    if(!strcmp(method, "PROPFIND")) {
-        return webdav_propfind(pb, sn, rq);
-    } else if(!strcmp(method, "PROPPATCH")) {
-        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;
-}
-
-int webdav_put(pblock *pb, Session *sn, Request *rq) {
-    int length = 0;
-    
-    char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars);
-    char *ctlen = pblock_findkeyval(pb_key_content_length, rq->headers);
-    if(ctlen) {
-        length = atoi(ctlen);
-    } else {
-        /* invalid request */
-        printf("invalid request\n");
-        return REQ_ABORTED;
-    }
-    
-    printf("PUT length: %d\n", length);
-    
-    //int status = 201;
-    //FILE *out = fopen(ppath, "w");
-    
-    VFSContext *vfs = vfs_request_context(sn, rq);
-    SYS_FILE out = vfs_openWO(vfs, ppath);
-    if(out == NULL) {
-        fprintf(stderr, "vfs_openWO(%s, \"w\") failed\n", ppath);
-        //protocol_status(sn, rq, 500, NULL);
-        return REQ_ABORTED;
-    }
-    
-    if(length > 0) {
-        size_t len = (length > 4096) ? (4096) : (length);
-        char *buffer = pool_malloc(sn->pool, len);
-        
-        int r;
-        int r2 = 0;
-        while(r2 < length) {
-            r = netbuf_getbytes(sn->inbuf, buffer, len);
-            if(r == NETBUF_EOF) {
-                break;
-            }
-            system_fwrite(out, buffer, r);
-            
-            r2 += r;
-        }
-        
-        pool_free(sn->pool, buffer);
-    } else {
-        
-    }
-    vfs_close(out);
-    
-    protocol_status(sn, rq, 201, 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_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);
-    
-    VFSContext *vfs = vfs_request_context(sn, rq);
-    
-    int status = 204;
-    
-    struct stat st;
-    if(vfs_stat(vfs, ppath, &st)) {
-        return REQ_ABORTED;
-    }
-    
-    if(!strcmp(uri, "/")) {
-        status = 403;
-    } else if((st.st_mode & S_IFDIR) == S_IFDIR) {
-        if(rmdir(ppath) != 0) {
-            /* ERROR */
-            status = 403;
-        }
-    } else {
-        if(vfs_unlink(vfs, ppath)) {
-            /* ERROR */
-            return REQ_ABORTED;
-        }
-    }
-    
-    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);
-    
-    VFSContext *vfs = vfs_request_context(sn, rq);
-    if(vfs_mkdir(vfs, ppath)) {
-        return REQ_ABORTED;
-    }
-    
-    protocol_status(sn, rq, 201, 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 */
-
-    /* Get request body which contains the webdav XML request */
-    char   *xml_body;
-    size_t xml_len = 0;
-
-    char *ctlen = pblock_findkeyval(pb_key_content_length, rq->headers);
-    if(ctlen) {
-        xml_len = atoi(ctlen);
-    } else {
-        /* invalid request */
-        printf("invalid request\n");
-        return REQ_ABORTED;
-    }
-
-    xml_body = pool_malloc(sn->pool, xml_len + 1);
-    if(xml_body == NULL) {
-        return REQ_ABORTED;
-    }
-    xml_body[xml_len] = 0;
-    if(!xml_body) {
-        /* server error */
-        printf("server error\n");
-        return REQ_ABORTED;
-    }
-
-    /* get request body */
-    int r = 0;
-    char *xb = xml_body;
-    size_t xl = xml_len;
-    while((r = netbuf_getbytes(sn->inbuf, xb, xl)) != NETBUF_EOF) {
-        xb += r;
-        xl -= r;
-    }
-
-    /*
-     * get requested properties and initialize some stuff
-     */
-    DavCollection *collection = rq->davCollection;
-    if(!collection) {
-        collection = pool_malloc(sn->pool, sizeof(DavCollection));
-        collection->mgr = ucx_map_cstr_get(pmgr_map, "default");
-    }
-    
-    PropfindRequest *davrq = dav_parse_propfind2(sn, rq, xml_body, xml_len);  
-    davrq->sn = sn;
-    davrq->rq = rq;
-    davrq->out = sbuf_new(512);
-    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);
-    
-    // create the response for the requested resource
-    dav_resource_response(davrq, sstr(ppath), sstr(uri));
-    
-    /*
-     * if the requested webdav resource(file) is a directory, we create
-     * a response for every child
-     */
-    if(S_ISDIR(st.st_mode)) {
-        VFS_DIR dir = vfs_opendir(vfs, ppath);
-        if(dir == NULL) {
-            return REQ_ABORTED;
-        }
-        
-        VFS_ENTRY entry;
-        while(vfs_readdir(dir, &entry)) {
-            sstr_t newpath = util_path_append(sn->pool, ppath, entry.name);
-            sstr_t newuri = util_path_append(sn->pool, uri, entry.name); 
-            // child response
-            dav_resource_response(davrq, newpath, newuri);
-        }
-    }
-    
-    // end propfind
-    davrq->persistencemgr->propfind_begin(davrq->persistencemgr, davrq);
-    
-    // end xml
-    sbuf_puts(davrq->out, "</D:multistatus>\n");
-    
-    //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(key, 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",
-            out->length + davrq->out->length,
-            rq->srvhdrs);
-    
-    http_start_response(sn, rq);
-    
-    // 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;
-}
-
-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;
-    size_t xml_len = 0;
-
-    char *ctlen = pblock_findkeyval(pb_key_content_length, rq->headers);
-    if(ctlen) {
-        xml_len = atoi(ctlen);
-    } else {
-        // invalid request
-        printf("invalid request\n");
-        return REQ_ABORTED;
-    }
-
-    xml_body = pool_malloc(sn->pool, xml_len + 1);
-    if(xml_body == NULL) {
-        return REQ_ABORTED;
-    }
-    xml_body[xml_len] = 0;
-    if(!xml_body) {
-        // server error
-        printf("server error\n");
-        return REQ_ABORTED;
-    }
-
-    // get request body
-    int r = 0;
-    char *xb = xml_body;
-    size_t xl = xml_len;
-    while((r = netbuf_getbytes(sn->inbuf, xb, xl)) != NETBUF_EOF) {
-        xb += r;
-        xl -= r;
-    }
-    
-    /*
-     * parse the xml request and create the proppatch object
-     */
-    DavCollection *collection = rq->davCollection;
-    if(!collection) {
-        collection = pool_malloc(sn->pool, sizeof(DavCollection));
-        collection->mgr = ucx_map_cstr_get(pmgr_map, "default");
-    }
-    
-    ProppatchRequest *davrq = dav_parse_proppatch(sn, rq, xml_body, xml_len);
-    davrq->sn = sn;
-    davrq->rq = rq;
-    davrq->out = sbuf_new(512);
-    davrq->backend = collection->mgr;
-    davrq->propstat = propstat_create(sn->pool);
-    
-    
-    /* 
-     * 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 */
-    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");
-    UcxMapIterator nsiter = ucx_map_iterator(davrq->nsmap->map);
-    XmlNs *ns;
-    UCX_MAP_FOREACH(key, 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);
-    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);
-    
-    dav_free_proppatch(davrq);
-    
-    return REQ_PROCEED;
-}
-
-void dav_resource_response(PropfindRequest *davrq, sstr_t path, sstr_t uri) {
-    printf("dav_resource_response %s %s\n", sstrdup(path).ptr, sstrdup(uri).ptr);
-    
-    sbuf_puts(davrq->out, "<D:response>\n");
-    sbuf_puts(davrq->out, "<D:href>");
-    sbuf_append(davrq->out, uri);
-    sbuf_puts(davrq->out, "</D:href>\n");
-    
-    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) {
-        /* 
-         * there are some properties written, so we close the
-         * prop and propstat tag
-         */
-        sbuf_puts(davrq->out, "</D:prop>\n");
-        sbuf_puts(davrq->out, "<D:status>HTTP/1.1 200 OK</D:status>\n");
-        sbuf_puts(davrq->out, "</D:propstat>\n");
-    }
-    
-    if(davrq->notFoundProps != NULL) {
-        sbuf_puts(davrq->out, "<D:propstat>\n<D:prop>\n");
-        DAV_FOREACH(elm, davrq->notFoundProps) {
-            DavProperty *prop = (DavProperty*)elm->data;
-            sbuf_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");
-        }
-        sbuf_puts(davrq->out, "</D:prop>\n");
-        sbuf_puts(davrq->out, "<D:status>HTTP/1.1 404 Not Found</D:status>\n");
-        sbuf_puts(davrq->out, "</D:propstat>\n");
-    }
-    
-    sbuf_puts(davrq->out, "</D:response>\n");
-    
-    /* reset */
-    davrq->prop = 0;
-    davrq->notFoundProps = NULL;
-    davrq->forbiddenProps = NULL;
-    
-}
-
-void dav_propfind_add_str_prop(
-        PropfindRequest *davrq,
-        DavProperty* prop,
-        char *str,
-        size_t len)
-{
-    if(!davrq->prop) {
-        sbuf_puts(davrq->out, "<D:propstat>\n<D:prop>\n");
-        davrq->prop = 1;
-    }
-    
-    sbuf_put(davrq->out, '<');
-    sbuf_puts(davrq->out, prop->xmlns->prefix);
-    sbuf_put(davrq->out, ':');
-    sbuf_puts(davrq->out, prop->name);
-    sbuf_put(davrq->out, '>');
-    
-    sbuf_append(davrq->out, sstrn(str, len));
-    
-    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");
-}
-
-void dav_propfind_add_prop_error(
-        PropfindRequest *davrq,
-        DavProperty *prop,
-        int error)
-{
-    // TODO: different errors
-    davrq->notFoundProps = ucx_list_append(davrq->notFoundProps, prop);
-}
 
 
-
-
-/* WebDAV Default Backend */
-static PersistenceManager dav_file_backend = {
-    dav_rq_propfind_begin,
-    dav_rq_propfind_end,
-    dav_rq_propfind,
-    dav_rq_proppatch,
-    0
-};
-
-PersistenceManager* create_property_backend() {
-    return &dav_file_backend;
-}
-
-void dav_rq_propfind_begin(PersistenceManager *mgr, PropfindRequest *rq) {
-    
-}
-
-void dav_rq_propfind_end(PersistenceManager *mgr, PropfindRequest *rq) {
-    
-}
-
-void dav_rq_propfind(PersistenceManager *b, PropfindRequest *rq ,char *path) {
-    struct stat st;
-    if(stat(path, &st) != 0) {
-        perror("dav_be_propfind");
-        fprintf(stderr, "Cannot get stat of file: %s\n", path);
-    }
-    
-    if(rq->allprop) {
-        DavProperty prop;
-        prop.xmlns = xmlnsmap_get(rq->nsmap, "DAV:");
-        
-        prop.name = "resourcetype";
-        if(S_ISDIR(st.st_mode)) {
-            dav_propfind_add_str_prop(rq, &prop, "<D:collection/>", 15);
-        } else {
-            dav_propfind_add_str_prop(rq, &prop, NULL, 0);
-        }
-        
-        if(!S_ISDIR(st.st_mode)) {
-            prop.name = "getcontentlength";
-            char buf[32];
-            size_t n = snprintf(buf, 32, "%jd", st.st_size);
-            dav_propfind_add_str_prop(rq, &prop, buf, n);
-        }
-        
-        prop.name = "getlastmodified";
-
-        sstr_t s = date_format_http(st.st_mtime, rq->sn->pool);
-        dav_propfind_add_str_prop(rq, &prop, s.ptr, s.length);
-        
-        prop.name = "creationdate";
-        s = date_format_iso8601(st.st_ctime, rq->sn->pool);
-        dav_propfind_add_str_prop(rq, &prop, s.ptr, s.length);
-        
-        return;
-    }
-    
-    DAV_FOREACH(elm, rq->properties) {
-        DavProperty *prop = (DavProperty*)elm->data;
-        
-        char *s = prop->name;
-        if(!strcmp(s, "resourcetype")) {
-            if(S_ISDIR(st.st_mode)) {
-                dav_propfind_add_str_prop(rq, prop, "<D:collection/>", 15);
-            } else {
-                dav_propfind_add_str_prop(rq, prop, NULL, 0);
-            }
-        } else if(!strcmp(s, "getcontentlength") && !S_ISDIR(st.st_mode)) {
-            char buf[32];
-            size_t n = snprintf(buf, 32, "%jd", st.st_size);
-            dav_propfind_add_str_prop(rq, prop, buf, n);
-        } else if(!strcmp(s, "getlastmodified")) {
-            sstr_t s = date_format_http(st.st_mtime, rq->sn->pool);
-            dav_propfind_add_str_prop(rq, prop, s.ptr, s.length);
-        } else if(!strcmp(s, "creationdate")) {
-            sstr_t s = date_format_iso8601(st.st_ctime, rq->sn->pool);
-            dav_propfind_add_str_prop(rq, prop, s.ptr, s.length);
-        } else {
-            dav_propfind_add_prop_error(rq, prop, 404);
-        }
-    }
-}
-
-void dav_rq_proppatch(PersistenceManager *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(pool_handle_t *pool) {
-    XmlNsMap *map = pool_malloc(pool, sizeof(XmlNsMap));
-    UcxMap *uxm = ucx_map_new(16); // TODO: use pool for map
-    if(map == NULL || uxm == NULL) {
-        return NULL;
-    }
-    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;
-}
-
-void xmlnsmap_free(XmlNsMap *map) {
-    ucx_map_free(map->map);
-}
-
-XmlNs* xmlnsmap_put(XmlNsMap *map, char *ns) {
-    if(!ns) {
-        return NULL;
-    }
-    
-    XmlNs *xmlns = xmlnsmap_get(map, ns);
-    if(xmlns != NULL) {
-        return xmlns;
-    }
-    
-    xmlns = pool_malloc(map->pool, sizeof(XmlNs));
-    if(xmlns == NULL) {
-        return NULL;
-    }
-    
-    sstr_t newns = sstrdup(sstr(ns));
-    
-    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;
-}
-
-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_list_append(parent->content, child);
-    }
-}
-
-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, sstr(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, (UcxList*)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, sstr(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, sstr(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_list_append(propstat->okprop, prop);
-    } else {
-        UcxKey key;
-        key.data = &status;
-        key.len = sizeof(int);
-
-        UcxList *list = ucx_map_get(propstat->map, key);
-        list = ucx_list_append(list, prop);
-
-        ucx_map_put(propstat->map, key, list);
-    }
-}
-
-void propstat_write(Propstat *propstat, Buffer *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");
-    }
-    
-    UcxMapIterator iter = ucx_map_iterator(propstat->map);
-    UcxList *proplist;
-    UCX_MAP_FOREACH(key, proplist, iter) { 
-        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*)iter.cur->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");
-        }
-    }
-}

mercurial