src/server/plugins/postgresql/webdav.c

branch
webdav
changeset 315
b608b7aa43a6
parent 314
6b1a6066ee43
child 317
09676b559091
equal deleted inserted replaced
314:6b1a6066ee43 315:b608b7aa43a6
29 #include "webdav.h" 29 #include "webdav.h"
30 #include "vfs.h" 30 #include "vfs.h"
31 31
32 #include "../../util/util.h" 32 #include "../../util/util.h"
33 33
34 #include <ucx/buffer.h>
34 #include <libxml/tree.h> 35 #include <libxml/tree.h>
35 36
36 static WebdavBackend pg_webdav_backend = { 37 static WebdavBackend pg_webdav_backend = {
37 pg_dav_propfind_init, 38 pg_dav_propfind_init,
38 pg_dav_propfind_do, 39 pg_dav_propfind_do,
86 r.contentlength,\n\ 87 r.contentlength,\n\
87 p.xmlns,\n\ 88 p.xmlns,\n\
88 p.pname,\n\ 89 p.pname,\n\
89 p.pvalue\n\ 90 p.pvalue\n\
90 from Resource r\n\ 91 from Resource r\n\
91 left join Property p on r.resource_id = p.resource_id\n\ 92 left join (\n\
92 inner join (select unnest($3::text[]) as xmlns, unnest($4::text[]) as pname) n\n\ 93 select p.* from Property p\
93 on ( p.xmlns = n.xmlns and p.pname = n.pname ) or p.property_id is null\n\ 94 inner join (select unnest($3::text[]) as xmlns, unnest($4::text[]) as pname) n\n\
95 on p.xmlns = n.xmlns and p.pname = n.pname\n\
96 ) p on r.resource_id = p.resource_id\n\
94 where r.resource_id = $1;"; 97 where r.resource_id = $1;";
95 98
96 // propfind with depth = 1 99 // propfind with depth = 1
97 // params: $1: resource_id 100 // params: $1: resource_id
98 static const char *sql_propfind_allprop_depth1 = "\ 101 static const char *sql_propfind_allprop_depth1 = "\
111 p.pname,\n\ 114 p.pname,\n\
112 p.pvalue\n\ 115 p.pvalue\n\
113 from Resource r\n\ 116 from Resource r\n\
114 left join Property p on r.resource_id = p.resource_id\n\ 117 left join Property p on r.resource_id = p.resource_id\n\
115 where r.resource_id = $1 or r.parent_id = $1\n\ 118 where r.resource_id = $1 or r.parent_id = $1\n\
116 order by order by case when resource_id = $1 then 0 else 1 end, nodename, resource_id;"; 119 order by case when r.resource_id = $1 then 0 else 1 end, nodename, resource_id;";
117 120
118 121
119 // propfind with depth = 1 for specific properties 122 // propfind with depth = 1 for specific properties
120 // params: $1: resource_id 123 // params: $1: resource_id
121 static const char *sql_propfind_depth1 = "\ 124 static const char *sql_propfind_depth1 = "\
132 r.contentlength,\n\ 135 r.contentlength,\n\
133 p.xmlns,\n\ 136 p.xmlns,\n\
134 p.pname,\n\ 137 p.pname,\n\
135 p.pvalue\n\ 138 p.pvalue\n\
136 from Resource r\n\ 139 from Resource r\n\
137 left join Property p on r.resource_id = p.resource_id\n\ 140 left join (\n\
138 inner join (select unnest($3::text[]) as xmlns, unnest($4::text[]) as pname) n\n\ 141 select p.* from Property p\
139 on ( p.xmlns = n.xmlns and p.pname = n.pname ) or p.property_id is null\n\ 142 inner join (select unnest($3::text[]) as xmlns, unnest($4::text[]) as pname) n\n\
143 on p.xmlns = n.xmlns and p.pname = n.pname\n\
144 ) p on r.resource_id = p.resource_id\n\
140 where r.resource_id = $1 or r.parent_id = $1\n\ 145 where r.resource_id = $1 or r.parent_id = $1\n\
141 order by order by case when resource_id = $1 then 0 else 1 end, nodename, resource_id;"; 146 order by case when r.resource_id = $1 then 0 else 1 end, nodename, resource_id;";
142 147
143 // recursive propfind 148 // recursive propfind
144 // params: $1: resource_id 149 // params: $1: resource_id
145 static const char *sql_propfind_allprop_recursive = "\ 150 static const char *sql_propfind_allprop_recursive = "\
146 with recursive resolvepath as (\n\ 151 with recursive resolvepath as (\n\
192 from Resource r\n\ 197 from Resource r\n\
193 inner join resolvepath p on r.parent_id = p.resource_id\n\ 198 inner join resolvepath p on r.parent_id = p.resource_id\n\
194 )\n\ 199 )\n\
195 select\n\ 200 select\n\
196 case when r.resource_id = $1 then $2\n\ 201 case when r.resource_id = $1 then $2\n\
197 else $2 || '/' || r.ppath\n\ 202 else $2 || r.ppath\n\
198 end as ppath,\n\ 203 end as ppath,\n\
199 r.resource_id,\n\ 204 r.resource_id,\n\
200 r.parent_id,\n\ 205 r.parent_id,\n\
201 r.nodename,\n\ 206 r.nodename,\n\
202 r.iscollection,\n\ 207 r.iscollection,\n\
205 r.contentlength,\n\ 210 r.contentlength,\n\
206 p.xmlns,\n\ 211 p.xmlns,\n\
207 p.pname,\n\ 212 p.pname,\n\
208 p.pvalue\n\ 213 p.pvalue\n\
209 from resolvepath r\n\ 214 from resolvepath r\n\
210 left join Property p on r.resource_id = p.resource_id\n\ 215 left join (\n\
211 inner join (select unnest($2::text[]) as xmlns, unnest($3::text[]) as pname) n\n\ 216 select p.* from Property p\
212 on ( p.xmlns = n.xmlns and p.pname = n.pname ) or p.property_id is null\n\ 217 inner join (select unnest($3::text[]) as xmlns, unnest($4::text[]) as pname) n\n\
218 on p.xmlns = n.xmlns and p.pname = n.pname\n\
219 ) p on r.resource_id = p.resource_id\n\
213 order by replace(ppath, '/', chr(1)), resource_id;"; 220 order by replace(ppath, '/', chr(1)), resource_id;";
214 221
215 WebdavBackend* pg_webdav_create(Session *sn, Request *rq, pblock *pb) { 222 WebdavBackend* pg_webdav_create(Session *sn, Request *rq, pblock *pb) {
216 // resourcepool is required 223 // resourcepool is required
217 char *resource_pool = pblock_findval("resourcepool", pb); 224 char *resource_pool = pblock_findval("resourcepool", pb);
250 return webdav; 257 return webdav;
251 } 258 }
252 259
253 WebdavBackend* pg_webdav_prop_create(Session *sn, Request *rq, pblock *pb) { 260 WebdavBackend* pg_webdav_prop_create(Session *sn, Request *rq, pblock *pb) {
254 return NULL; 261 return NULL;
262 }
263
264 /*
265 * adds str to the buffer
266 * some characters will be escaped: \,{}
267 */
268 static void buf_addstr_escaped(UcxBuffer *buf, const char *str) {
269 size_t len = strlen(str);
270 for(size_t i=0;i<len;i++) {
271 char c = str[i];
272 if(c == '{' || c == '}' || c == ',' || c == '\\') {
273 ucx_buffer_putc(buf, '\\');
274 }
275 ucx_buffer_putc(buf, c);
276 }
277 }
278
279 /*
280 * convert a property list to two pg array parameter strings
281 * array format: {elm1,elm2,elm3}
282 * xmlns: buffer for the xmlns array
283 * pname: buffer for the property name array
284 *
285 * returns 0 on success, 1 otherwise
286 */
287 int pg_create_property_param_arrays(WebdavPList *plist, UcxBuffer *xmlns, UcxBuffer *pname) {
288 ucx_buffer_putc(xmlns, '{');
289 ucx_buffer_putc(pname, '{');
290 while(plist) {
291 WebdavProperty *property = plist->property;
292 if(property && property->namespace && property->namespace->href && property->name) {
293 buf_addstr_escaped(xmlns, (const char*)property->namespace->href);
294 buf_addstr_escaped(pname, (const char*)property->name);
295 if(plist->next) {
296 ucx_buffer_putc(xmlns, ',');
297 ucx_buffer_putc(pname, ',');
298 }
299 }
300 plist = plist->next;
301 }
302 int r1 = ucx_buffer_write("}\0", 2, 1, xmlns) == 0;
303 int r2 = ucx_buffer_write("}\0", 2, 1, pname) == 0;
304 return r1+r2 != 0;
255 } 305 }
256 306
257 307
258 int pg_dav_propfind_init( 308 int pg_dav_propfind_init(
259 WebdavPropfindRequest *rq, 309 WebdavPropfindRequest *rq,
310 if(href_param[href_len-1] == '/') { 360 if(href_param[href_len-1] == '/') {
311 href_len--; 361 href_len--;
312 } 362 }
313 href_param[href_len] = '\0'; 363 href_param[href_len] = '\0';
314 364
315 365 // if allprop is false, create array pair for xmlns/property names
316 const char* params[2] = { resource_id_str, href_param }; 366 UcxBuffer *xmlns_buf = NULL;
367 UcxBuffer *pname_buf = NULL;
368 char *xmlns_param = NULL;
369 char *pname_param = NULL;
370 int nparam = 2;
371 if(!rq->allprop) {
372 size_t bufsize = rq->propcount < 200 ? 8 + rq->propcount * 32 : 4096;
373 xmlns_buf = ucx_buffer_new(NULL, bufsize, UCX_BUFFER_AUTOEXTEND);
374 if(!xmlns_buf) {
375 return 1;
376 }
377 pname_buf = ucx_buffer_new(NULL, bufsize, UCX_BUFFER_AUTOEXTEND);
378 if(!pname_buf) {
379 ucx_buffer_free(xmlns_buf);
380 return 1;
381 }
382 if(pg_create_property_param_arrays(rq->properties, xmlns_buf, pname_buf)) {
383 ucx_buffer_free(xmlns_buf);
384 ucx_buffer_free(pname_buf);
385 return 1;
386 }
387 xmlns_param = xmlns_buf->space;
388 pname_param = pname_buf->space;
389 nparam = 4;
390 }
391
392 const char* params[4] = { resource_id_str, href_param, xmlns_param, pname_param };
317 PGresult *result = PQexecParams( 393 PGresult *result = PQexecParams(
318 pgdav->connection, 394 pgdav->connection,
319 sql_propfind_allprop_recursive, 395 query,
320 2, // number of parameters 396 nparam, // number of parameters
321 NULL, 397 NULL,
322 params, // parameter value 398 params, // parameter value
323 NULL, 399 NULL,
324 NULL, 400 NULL,
325 0); // 0: result in text format 401 0); // 0: result in text format
326 int nrows = PQntuples(result); 402 int nrows = PQntuples(result);
327 pool_free(rq->sn->pool, href_param); 403 pool_free(rq->sn->pool, href_param);
404 if(xmlns_buf) {
405 ucx_buffer_free(xmlns_buf);
406 ucx_buffer_free(pname_buf);
407 }
328 if(nrows < 1) { 408 if(nrows < 1) {
329 PQclear(result); 409 PQclear(result);
330 return 1; 410 return 1;
331 } 411 }
332 412

mercurial