--- 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");