src/server/plugins/postgresql/webdav.c

branch
webdav
changeset 307
8787cb5ebab3
parent 306
e03737cea6e2
child 309
fc021bd576d4
--- a/src/server/plugins/postgresql/webdav.c	Sun Apr 24 18:35:44 2022 +0200
+++ b/src/server/plugins/postgresql/webdav.c	Mon Apr 25 13:48:05 2022 +0200
@@ -57,7 +57,7 @@
 // params: $1: resource_id
 static const char *sql_propfind_allprop_depth0 = "\
 select\n\
-    NULL as ppath,\n\
+    $2::text as ppath,\n\
     r.resource_id,\n\
     r.parent_id,\n\
     r.nodename,\n\
@@ -76,7 +76,7 @@
 // params: $1: resource_id
 static const char *sql_propfind_depth0 = "\
 select\n\
-    NULL as ppath,\n\
+    $2::text as ppath,\n\
     r.resource_id,\n\
     r.parent_id,\n\
     r.nodename,\n\
@@ -89,7 +89,7 @@
     p.pvalue\n\
 from Resource r\n\
 left join Property p on r.resource_id = p.resource_id\n\
-inner join (select unnest($2::text[]) as xmlns, unnest($3::text[]) as pname) n\n\
+inner join (select unnest($3::text[]) as xmlns, unnest($4::text[]) as pname) n\n\
    on ( p.xmlns = n.xmlns and p.pname = n.pname ) or p.property_id is null\n\
 where r.resource_id = $1;";
 
@@ -97,7 +97,9 @@
 // params: $1: resource_id
 static const char *sql_propfind_allprop_depth1 = "\
 select\n\
-    NULL ass ppath,\n\
+    case when r.resource_id = $1 then $2\n\
+         else $2 || '/' || r.nodename\n\
+    end as ppath,\n\
     r.resource_id,\n\
     r.parent_id,\n\
     r.nodename,\n\
@@ -118,7 +120,9 @@
 // params: $1: resource_id
 static const char *sql_propfind_depth1 = "\
 select\n\
-    NULL as ppath,\n\
+    case when r.resource_id = $1 then $2\n\
+         else $2 || '/' || r.nodename\n\
+    end as ppath,\n\
     r.resource_id,\n\
     r.parent_id,\n\
     r.nodename,\n\
@@ -131,7 +135,7 @@
     p.pvalue\n\
 from Resource r\n\
 left join Property p on r.resource_id = p.resource_id\n\
-inner join (select unnest($2::text[]) as xmlns, unnest($3::text[]) as pname) n\n\
+inner join (select unnest($3::text[]) as xmlns, unnest($4::text[]) as pname) n\n\
    on ( p.xmlns = n.xmlns and p.pname = n.pname ) or p.property_id is null\n\
 where r.resource_id = $1 or r.parent_id = $1\n\
 order by order by case when resource_id = $1 then 0 else 1 end, nodename, resource_id;";
@@ -153,7 +157,9 @@
     inner join resolvepath p on r.parent_id = p.resource_id\n\
     )\n\
 select\n\
-    r.ppath,\n\
+    case when r.resource_id = $1 then $2\n\
+         else $2 || r.ppath\n\
+    end as ppath,\n\
     r.resource_id,\n\
     r.parent_id,\n\
     r.nodename,\n\
@@ -187,7 +193,9 @@
     inner join resolvepath p on r.parent_id = p.resource_id\n\
     )\n\
 select\n\
-    r.ppath,\n\
+    case when r.resource_id = $1 then $2\n\
+         else $2 || '/' || r.ppath\n\
+    end as ppath,\n\
     r.resource_id,\n\
     r.parent_id,\n\
     r.nodename,\n\
@@ -250,6 +258,7 @@
 int pg_dav_propfind_init(
         WebdavPropfindRequest *rq,
         const char *path,
+        const char *href,
         WebdavPList **outplist)
 {
     PgWebdavBackend *pgdav = rq->dav->instance;
@@ -295,17 +304,27 @@
     char resource_id_str[32];
     snprintf(resource_id_str, 32, "%" PRId64, resource_id);
     
-    const char* params[1] = { resource_id_str };
+    size_t href_len = strlen(href);
+    char *href_param = pool_malloc(rq->sn->pool, href_len + 1);
+    memcpy(href_param, href, href_len);
+    if(href_param[href_len-1] == '/') {
+        href_len--;
+    }
+    href_param[href_len] = '\0';
+    
+    
+    const char* params[2] = { resource_id_str, href_param };
     PGresult *result = PQexecParams(
             pgdav->connection,
             sql_propfind_allprop_recursive,
-            1,     // number of parameters
+            2,     // number of parameters
             NULL,
             params, // parameter value
             NULL,
             NULL,
             0);    // 0: result in text format
     int nrows = PQntuples(result);
+    pool_free(rq->sn->pool, href_param);
     if(nrows < 1) {
         PQclear(result);
         return 1;
@@ -353,6 +372,8 @@
         
         char *path = PQgetvalue(result, r, 0);
         char *res_id = PQgetvalue(result, r, 1);
+        char *iscollection_str = PQgetvalue(result, r, 4);
+        WSBool iscollection = iscollection_str && iscollection_str[0] == 't';
         int64_t resource_id;
         if(!util_strtoint(res_id, &resource_id)) {
             log_ereport(LOG_FAILURE, "pg_dav_propfind_do: cannot convert resource_id '%s' to int", res_id);
@@ -361,8 +382,22 @@
         
         char *nodename = PQgetvalue(result, r, 3);
         if(resource_id != current_resource_id) {
+            // create a href string for the new resource
+            // if the resource is a collection, it should have a trailing '/'
+            size_t pathlen = strlen(path);
+            if(pathlen == 0) {
+                log_ereport(LOG_FAILURE, "pg_dav_propfind_do: query returned invalid path");
+                return 1;
+            }
+            char *newres_href = pool_malloc(pool, pathlen+2);
+            memcpy(newres_href, path, pathlen);
+            if(iscollection && path[pathlen-1] != '/') {
+                newres_href[pathlen++] = '/';
+            }
+            newres_href[pathlen] = '\0';
+            
             // new resource
-            resource = response->addresource(response, nodename);
+            resource = response->addresource(response, newres_href);
             vfsprops_set = FALSE;
             current_resource_id = resource_id;
         }
@@ -370,8 +405,7 @@
         // standard webdav properties
         if(!vfsprops_set) {
             if(vfsprops.getresourcetype) {
-                char *iscollection = PQgetvalue(result, r, 4);
-                if(iscollection && iscollection[0] == 't') {
+                if(iscollection) {
                     resource->addproperty(resource, webdav_resourcetype_collection(), 200);
                 } else {
                     resource->addproperty(resource, webdav_resourcetype_empty(), 200);
@@ -406,8 +440,8 @@
             
             xmlNs *namespace = pool_malloc(pool, sizeof(xmlNs));
             memset(namespace, 0, sizeof(struct _xmlNs));
-            namespace->href = pool_strdup(pool, xmlns);
-            namespace->prefix = "zx1";
+            namespace->href = (xmlChar*)pool_strdup(pool, xmlns);
+            namespace->prefix = (xmlChar*)"zx1"; // TODO
             property->namespace = namespace;
             
             property->vtype = WS_VALUE_TEXT;

mercurial