diff -r ff5826fc6a6c -r 5f05e56cb8e2 src/server/webdav/multistatus.c --- a/src/server/webdav/multistatus.c Tue Dec 31 16:31:29 2019 +0100 +++ b/src/server/webdav/multistatus.c Tue Jan 14 20:05:18 2020 +0100 @@ -56,206 +56,15 @@ return ms; } -static int send_xml_root(Multistatus *ms, Writer *out) { - writer_puts(out, S("\n" - "namespaces); - char *href; - UCX_MAP_FOREACH(key, href, i) { - writer_puts(out, S(" xmlns:")); - writer_put(out, key.data, key.len); - writer_puts(out, S("=\"")); - writer_puts(out, sstr(href)); - writer_puts(out, S("\"")); - } - - writer_puts(out, S(">\n")); - - return out->error; -} - -static int send_prop_name( - Multistatus *ms, - WebdavProperty *p, - Writer *out, - char *prefixbuf, - int *prefixbuflen) -{ - int in_prefix_len = *prefixbuflen; - *prefixbuflen = 0; - - writer_putc(out, '<'); - - const char *prefix = NULL; - const char *href = NULL; - - if(p->namespace && p->namespace->href) { - href = (const char*)p->namespace->href; - - if(p->namespace->prefix) { - // check if there is a namespace with this prefix already defined - // and has the same namespace uri - prefix = (const char*)p->namespace->prefix; - char *nshref = ucx_map_cstr_get( - ms->namespaces, - (const char*)p->namespace->prefix); - if(!strcmp(nshref, href)) { - href = NULL; // we don't need a new xmlns def - } - } else { - // generate new prefix - for(int i=0;i<1024;i++) { - int len = snprintf(prefixbuf, in_prefix_len, "x%d\0", i); - char *test = ucx_map_cstr_get(ms->namespaces, prefixbuf); - if(!test) { - prefix = prefixbuf; - *prefixbuflen = len; - break; // found an unused prefix - } - if(!prefix) { - // What? Can't find a free prefix? - return 1; - } - } - } - } - - if(prefix) { - writer_put(out, prefix, strlen(prefix)); - writer_put(out, ":", 1); - } - - // write xml element name - writer_put(out, (const char*)p->name, strlen((const char*)p->name)); - - if(href) { - writer_puts(out, S(" xmlns:")); - writer_put(out, prefix, strlen(prefix)); - writer_puts(out, S("=\"")); - writer_put(out, href, strlen(href)); - writer_putc(out, '\"'); - } - - if(p->lang) { - writer_puts(out, S(" lang=\"")); - writer_puts(out, sstr(p->lang)); - writer_putc(out, '\"'); - } - - writer_putc(out, '>'); - - return out->error; -} - - - -#define MAX_XML_TREE_DEPTH 128 -static int send_xml(Multistatus *ms, Writer *out, WSXmlNode *node, WSNamespace *rootns, int depth) { - int ret = 0; - const char *s; - while(node) { - switch(node->type) { - case XML_ELEMENT_NODE: { - writer_putc(out, '<'); - if(node->ns && node->ns->prefix) { - s = (const char*)node->ns->prefix; - writer_put(out, s, strlen(s)); - writer_putc(out, ':'); - } - s = (const char*)node->name; - writer_put(out, s, strlen(s)); - - - } - - } - node = node->next; - } - - return ret; -} - -static int send_response_tag(Multistatus *ms, MSResponse *rp, Writer *out) { - writer_puts(out, S(" \n" - " ")); - writer_puts(out, sstr(rp->resource.href)); - writer_puts(out, S("\n")); - - if(rp->plist_begin) { - writer_puts(out, S(" " - " \n")); - WebdavPList *p = rp->plist_begin; - char prefix[16]; - while(p) { - WebdavProperty *prop = p->property; - int prefixlen = 16; - if(send_prop_name(ms, prop, out, prefix, &prefixlen)) { - return 1; - } - - // send content - - - // send end tag - writer_put(out, "<", 1); - if(prop->namespace && prop->namespace->href) { - const char *pre = NULL; - if(prop->namespace->prefix) { - pre = (const char*)prop->namespace->prefix; - } else if(prefixlen > 0) { - pre = prefix; - } - - if(pre) { - writer_put(out, pre, strlen(pre)); - writer_put(out, ":", 1); - } - } - writer_put(out, prop->name, strlen(prop->name)); - writer_put(out, ">", 1); - - if(out->error) { - return 1; - } - - p = p->next; - } - writer_puts(out, S(" \n" - " HTTP/1.1 200 OK" - " \n")); - } - - return out->error; -} - int multistatus_send(Multistatus *ms, SYS_NETFD net) { char buffer[MULTISTATUS_BUFFER_LENGTH]; Writer writer; Writer *out = &writer; writer_init(out, net, buffer, MULTISTATUS_BUFFER_LENGTH); - // send the xml root element with namespace defs - if(send_xml_root(ms, out)) { - return 1; - } - // send response tags - MSResponse *response = ms->first; - while(response) { - if(send_response_tag(ms, response, out)) { - return 1; - } - response = response->next; - } - - return 0; } - WebdavResource * multistatus_addresource( WebdavResponse *response, const char *path) @@ -267,6 +76,10 @@ } ZERO(res, sizeof(MSResponse)); + // set href + res->resource.href = pool_strdup(response->op->sn->pool, path); + + // add resource funcs res->resource.addproperty = msresponse_addproperty; res->resource.close = msresponse_close; @@ -275,7 +88,9 @@ res->resource.isclosed = 0; res->closing = 0; + // add new resource to the resource list if(ms->current) { + // before adding a new resource, the current resource must be closed if(!ms->current->resource.isclosed) { msresponse_close((WebdavResource*)ms->current); } @@ -302,26 +117,91 @@ return 0; } + // some WebdavProperty checks to make sure nothing explodes + if(!property->namespace || !property->namespace->href) { + // error: namespace is required + log_ereport( + LOG_FAILURE, + "%s", + "webdav: property '%s' has no namespace", + property->name); + return 1; + } + if(property->nsdef) { + // error: nsdef MUST be NULL, only fill nsdef in this func + log_ereport( + LOG_FAILURE, + "%s", + "webdav: property '%s': nsdef must be null", + property->name); + return 1; + } + // add namespace of this property to the namespace map - if(property->namespace && property->namespace->prefix) { + // the namespace map will be used for global namespace definitions + if(property->namespace->prefix) { char *ns = ucx_map_cstr_get( response->multistatus->namespaces, (const char*)property->namespace->prefix); if(!ns) { + // prefix is not in use -> we can add the namespace to the ns map int err = ucx_map_cstr_put( response->multistatus->namespaces, (const char*)property->namespace->prefix, property->namespace->href); if(err) { - return 1; + return 1; // OOM } + } else if(strcmp((char*)property->namespace->href, ns)) { + // global namespace != local namespace + // therefore we need a namespace definition in this element + + if(webdav_property_add_nsdef( + property, + response->multistatus->sn->pool, + (const char*)property->namespace->prefix, + (const char*)property->namespace->href)) + { + return 1; // OOM + } } } - if(status != 200) { + // error properties will be added to a separate list + if(status != 200) { return msresponse_addproperror(response, property, status); } + // add all namespaces used by this property to the nsdef list + if(property->vtype == WS_VALUE_XML_NODE) { + // iterate over xml tree and collect all namespaces + + // TODO: implement + } else if(property->vtype == WS_VALUE_XML_DATA) { + // xml data contains a list of all used namespaces + WebdavNSList *nslist = property->value.data->namespaces; + while(nslist) { + // only add the namespace to the definitions list, if it isn't + // property namespace, because the prop ns is already added + // to the element's def list or global definitions list + if(strcmp( + (const char*)nslist->namespace->prefix, + (const char*)property->namespace->prefix)) + { + // ns-prefix != property-prefix -> add ns to nsdef + if(webdav_property_add_nsdef( + property, + response->multistatus->sn->pool, + (const char*)nslist->namespace->prefix, + (const char*)nslist->namespace->href)) + { + return 1; // OOM + } + } + nslist = nslist->next; + } + } // other value types don't contain xml namespaces + // add property to the list WebdavPList *listelm = pool_malloc( response->multistatus->sn->pool,