Thu, 16 Jan 2020 21:31:16 +0100
add function for getting all namespace definitions that are required for an element
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2019 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 "../daemon/session.h" #include "operation.h" #include "multistatus.h" #define MULTISTATUS_BUFFER_LENGTH 2048 Multistatus* multistatus_response(Session *sn, Request *rq) { Multistatus *ms = pool_malloc(sn->pool, sizeof(Multistatus)); if(!ms) { return NULL; } ZERO(ms, sizeof(Multistatus)); ms->response.addresource = multistatus_addresource; ms->sn = sn; ms->rq = rq; ms->namespaces = ucx_map_new_a(session_get_allocator(ms->sn), 8); if(!ms->namespaces) { return NULL; } if(ucx_map_cstr_put(ms->namespaces, "D", "DAV:")) { return NULL; } return ms; } 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); } WebdavResource * multistatus_addresource( WebdavResponse *response, const char *path) { Multistatus *ms = (Multistatus*)response; MSResponse *res = pool_malloc(ms->sn->pool, sizeof(MSResponse)); if(!res) { return NULL; } ZERO(res, sizeof(MSResponse)); // set href res->resource.href = pool_strdup(ms->sn->pool, path); // add resource funcs res->resource.addproperty = msresponse_addproperty; res->resource.close = msresponse_close; res->multistatus = ms; res->errors = NULL; 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); } ms->current->next = res; } else { ms->first = res; } ms->current = res; return (WebdavResource*)res; } int msresponse_addproperty( WebdavResource *res, WebdavProperty *property, int status) { MSResponse *response = (MSResponse*)res; if(response->resource.isclosed) { log_ereport( LOG_WARN, "%s", "webdav: cannot add property to closed response tag"); 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 // 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; // 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 } } } // 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, sizeof(WebdavPList)); if(!listelm) { return 1; } listelm->property = property; listelm->next = NULL; if(response->plist_end) { response->plist_end->next = listelm; } else { response->plist_begin = listelm; } response->plist_end = listelm; return 0; } int msresponse_addproperror( MSResponse *response, WebdavProperty *property, int statuscode) { pool_handle_t *pool = response->multistatus->sn->pool; UcxAllocator *a = session_get_allocator(response->multistatus->sn); // MSResponse contains a list of properties for each status code // at first find the list for this status code PropertyErrorList *errlist = NULL; PropertyErrorList *list = response->errors; PropertyErrorList *last = NULL; while(list) { if(list->status == statuscode) { errlist = list; break; } last = list; list = list->next; } if(!errlist) { // no list available for this statuscode PropertyErrorList *newelm = pool_malloc(pool, sizeof(PropertyErrorList)); if(!newelm) { return 1; } newelm->begin = NULL; newelm->end = NULL; newelm->next = NULL; newelm->status = statuscode; if(last) { last->next = newelm; } else { response->errors = newelm; } errlist = newelm; } // we have the list -> add the new element UcxList *newlistelm = ucx_list_append_a(a, errlist->end, property); if(!newlistelm) { return 1; } errlist->end = newlistelm; if(!errlist->begin) { errlist->begin = newlistelm; } return 0; } int msresponse_close(WebdavResource *res) { MSResponse *response = (MSResponse*)res; if(response->closing) { return 0; // close already in progress } int ret = REQ_PROCEED; WebdavOperation *op = response->multistatus->response.op; if(webdav_op_propfiond_close_resource(op, res)) { ret = REQ_ABORTED; } response->resource.isclosed = TRUE; response->closing = FALSE; return ret; }