Mon, 25 Apr 2022 13:48:05 +0200
fix href in pg propfind response
--- a/src/server/plugins/postgresql/pgtest.c Sun Apr 24 18:35:44 2022 +0200 +++ b/src/server/plugins/postgresql/pgtest.c Mon Apr 25 13:48:05 2022 +0200 @@ -457,7 +457,7 @@ int ret; // Test 1 - init_test_webdav_method(&sn, &rq, &st, &pb, "PROPFIND", "/propfind", PG_TEST_PROPFIND1); + init_test_webdav_method(&sn, &rq, &st, &pb, "PROPFIND", "/propfind/", PG_TEST_PROPFIND1); rq->davCollection = create_test_pgdav(sn, rq); ret = webdav_propfind(pb, sn, rq);
--- 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;
--- a/src/server/plugins/postgresql/webdav.h Sun Apr 24 18:35:44 2022 +0200 +++ b/src/server/plugins/postgresql/webdav.h Mon Apr 25 13:48:05 2022 +0200 @@ -60,6 +60,7 @@ int pg_dav_propfind_init( WebdavPropfindRequest *rq, const char *path, + const char *href, WebdavPList **outplist); int pg_dav_propfind_do(
--- a/src/server/public/webdav.h Sun Apr 24 18:35:44 2022 +0200 +++ b/src/server/public/webdav.h Mon Apr 25 13:48:05 2022 +0200 @@ -272,6 +272,7 @@ * int propfind_init( * WebdavPropfindRequest *rq, * const char *path, + * const char *href, * WebdavPList **outplist); * * Initializes a propfind request. This is called once for each propfind @@ -279,7 +280,7 @@ * multistatus response. * */ - int (*propfind_init)(WebdavPropfindRequest *, const char *, WebdavPList **); + int (*propfind_init)(WebdavPropfindRequest *, const char *, const char *, WebdavPList **); /* * int propfind_do(
--- a/src/server/test/webdav.c Sun Apr 24 18:35:44 2022 +0200 +++ b/src/server/test/webdav.c Mon Apr 25 13:48:05 2022 +0200 @@ -55,6 +55,7 @@ static int backend2_propfind_init( WebdavPropfindRequest *propfind, const char *path, + const char *href, WebdavPList **outPList) { backend2_init_called = 1; @@ -145,6 +146,7 @@ static int backend1_propfind_init( WebdavPropfindRequest *propfind, const char *path, + const char *href, WebdavPList **outPList) { backend1_init_called = 1; @@ -313,7 +315,7 @@ UcxList *requests = NULL; // Initialize all Webdav Backends - if(webdav_propfind_init(&backend1, propfind, "/", &requests)) { + if(webdav_propfind_init(&backend1, propfind, "/", "/", &requests)) { return NULL; } @@ -996,7 +998,7 @@ UCX_TEST_ASSERT(!test_init(&sn, &rq, &propfind, TEST_PROPFIND1), "init failed"); UcxList *requests = NULL; - int err = webdav_propfind_init(&backend1, propfind, "/", &requests); + int err = webdav_propfind_init(&backend1, propfind, "/", "/", &requests); UCX_TEST_ASSERT(!err, "webdav_propfind_init failed"); UCX_TEST_ASSERT(requests, "request list is empty");
--- a/src/server/test/webdav.h Sun Apr 24 18:35:44 2022 +0200 +++ b/src/server/test/webdav.h Mon Apr 25 13:48:05 2022 +0200 @@ -32,6 +32,8 @@ #include "../public/nsapi.h" #include "../public/webdav.h" +#include "testutils.h" + #include <ucx/test.h> #ifdef __cplusplus
--- a/src/server/webdav/webdav.c Sun Apr 24 18:35:44 2022 +0200 +++ b/src/server/webdav/webdav.c Mon Apr 25 13:48:05 2022 +0200 @@ -278,6 +278,7 @@ WebdavBackend *dav, WebdavPropfindRequest *propfind, const char *path, + const char *uri, UcxList **out_req) { pool_handle_t *pool = propfind->sn->pool; @@ -317,7 +318,7 @@ // run init: this can generate a new properties list (newProp) // which will be passed to the next backend - if(davList->propfind_init(pReq, path, &newProp)) { + if(davList->propfind_init(pReq, path, uri, &newProp)) { return REQ_ABORTED; } @@ -348,7 +349,7 @@ UcxList *requestObjects = NULL; // Initialize all Webdav Backends - if(webdav_propfind_init(dav, propfind, path, &requestObjects)) { + if(webdav_propfind_init(dav, propfind, path, uri, &requestObjects)) { return REQ_ABORTED; } @@ -765,6 +766,7 @@ int default_propfind_init( WebdavPropfindRequest *rq, const char* path, + const char *href, WebdavPList **outplist) { DefaultWebdavData *data = pool_malloc(
--- a/src/server/webdav/webdav.h Sun Apr 24 18:35:44 2022 +0200 +++ b/src/server/webdav/webdav.h Mon Apr 25 13:48:05 2022 +0200 @@ -66,6 +66,7 @@ WebdavBackend *dav, WebdavPropfindRequest *propfind, const char *path, + const char *uri, UcxList **out_req); int webdav_propfind_do( @@ -93,7 +94,8 @@ int default_propfind_init( WebdavPropfindRequest *rq, - const char* path, + const char *path, + const char *href, WebdavPList **outplist); int default_propfind_do( WebdavPropfindRequest *request,