src/server/plugins/postgresql/webdav.c

branch
webdav
changeset 307
8787cb5ebab3
parent 306
e03737cea6e2
child 309
fc021bd576d4
equal deleted inserted replaced
306:e03737cea6e2 307:8787cb5ebab3
55 55
56 // propfind with depth = 0 56 // propfind with depth = 0
57 // params: $1: resource_id 57 // params: $1: resource_id
58 static const char *sql_propfind_allprop_depth0 = "\ 58 static const char *sql_propfind_allprop_depth0 = "\
59 select\n\ 59 select\n\
60 NULL as ppath,\n\ 60 $2::text as ppath,\n\
61 r.resource_id,\n\ 61 r.resource_id,\n\
62 r.parent_id,\n\ 62 r.parent_id,\n\
63 r.nodename,\n\ 63 r.nodename,\n\
64 r.iscollection,\n\ 64 r.iscollection,\n\
65 r.lastmodified,\n\ 65 r.lastmodified,\n\
74 74
75 // propfind with depth = 0 for specific properties 75 // propfind with depth = 0 for specific properties
76 // params: $1: resource_id 76 // params: $1: resource_id
77 static const char *sql_propfind_depth0 = "\ 77 static const char *sql_propfind_depth0 = "\
78 select\n\ 78 select\n\
79 NULL as ppath,\n\ 79 $2::text as ppath,\n\
80 r.resource_id,\n\ 80 r.resource_id,\n\
81 r.parent_id,\n\ 81 r.parent_id,\n\
82 r.nodename,\n\ 82 r.nodename,\n\
83 r.iscollection,\n\ 83 r.iscollection,\n\
84 r.lastmodified,\n\ 84 r.lastmodified,\n\
87 p.xmlns,\n\ 87 p.xmlns,\n\
88 p.pname,\n\ 88 p.pname,\n\
89 p.pvalue\n\ 89 p.pvalue\n\
90 from Resource r\n\ 90 from Resource r\n\
91 left join Property p on r.resource_id = p.resource_id\n\ 91 left join Property p on r.resource_id = p.resource_id\n\
92 inner join (select unnest($2::text[]) as xmlns, unnest($3::text[]) as pname) n\n\ 92 inner join (select unnest($3::text[]) as xmlns, unnest($4::text[]) as pname) n\n\
93 on ( p.xmlns = n.xmlns and p.pname = n.pname ) or p.property_id is null\n\ 93 on ( p.xmlns = n.xmlns and p.pname = n.pname ) or p.property_id is null\n\
94 where r.resource_id = $1;"; 94 where r.resource_id = $1;";
95 95
96 // propfind with depth = 1 96 // propfind with depth = 1
97 // params: $1: resource_id 97 // params: $1: resource_id
98 static const char *sql_propfind_allprop_depth1 = "\ 98 static const char *sql_propfind_allprop_depth1 = "\
99 select\n\ 99 select\n\
100 NULL ass ppath,\n\ 100 case when r.resource_id = $1 then $2\n\
101 else $2 || '/' || r.nodename\n\
102 end as ppath,\n\
101 r.resource_id,\n\ 103 r.resource_id,\n\
102 r.parent_id,\n\ 104 r.parent_id,\n\
103 r.nodename,\n\ 105 r.nodename,\n\
104 r.iscollection,\n\ 106 r.iscollection,\n\
105 r.lastmodified,\n\ 107 r.lastmodified,\n\
116 118
117 // propfind with depth = 1 for specific properties 119 // propfind with depth = 1 for specific properties
118 // params: $1: resource_id 120 // params: $1: resource_id
119 static const char *sql_propfind_depth1 = "\ 121 static const char *sql_propfind_depth1 = "\
120 select\n\ 122 select\n\
121 NULL as ppath,\n\ 123 case when r.resource_id = $1 then $2\n\
124 else $2 || '/' || r.nodename\n\
125 end as ppath,\n\
122 r.resource_id,\n\ 126 r.resource_id,\n\
123 r.parent_id,\n\ 127 r.parent_id,\n\
124 r.nodename,\n\ 128 r.nodename,\n\
125 r.iscollection,\n\ 129 r.iscollection,\n\
126 r.lastmodified,\n\ 130 r.lastmodified,\n\
129 p.xmlns,\n\ 133 p.xmlns,\n\
130 p.pname,\n\ 134 p.pname,\n\
131 p.pvalue\n\ 135 p.pvalue\n\
132 from Resource r\n\ 136 from Resource r\n\
133 left join Property p on r.resource_id = p.resource_id\n\ 137 left join Property p on r.resource_id = p.resource_id\n\
134 inner join (select unnest($2::text[]) as xmlns, unnest($3::text[]) as pname) n\n\ 138 inner join (select unnest($3::text[]) as xmlns, unnest($4::text[]) as pname) n\n\
135 on ( p.xmlns = n.xmlns and p.pname = n.pname ) or p.property_id is null\n\ 139 on ( p.xmlns = n.xmlns and p.pname = n.pname ) or p.property_id is null\n\
136 where r.resource_id = $1 or r.parent_id = $1\n\ 140 where r.resource_id = $1 or r.parent_id = $1\n\
137 order by order by case when resource_id = $1 then 0 else 1 end, nodename, resource_id;"; 141 order by order by case when resource_id = $1 then 0 else 1 end, nodename, resource_id;";
138 142
139 // recursive propfind 143 // recursive propfind
151 r.*\n\ 155 r.*\n\
152 from Resource r\n\ 156 from Resource r\n\
153 inner join resolvepath p on r.parent_id = p.resource_id\n\ 157 inner join resolvepath p on r.parent_id = p.resource_id\n\
154 )\n\ 158 )\n\
155 select\n\ 159 select\n\
156 r.ppath,\n\ 160 case when r.resource_id = $1 then $2\n\
161 else $2 || r.ppath\n\
162 end as ppath,\n\
157 r.resource_id,\n\ 163 r.resource_id,\n\
158 r.parent_id,\n\ 164 r.parent_id,\n\
159 r.nodename,\n\ 165 r.nodename,\n\
160 r.iscollection,\n\ 166 r.iscollection,\n\
161 r.lastmodified,\n\ 167 r.lastmodified,\n\
185 r.*\n\ 191 r.*\n\
186 from Resource r\n\ 192 from Resource r\n\
187 inner join resolvepath p on r.parent_id = p.resource_id\n\ 193 inner join resolvepath p on r.parent_id = p.resource_id\n\
188 )\n\ 194 )\n\
189 select\n\ 195 select\n\
190 r.ppath,\n\ 196 case when r.resource_id = $1 then $2\n\
197 else $2 || '/' || r.ppath\n\
198 end as ppath,\n\
191 r.resource_id,\n\ 199 r.resource_id,\n\
192 r.parent_id,\n\ 200 r.parent_id,\n\
193 r.nodename,\n\ 201 r.nodename,\n\
194 r.iscollection,\n\ 202 r.iscollection,\n\
195 r.lastmodified,\n\ 203 r.lastmodified,\n\
248 256
249 257
250 int pg_dav_propfind_init( 258 int pg_dav_propfind_init(
251 WebdavPropfindRequest *rq, 259 WebdavPropfindRequest *rq,
252 const char *path, 260 const char *path,
261 const char *href,
253 WebdavPList **outplist) 262 WebdavPList **outplist)
254 { 263 {
255 PgWebdavBackend *pgdav = rq->dav->instance; 264 PgWebdavBackend *pgdav = rq->dav->instance;
256 265
257 // check if the resource exists 266 // check if the resource exists
293 302
294 // get all resources and properties 303 // get all resources and properties
295 char resource_id_str[32]; 304 char resource_id_str[32];
296 snprintf(resource_id_str, 32, "%" PRId64, resource_id); 305 snprintf(resource_id_str, 32, "%" PRId64, resource_id);
297 306
298 const char* params[1] = { resource_id_str }; 307 size_t href_len = strlen(href);
308 char *href_param = pool_malloc(rq->sn->pool, href_len + 1);
309 memcpy(href_param, href, href_len);
310 if(href_param[href_len-1] == '/') {
311 href_len--;
312 }
313 href_param[href_len] = '\0';
314
315
316 const char* params[2] = { resource_id_str, href_param };
299 PGresult *result = PQexecParams( 317 PGresult *result = PQexecParams(
300 pgdav->connection, 318 pgdav->connection,
301 sql_propfind_allprop_recursive, 319 sql_propfind_allprop_recursive,
302 1, // number of parameters 320 2, // number of parameters
303 NULL, 321 NULL,
304 params, // parameter value 322 params, // parameter value
305 NULL, 323 NULL,
306 NULL, 324 NULL,
307 0); // 0: result in text format 325 0); // 0: result in text format
308 int nrows = PQntuples(result); 326 int nrows = PQntuples(result);
327 pool_free(rq->sn->pool, href_param);
309 if(nrows < 1) { 328 if(nrows < 1) {
310 PQclear(result); 329 PQclear(result);
311 return 1; 330 return 1;
312 } 331 }
313 332
351 // 9: property name 370 // 9: property name
352 // 10: property value 371 // 10: property value
353 372
354 char *path = PQgetvalue(result, r, 0); 373 char *path = PQgetvalue(result, r, 0);
355 char *res_id = PQgetvalue(result, r, 1); 374 char *res_id = PQgetvalue(result, r, 1);
375 char *iscollection_str = PQgetvalue(result, r, 4);
376 WSBool iscollection = iscollection_str && iscollection_str[0] == 't';
356 int64_t resource_id; 377 int64_t resource_id;
357 if(!util_strtoint(res_id, &resource_id)) { 378 if(!util_strtoint(res_id, &resource_id)) {
358 log_ereport(LOG_FAILURE, "pg_dav_propfind_do: cannot convert resource_id '%s' to int", res_id); 379 log_ereport(LOG_FAILURE, "pg_dav_propfind_do: cannot convert resource_id '%s' to int", res_id);
359 return 1; 380 return 1;
360 } 381 }
361 382
362 char *nodename = PQgetvalue(result, r, 3); 383 char *nodename = PQgetvalue(result, r, 3);
363 if(resource_id != current_resource_id) { 384 if(resource_id != current_resource_id) {
385 // create a href string for the new resource
386 // if the resource is a collection, it should have a trailing '/'
387 size_t pathlen = strlen(path);
388 if(pathlen == 0) {
389 log_ereport(LOG_FAILURE, "pg_dav_propfind_do: query returned invalid path");
390 return 1;
391 }
392 char *newres_href = pool_malloc(pool, pathlen+2);
393 memcpy(newres_href, path, pathlen);
394 if(iscollection && path[pathlen-1] != '/') {
395 newres_href[pathlen++] = '/';
396 }
397 newres_href[pathlen] = '\0';
398
364 // new resource 399 // new resource
365 resource = response->addresource(response, nodename); 400 resource = response->addresource(response, newres_href);
366 vfsprops_set = FALSE; 401 vfsprops_set = FALSE;
367 current_resource_id = resource_id; 402 current_resource_id = resource_id;
368 } 403 }
369 404
370 // standard webdav properties 405 // standard webdav properties
371 if(!vfsprops_set) { 406 if(!vfsprops_set) {
372 if(vfsprops.getresourcetype) { 407 if(vfsprops.getresourcetype) {
373 char *iscollection = PQgetvalue(result, r, 4); 408 if(iscollection) {
374 if(iscollection && iscollection[0] == 't') {
375 resource->addproperty(resource, webdav_resourcetype_collection(), 200); 409 resource->addproperty(resource, webdav_resourcetype_collection(), 200);
376 } else { 410 } else {
377 resource->addproperty(resource, webdav_resourcetype_empty(), 200); 411 resource->addproperty(resource, webdav_resourcetype_empty(), 200);
378 } 412 }
379 } 413 }
404 property->lang = NULL; 438 property->lang = NULL;
405 property->name = pool_strdup(pool, pname); 439 property->name = pool_strdup(pool, pname);
406 440
407 xmlNs *namespace = pool_malloc(pool, sizeof(xmlNs)); 441 xmlNs *namespace = pool_malloc(pool, sizeof(xmlNs));
408 memset(namespace, 0, sizeof(struct _xmlNs)); 442 memset(namespace, 0, sizeof(struct _xmlNs));
409 namespace->href = pool_strdup(pool, xmlns); 443 namespace->href = (xmlChar*)pool_strdup(pool, xmlns);
410 namespace->prefix = "zx1"; 444 namespace->prefix = (xmlChar*)"zx1"; // TODO
411 property->namespace = namespace; 445 property->namespace = namespace;
412 446
413 property->vtype = WS_VALUE_TEXT; 447 property->vtype = WS_VALUE_TEXT;
414 property->value.text.str = pool_strdup(pool, pvalue); 448 property->value.text.str = pool_strdup(pool, pvalue);
415 property->value.text.length = strlen(pvalue); 449 property->value.text.length = strlen(pvalue);

mercurial