src/server/webdav/multistatus.c

branch
webdav
changeset 222
5f05e56cb8e2
parent 217
8ed14d76db42
child 223
bbaec8415c10
--- 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("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
-                       "<D:multistatus"));
-    
-    // write the namespaces definitions
-    // key is the namespace prefix
-    // the map always contains the "DAV:" namespace with the prefix "D"
-    UcxMapIterator i = ucx_map_iterator(ms->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("  <D:response>\n"
-                       "    <D:href>"));
-    writer_puts(out, sstr(rp->resource.href));
-    writer_puts(out, S("</href>\n"));
-    
-    if(rp->plist_begin) {
-        writer_puts(out, S("    <D:propstat>"
-                           "      <D:prop>\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("      </D:prop>\n"
-                           "      <D:status>HTTP/1.1 200 OK</D:status>"
-                           "    </D:propstat>\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,

mercurial