src/server/plugins/postgresql/webdav.c

branch
webdav
changeset 376
61d481d3c2e4
parent 375
32b8017f5308
child 377
c011bc2b3143
equal deleted inserted replaced
375:32b8017f5308 376:61d481d3c2e4
34 #include "../../util/pblock.h" 34 #include "../../util/pblock.h"
35 35
36 #include "../../daemon/http.h" // etag 36 #include "../../daemon/http.h" // etag
37 37
38 #include <ucx/buffer.h> 38 #include <ucx/buffer.h>
39 #include <ucx/utils.h>
39 #include <libxml/tree.h> 40 #include <libxml/tree.h>
40 41
41 42
42 static WebdavBackend pg_webdav_backend = { 43 static WebdavBackend pg_webdav_backend = {
43 pg_dav_propfind_init, 44 pg_dav_propfind_init,
275 int r2 = ucx_buffer_write("}\0", 2, 1, pname) == 0; 276 int r2 = ucx_buffer_write("}\0", 2, 1, pname) == 0;
276 return r1+r2 != 0; 277 return r1+r2 != 0;
277 } 278 }
278 279
279 280
280 static int pg_create_propfind_query(WebdavPropfindRequest *rq, WSBool iscollection, UcxBuffer *sql) { 281 static int propfind_ext_cmp(const void *f1, const void *f2) {
282 const PgPropfindExtCol *e1 = f1;
283 const PgPropfindExtCol *e2 = f2;
284
285 if(e1->ext->tableindex != e2->ext->tableindex) {
286 return e1->ext->tableindex < e2->ext->tableindex ? -1 : 1;
287 }
288
289 return 0;
290 }
291
292
293 static int pg_create_propfind_query(
294 WebdavPropfindRequest *rq,
295 WSBool iscollection,
296 PgPropfindExtCol *ext,
297 size_t numext,
298 UcxBuffer *sql)
299 {
281 PgWebdavBackend *pgdav = rq->dav->instance; 300 PgWebdavBackend *pgdav = rq->dav->instance;
301 PgRepository *repo = pgdav->repository;
282 int depth = !iscollection ? 0 : rq->depth; 302 int depth = !iscollection ? 0 : rq->depth;
283 303
284 /* 304 /*
285 * PROPFIND queries are build from components: 305 * PROPFIND queries are build from components:
286 * 306 *
312 } 332 }
313 333
314 // cols 334 // cols
315 ucx_buffer_puts(sql, sql_propfind_cols); 335 ucx_buffer_puts(sql, sql_propfind_cols);
316 336
337 // ext_cols
338 if(ext) {
339 if(rq->allprop) {
340 for(int i=0;i<repo->ntables;i++) {
341 ucx_bprintf(sql, ",x%d.*\n", i);
342 }
343 } else {
344 for(int i=0;i<numext;i++) {
345 PgPropfindExtCol e = ext[i];
346 ucx_bprintf(sql, ",x%d.%s\n", e.ext->tableindex, e.ext->column);
347 }
348 }
349 }
350
317 // from 351 // from
318 ucx_buffer_puts(sql, depth == -1 ? sql_propfind_from_cte : sql_propfind_from_table); 352 ucx_buffer_puts(sql, depth == -1 ? sql_propfind_from_cte : sql_propfind_from_table);
319 353
320 // prop join 354 // prop join
321 ucx_buffer_puts(sql, rq->allprop ? sql_propfind_propjoin_allprop : sql_propfind_propjoin_plist); 355 ucx_buffer_puts(sql, rq->allprop ? sql_propfind_propjoin_allprop : sql_propfind_propjoin_plist);
356
357 // ext_join
358 if(ext) {
359 if(rq->allprop) {
360 for(int i=0;i<repo->ntables;i++) {
361 ucx_bprintf(sql, "left join %s x%d on r.resource_id = x%d.resource_id\n", repo->tables[i].table, i, i);
362 }
363 } else {
364 int tab = -1;
365 for(int i=0;i<numext;i++) {
366 PgPropfindExtCol e = ext[i];
367 if(e.ext->tableindex != tab) {
368 tab = e.ext->tableindex;
369 ucx_bprintf(sql, "left join %s x%d on r.resource_id = x%d.resource_id\n", repo->tables[tab].table, tab, tab);
370 }
371 }
372 }
373
374 }
322 375
323 // where 376 // where
324 if(depth == 0) { 377 if(depth == 0) {
325 ucx_buffer_puts(sql, sql_propfind_where_depth0); 378 ucx_buffer_puts(sql, sql_propfind_where_depth0);
326 } else if(depth == 1) { 379 } else if(depth == 1) {
334 ucx_buffer_puts(sql, sql_propfind_order_depth_infinity); 387 ucx_buffer_puts(sql, sql_propfind_order_depth_infinity);
335 } 388 }
336 389
337 // end 390 // end
338 ucx_buffer_puts(sql, ";\0"); 391 ucx_buffer_puts(sql, ";\0");
339
340 //printf("\n\n%s\n\n", sql->space);
341 //fflush(stdout);
342 392
343 return 0; 393 return 0;
344 } 394 }
345 395
346 int pg_dav_propfind_init( 396 int pg_dav_propfind_init(
349 const char *href, 399 const char *href,
350 WebdavPList **outplist) 400 WebdavPList **outplist)
351 { 401 {
352 PgWebdavBackend *pgdav = rq->dav->instance; 402 PgWebdavBackend *pgdav = rq->dav->instance;
353 403
354 // check if the resource exists 404 // first, check if the resource exists
405 // if it doesn't exist, we can return immediately
355 int64_t parent_id; 406 int64_t parent_id;
356 int64_t resource_id; 407 int64_t resource_id;
357 const char *resourcename; 408 const char *resourcename;
358 WSBool iscollection; 409 WSBool iscollection;
359 int res_errno = 0; 410 int res_errno = 0;
375 protocol_status(rq->sn, rq->rq, PROTOCOL_NOT_FOUND, NULL); 426 protocol_status(rq->sn, rq->rq, PROTOCOL_NOT_FOUND, NULL);
376 } 427 }
377 return 1; 428 return 1;
378 } 429 }
379 430
431 // create a list of requsted extended properties
432 PgPropfindExtCol *ext;
433 size_t numext;
434 if(pgdav->repository->ntables == 0) {
435 // no property extensions configured
436 ext = NULL;
437 numext = 0;
438 } else {
439 numext = pgdav->repository->prop_ext->count;
440 ext = pool_calloc(rq->sn->pool, numext, sizeof(PgPropfindExtCol));
441
442 if(rq->allprop) {
443 // the map pgdav->repository->prop_ext contains all property extensions
444 // we can just convert the map to an array
445 UcxMapIterator i = ucx_map_iterator(pgdav->repository->prop_ext);
446 PgPropertyStoreExt *cfg_ext;
447 int j = 0;
448 UCX_MAP_FOREACH(key, cfg_ext, i) {
449 PgPropfindExtCol extcol;
450 extcol.ext = cfg_ext;
451 extcol.field_num = -1; // get the field_num after the PQexec
452 ext[j++] = extcol;
453 }
454 } else {
455 WebdavPListIterator i = webdav_plist_iterator(outplist);
456 WebdavPList *cur;
457 int j = 0;
458 while(webdav_plist_iterator_next(&i, &cur)) {
459 WSNamespace *ns = cur->property->namespace;
460 if(ns) {
461 UcxKey pkey = webdav_property_key((const char*)ns->href, cur->property->name);
462 PgPropertyStoreExt *cfg_ext = ucx_map_get(pgdav->repository->prop_ext, pkey);
463 char *pkey_data = pkey.data;
464 free((void*)pkey.data);
465 if(cfg_ext) {
466 PgPropfindExtCol extcol;
467 extcol.ext = cfg_ext;
468 extcol.field_num = -1; // get the field_num after the PQexec
469 ext[j++] = extcol;
470
471 webdav_plist_iterator_remove_current(&i);
472 }
473 }
474 }
475 numext = j;
476 }
477
478 qsort(ext, numext, sizeof(PgPropfindExtCol), propfind_ext_cmp);
479 }
480
380 // create sql query 481 // create sql query
381 const char *query = NULL; 482 const char *query = NULL;
382 UcxBuffer *sql = ucx_buffer_new(NULL, 2048, UCX_BUFFER_AUTOEXTEND); 483 UcxBuffer *sql = ucx_buffer_new(NULL, 2048, UCX_BUFFER_AUTOEXTEND);
383 if(pg_create_propfind_query(rq, iscollection, sql)) { 484 if(pg_create_propfind_query(rq, iscollection, ext, numext, sql)) {
384 return 1; 485 return 1;
385 } 486 }
386 query = sql->space; 487 query = sql->space;
387 488
388 // get all resources and properties 489 // get all resources and properties
412 pname_buf = ucx_buffer_new(NULL, bufsize, UCX_BUFFER_AUTOEXTEND); 513 pname_buf = ucx_buffer_new(NULL, bufsize, UCX_BUFFER_AUTOEXTEND);
413 if(!pname_buf) { 514 if(!pname_buf) {
414 ucx_buffer_free(xmlns_buf); 515 ucx_buffer_free(xmlns_buf);
415 return 1; 516 return 1;
416 } 517 }
417 if(pg_create_property_param_arrays(rq->properties, xmlns_buf, pname_buf)) { 518 if(pg_create_property_param_arrays(*outplist, xmlns_buf, pname_buf)) {
418 ucx_buffer_free(xmlns_buf); 519 ucx_buffer_free(xmlns_buf);
419 ucx_buffer_free(pname_buf); 520 ucx_buffer_free(pname_buf);
420 return 1; 521 return 1;
421 } 522 }
422 xmlns_param = xmlns_buf->space; 523 xmlns_param = xmlns_buf->space;
452 pg->resource_id = resource_id; 553 pg->resource_id = resource_id;
453 pg->vfsproperties = webdav_vfs_properties(outplist, TRUE, rq->allprop, 0); 554 pg->vfsproperties = webdav_vfs_properties(outplist, TRUE, rq->allprop, 0);
454 pg->result = result; 555 pg->result = result;
455 pg->nrows = nrows; 556 pg->nrows = nrows;
456 557
558 pg->ext = ext;
559 pg->numext = numext;
560 if(ext) {
561 // get field_nums for all property extensions
562 for(int i=0;i<numext;i++) {
563 PgPropfindExtCol *c = &ext[i];
564 c->field_num = PQfnumber(result, c->ext->column);
565 }
566 }
567
457 return 0; 568 return 0;
458 } 569 }
459 570
460 int pg_dav_propfind_do( 571 int pg_dav_propfind_do(
461 WebdavPropfindRequest *rq, 572 WebdavPropfindRequest *rq,
468 pool_handle_t *pool = rq->sn->pool; 579 pool_handle_t *pool = rq->sn->pool;
469 PGresult *result = pg->result; 580 PGresult *result = pg->result;
470 WebdavVFSProperties vfsprops = pg->vfsproperties; 581 WebdavVFSProperties vfsprops = pg->vfsproperties;
471 582
472 WSBool vfsprops_set = 0; // are live properties added to the response? 583 WSBool vfsprops_set = 0; // are live properties added to the response?
584 WSBool extprops_set = 0; // are extended properties added to the response?
473 int64_t current_resource_id = pg->resource_id; 585 int64_t current_resource_id = pg->resource_id;
474 for(int r=0;r<pg->nrows;r++) { 586 for(int r=0;r<pg->nrows;r++) {
475 // columns: 587 // columns:
476 // 0: path 588 // 0: path
477 // 1: resource_id 589 // 1: resource_id
567 } 679 }
568 } 680 }
569 } 681 }
570 682
571 vfsprops_set = TRUE; 683 vfsprops_set = TRUE;
684 }
685
686 if(!extprops_set) {
687 // extended properties
688 if(pg->ext) {
689 for(int extc=0;extc<pg->numext;extc++) {
690 PgPropfindExtCol ext = pg->ext[extc];
691 int fieldnum = ext.field_num;
692
693 if(!PQgetisnull(result, r, fieldnum)) {
694 char *ext_value = PQgetvalue(result, r, fieldnum);
695 int ext_value_len = PQgetlength(result, r, fieldnum);
696 char ext_xmlns_prefix[32];
697 snprintf(ext_xmlns_prefix, 32, "x%d", ext.ext->tableindex);
698
699 WebdavProperty *property = pool_malloc(pool, sizeof(WebdavProperty));
700 property->lang = NULL;
701 property->name = pool_strdup(pool, ext.ext->name);
702
703 xmlNs *namespace = pool_malloc(pool, sizeof(xmlNs));
704 memset(namespace, 0, sizeof(struct _xmlNs));
705 namespace->href = (xmlChar*)pool_strdup(pool, ext.ext->ns);
706 namespace->prefix = (xmlChar*)pool_strdup(pool, ext_xmlns_prefix);
707 property->namespace = namespace;
708
709 char *content = pool_malloc(pool, ext_value_len+1);
710 memcpy(content, ext_value, ext_value_len);
711 content[ext_value_len] = '\0';
712
713 WebdavNSList *nslist = pool_malloc(pool, sizeof(WebdavNSList));
714 nslist->namespace = namespace;
715 nslist->prev = NULL;
716 nslist->next = NULL;
717
718 property->vtype = WS_VALUE_XML_DATA;
719 property->value.data.data = content;
720 property->value.data.length = ext_value_len;
721 property->value.data.namespaces = nslist;
722
723 resource->addproperty(resource, property, 200);
724 }
725 }
726 }
727
728 extprops_set = TRUE;
572 } 729 }
573 730
574 // dead properties 731 // dead properties
575 if(!PQgetisnull(result, r, 9)) { 732 if(!PQgetisnull(result, r, 9)) {
576 char *prefix = PQgetvalue(result, r, 9); 733 char *prefix = PQgetvalue(result, r, 9);
607 if(nsdef_isnull) { 764 if(nsdef_isnull) {
608 property->vtype = WS_VALUE_TEXT; 765 property->vtype = WS_VALUE_TEXT;
609 property->value.text.str = content; 766 property->value.text.str = content;
610 property->value.text.length = pvalue_len; 767 property->value.text.length = pvalue_len;
611 } else { 768 } else {
612 WebdavNSList *nslist = wsxml_string2nslist(pool, nsdef); 769 WebdavNSList *nslist = wsxml_string2nslist(pool, nsdef);
613 property->vtype = WS_VALUE_XML_DATA; 770 property->vtype = WS_VALUE_XML_DATA;
614 property->value.data->data = content; 771 property->value.data.data = content;
615 property->value.data->length = pvalue_len; 772 property->value.data.length = pvalue_len;
616 property->value.data->namespaces = nslist; 773 property->value.data.namespaces = nslist;
617 774
618 } 775 }
619 } 776 }
620 777
621 resource->addproperty(resource, property, 200); 778 resource->addproperty(resource, property, 200);

mercurial