diff -r e03737cea6e2 -r 8787cb5ebab3 src/server/plugins/postgresql/webdav.c --- 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;