diff -r 6b1a6066ee43 -r b608b7aa43a6 src/server/plugins/postgresql/webdav.c --- a/src/server/plugins/postgresql/webdav.c Mon Apr 25 22:38:05 2022 +0200 +++ b/src/server/plugins/postgresql/webdav.c Tue Apr 26 14:33:58 2022 +0200 @@ -31,6 +31,7 @@ #include "../../util/util.h" +#include #include static WebdavBackend pg_webdav_backend = { @@ -88,9 +89,11 @@ p.pname,\n\ p.pvalue\n\ from Resource r\n\ -left join Property p on r.resource_id = p.resource_id\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\ +left join (\n\ + select p.* from Property p\ + 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\n\ +) p on r.resource_id = p.resource_id\n\ where r.resource_id = $1;"; // propfind with depth = 1 @@ -113,7 +116,7 @@ from Resource r\n\ left join Property p on r.resource_id = p.resource_id\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;"; +order by case when r.resource_id = $1 then 0 else 1 end, nodename, resource_id;"; // propfind with depth = 1 for specific properties @@ -134,11 +137,13 @@ p.pname,\n\ p.pvalue\n\ from Resource r\n\ -left join Property p on r.resource_id = p.resource_id\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\ +left join (\n\ + select p.* from Property p\ + 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\n\ +) p on r.resource_id = p.resource_id\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;"; +order by case when r.resource_id = $1 then 0 else 1 end, nodename, resource_id;"; // recursive propfind // params: $1: resource_id @@ -194,7 +199,7 @@ )\n\ select\n\ case when r.resource_id = $1 then $2\n\ - else $2 || '/' || r.ppath\n\ + else $2 || r.ppath\n\ end as ppath,\n\ r.resource_id,\n\ r.parent_id,\n\ @@ -207,9 +212,11 @@ p.pname,\n\ p.pvalue\n\ from resolvepath 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\ - on ( p.xmlns = n.xmlns and p.pname = n.pname ) or p.property_id is null\n\ +left join (\n\ + select p.* from Property p\ + 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\n\ +) p on r.resource_id = p.resource_id\n\ order by replace(ppath, '/', chr(1)), resource_id;"; WebdavBackend* pg_webdav_create(Session *sn, Request *rq, pblock *pb) { @@ -254,6 +261,49 @@ return NULL; } +/* + * adds str to the buffer + * some characters will be escaped: \,{} + */ +static void buf_addstr_escaped(UcxBuffer *buf, const char *str) { + size_t len = strlen(str); + for(size_t i=0;iproperty; + if(property && property->namespace && property->namespace->href && property->name) { + buf_addstr_escaped(xmlns, (const char*)property->namespace->href); + buf_addstr_escaped(pname, (const char*)property->name); + if(plist->next) { + ucx_buffer_putc(xmlns, ','); + ucx_buffer_putc(pname, ','); + } + } + plist = plist->next; + } + int r1 = ucx_buffer_write("}\0", 2, 1, xmlns) == 0; + int r2 = ucx_buffer_write("}\0", 2, 1, pname) == 0; + return r1+r2 != 0; +} + int pg_dav_propfind_init( WebdavPropfindRequest *rq, @@ -312,12 +362,38 @@ } href_param[href_len] = '\0'; + // if allprop is false, create array pair for xmlns/property names + UcxBuffer *xmlns_buf = NULL; + UcxBuffer *pname_buf = NULL; + char *xmlns_param = NULL; + char *pname_param = NULL; + int nparam = 2; + if(!rq->allprop) { + size_t bufsize = rq->propcount < 200 ? 8 + rq->propcount * 32 : 4096; + xmlns_buf = ucx_buffer_new(NULL, bufsize, UCX_BUFFER_AUTOEXTEND); + if(!xmlns_buf) { + return 1; + } + pname_buf = ucx_buffer_new(NULL, bufsize, UCX_BUFFER_AUTOEXTEND); + if(!pname_buf) { + ucx_buffer_free(xmlns_buf); + return 1; + } + if(pg_create_property_param_arrays(rq->properties, xmlns_buf, pname_buf)) { + ucx_buffer_free(xmlns_buf); + ucx_buffer_free(pname_buf); + return 1; + } + xmlns_param = xmlns_buf->space; + pname_param = pname_buf->space; + nparam = 4; + } - const char* params[2] = { resource_id_str, href_param }; + const char* params[4] = { resource_id_str, href_param, xmlns_param, pname_param }; PGresult *result = PQexecParams( pgdav->connection, - sql_propfind_allprop_recursive, - 2, // number of parameters + query, + nparam, // number of parameters NULL, params, // parameter value NULL, @@ -325,6 +401,10 @@ 0); // 0: result in text format int nrows = PQntuples(result); pool_free(rq->sn->pool, href_param); + if(xmlns_buf) { + ucx_buffer_free(xmlns_buf); + ucx_buffer_free(pname_buf); + } if(nrows < 1) { PQclear(result); return 1;