src/server/webdav/multistatus.c

changeset 415
d938228c382e
parent 403
0f678595d497
child 484
c036a8b242a8
equal deleted inserted replaced
414:99a34860c105 415:d938228c382e
31 31
32 #include "../daemon/session.h" 32 #include "../daemon/session.h"
33 #include "../daemon/protocol.h" 33 #include "../daemon/protocol.h"
34 #include "../util/platform.h" 34 #include "../util/platform.h"
35 35
36 #include <ucx/string.h> 36 #include <cx/string.h>
37 #include <cx/hash_map.h>
37 38
38 #include "multistatus.h" 39 #include "multistatus.h"
39 40
40 #include "operation.h" 41 #include "operation.h"
41 #include "xml.h" 42 #include "xml.h"
49 } 50 }
50 ZERO(ms, sizeof(Multistatus)); 51 ZERO(ms, sizeof(Multistatus));
51 ms->response.addresource = multistatus_addresource; 52 ms->response.addresource = multistatus_addresource;
52 ms->sn = sn; 53 ms->sn = sn;
53 ms->rq = rq; 54 ms->rq = rq;
54 ms->namespaces = ucx_map_new_a(session_get_allocator(ms->sn), 8); 55 ms->namespaces = cxHashMapCreate(pool_allocator(sn->pool), 8);
55 ms->proppatch = FALSE; 56 ms->proppatch = FALSE;
56 if(!ms->namespaces) { 57 if(!ms->namespaces) {
57 return NULL; 58 return NULL;
58 } 59 }
59 if(ucx_map_cstr_put(ms->namespaces, "D", webdav_dav_namespace())) { 60 if(cxMapPut(ms->namespaces, cx_hash_key_str("D"), webdav_dav_namespace())) {
60 return NULL; 61 return NULL;
61 } 62 }
62 return ms; 63 return ms;
63 } 64 }
64 65
65 static int send_xml_root(Multistatus *ms, Writer *out) { 66 static int send_xml_root(Multistatus *ms, Writer *out) {
66 writer_puts(out, S("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" 67 writer_put_lit(out, "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
67 "<D:multistatus")); 68 "<D:multistatus");
68 69
69 // write the namespaces definitions 70 // write the namespaces definitions
70 // key is the namespace prefix 71 // key is the namespace prefix
71 // the map always contains the "DAV:" namespace with the prefix "D" 72 // the map always contains the "DAV:" namespace with the prefix "D"
72 UcxMapIterator i = ucx_map_iterator(ms->namespaces); 73 CxIterator i = cxMapIterator(ms->namespaces);
73 WSNamespace *ns; 74 cx_foreach(CxMapEntry*, entry, i) {
74 UCX_MAP_FOREACH(key, ns, i) { 75 WSNamespace *ns = entry->value;
75 writer_puts(out, S(" xmlns:")); 76 writer_put_lit(out, " xmlns:");
76 writer_put(out, key.data, key.len); 77 writer_put (out, entry->key->data.str, entry->key->len);
77 writer_puts(out, S("=\"")); 78 writer_put_lit(out, "=\"");
78 writer_puts(out, sstr((char*)ns->href)); 79 writer_put_str(out, (char*)ns->href);
79 writer_puts(out, S("\"")); 80 writer_put_lit(out, "\"");
80 } 81 }
81 82
82 writer_puts(out, S(">\n")); 83 writer_put_lit(out, ">\n");
83 84
84 return out->error; 85 return out->error;
85 } 86 }
86 87
87 static void send_nsdef(WSNamespace *ns, Writer *out) { 88 static void send_nsdef(WSNamespace *ns, Writer *out) {
88 writer_puts(out, S(" xmlns:")); 89 writer_put_lit(out, " xmlns:");
89 writer_puts(out, sstr((char*)ns->prefix)); 90 writer_put_str(out, (char*)ns->prefix);
90 writer_puts(out, S("=\"")); 91 writer_put_lit(out, "=\"");
91 writer_puts(out, sstr((char*)ns->href)); 92 writer_put_str(out, (char*)ns->href);
92 writer_putc(out, '\"'); 93 writer_putc (out, '\"');
93 } 94 }
94 95
95 static void send_string_escaped(Writer *out, sstr_t str) { 96 static void send_string_escaped(Writer *out, cxmutstr str) {
96 char *begin = str.ptr; 97 char *begin = str.ptr;
97 char *end = begin; 98 char *end = begin;
98 char *escape = NULL; 99 char *escape = NULL;
99 int esclen; 100 int esclen;
100 for(size_t i=0;i<str.length;i++) { 101 for(size_t i=0;i<str.length;i++) {
148 WebdavNSList *nsdef, 149 WebdavNSList *nsdef,
149 WSBool writeContent, 150 WSBool writeContent,
150 Writer *out) 151 Writer *out)
151 { 152 {
152 // write: "<prefix:name" 153 // write: "<prefix:name"
153 writer_putc(out, '<'); 154 writer_putc (out, '<');
154 writer_puts(out, sstr((char*)property->namespace->prefix)); 155 writer_put_str(out, (char*)property->namespace->prefix);
155 writer_putc(out, ':'); 156 writer_putc (out, ':');
156 writer_puts(out, sstr((char*)property->name)); 157 writer_put_str(out, (char*)property->name);
157 158
158 // send additional namespace definitions required for the value 159 // send additional namespace definitions required for the value
159 WebdavNSList *def = nsdef; 160 WebdavNSList *def = nsdef;
160 while(def) { 161 while(def) {
161 send_nsdef(def->namespace, out); 162 send_nsdef(def->namespace, out);
162 def = def->next; 163 def = def->next;
163 } 164 }
164 165
165 // send xml lang attribute 166 // send xml lang attribute
166 if(property->lang) { 167 if(property->lang) {
167 writer_puts(out, S(" xml:lang=\"")); 168 writer_put_lit(out, " xml:lang=\"");
168 writer_puts(out, sstr((char*)property->lang)); 169 writer_put_str(out, (char*)property->lang);
169 writer_putc(out, '\"'); 170 writer_putc (out, '\"');
170 } 171 }
171 172
172 // end property tag and write content 173 // end property tag and write content
173 if(writeContent) { 174 if(writeContent) {
174 writer_putc(out, '>'); 175 writer_putc(out, '>');
200 break; 201 break;
201 } 202 }
202 } 203 }
203 204
204 // end tag 205 // end tag
205 writer_puts(out, S("</")); 206 writer_put_lit(out, "</");
206 writer_puts(out, sstr((char*)property->namespace->prefix)); 207 writer_put_str(out, (char*)property->namespace->prefix);
207 writer_putc(out, ':'); 208 writer_putc (out, ':');
208 writer_puts(out, sstr((char*)property->name)); 209 writer_put_str(out, (char*)property->name);
209 writer_putc(out, '>'); 210 writer_putc (out, '>');
210 } else { 211 } else {
211 writer_puts(out, S("/>")); 212 writer_put_lit(out, "/>");
212 } 213 }
213 214
214 return out->error; 215 return out->error;
215 } 216 }
216 217
217 static int send_response_tag(Multistatus *ms, MSResponse *rp, Writer *out) { 218 static int send_response_tag(Multistatus *ms, MSResponse *rp, Writer *out) {
218 writer_puts(out, S(" <D:response>\n" 219 writer_put_lit(out, " <D:response>\n"
219 " <D:href>")); 220 " <D:href>");
220 //writer_puts(out, sstr(rp->resource.href)); 221 send_string_escaped(out, cx_mutstr(rp->resource.href));
221 send_string_escaped(out, sstr(rp->resource.href)); 222 writer_put_lit(out, "</D:href>\n");
222 writer_puts(out, S("</D:href>\n"));
223 223
224 WSBool writeContent = ms->proppatch ? FALSE : TRUE; 224 WSBool writeContent = ms->proppatch ? FALSE : TRUE;
225 225
226 if(rp->plist_begin) { 226 if(rp->plist_begin) {
227 writer_puts(out, S(" <D:propstat>\n" 227 writer_put_lit(out, " <D:propstat>\n"
228 " <D:prop>\n")); 228 " <D:prop>\n");
229 // send properties 229 // send properties
230 PropertyOkList *p = rp->plist_begin; 230 PropertyOkList *p = rp->plist_begin;
231 while(p) { 231 while(p) {
232 writer_puts(out, S(" ")); 232 writer_put_lit(out, " ");
233 if(send_property(ms, p->property, p->nsdef, writeContent, out)) { 233 if(send_property(ms, p->property, p->nsdef, writeContent, out)) {
234 return out->error; 234 return out->error;
235 } 235 }
236 writer_puts(out, S("\n")); 236 writer_put_lit(out, "\n");
237 p = p->next; 237 p = p->next;
238 } 238 }
239 239
240 writer_puts(out, S(" </D:prop>\n" 240 writer_put_lit(out, " </D:prop>\n"
241 " <D:status>HTTP/1.1 200 OK</D:status>\n" 241 " <D:status>HTTP/1.1 200 OK</D:status>\n"
242 " </D:propstat>\n")); 242 " </D:propstat>\n");
243 } 243 }
244 244
245 // send error properties 245 // send error properties
246 PropertyErrorList *error = rp->errors; 246 PropertyErrorList *error = rp->errors;
247 while(error) { 247 while(error) {
248 writer_puts(out, S(" <D:propstat>\n" 248 writer_put_lit(out, " <D:propstat>\n"
249 " <D:prop>\n")); 249 " <D:prop>\n");
250 250
251 WebdavPList *errprop = error->begin; 251 WebdavPList *errprop = error->begin;
252 while(errprop) { 252 while(errprop) {
253 writer_puts(out, S(" ")); 253 writer_put_lit(out, " ");
254 if(send_property(ms, errprop->property, NULL, FALSE, out)) { 254 if(send_property(ms, errprop->property, NULL, FALSE, out)) {
255 return out->error; 255 return out->error;
256 } 256 }
257 writer_putc(out, '\n'); 257 writer_putc(out, '\n');
258 errprop = errprop->next; 258 errprop = errprop->next;
265 statuscode[1] = '0'; 265 statuscode[1] = '0';
266 statuscode[2] = '0'; 266 statuscode[2] = '0';
267 statuscode[3] = ' '; 267 statuscode[3] = ' ';
268 sclen = 4; 268 sclen = 4;
269 } 269 }
270 writer_puts(out, S(" </D:prop>\n" 270 writer_put_lit(out, " </D:prop>\n"
271 " <D:status>HTTP/1.1 ")); 271 " <D:status>HTTP/1.1 ");
272 writer_put(out, statuscode, sclen); 272 writer_put(out, statuscode, sclen);
273 const char *status_msg = protocol_status_message(error->status); 273 const char *status_msg = protocol_status_message(error->status);
274 if(status_msg) { 274 if(status_msg) {
275 writer_put(out, status_msg, strlen(status_msg)); 275 writer_put(out, status_msg, strlen(status_msg));
276 } else { 276 } else {
277 writer_puts(out, S("Server Error")); 277 writer_put_lit(out, "Server Error");
278 } 278 }
279 writer_puts(out, S("</D:status>\n" 279 writer_put_lit(out, "</D:status>\n"
280 " </D:propstat>\n")); 280 " </D:propstat>\n");
281 281
282 282
283 error = error->next; 283 error = error->next;
284 } 284 }
285 285
286 // end response tag 286 // end response tag
287 writer_puts(out, S(" </D:response>\n")); 287 writer_put_lit(out, " </D:response>\n");
288 288
289 return out->error; 289 return out->error;
290 } 290 }
291 291
292 int multistatus_send(Multistatus *ms, SYS_NETFD net) { 292 int multistatus_send(Multistatus *ms, SYS_NETFD net) {
320 } 320 }
321 response = response->next; 321 response = response->next;
322 } 322 }
323 323
324 // end multistatus 324 // end multistatus
325 writer_puts(out, S("</D:multistatus>\n")); 325 writer_put_lit(out, "</D:multistatus>\n");
326 326
327 //printf("\n\n"); 327 //printf("\n\n");
328 //fflush(stdout); 328 //fflush(stdout);
329 329
330 writer_flush(out); 330 writer_flush(out);
353 353
354 // add resource funcs 354 // add resource funcs
355 res->resource.addproperty = msresponse_addproperty; 355 res->resource.addproperty = msresponse_addproperty;
356 res->resource.close = msresponse_close; 356 res->resource.close = msresponse_close;
357 357
358 res->properties = ucx_map_new_a(session_get_allocator(ms->sn), 32); 358 res->properties = cxHashMapCreate(pool_allocator(ms->sn->pool), 32);
359 if(!res->properties) { 359 if(!res->properties) {
360 return NULL; 360 return NULL;
361 } 361 }
362 362
363 res->multistatus = ms; 363 res->multistatus = ms;
412 MSResponse *response, 412 MSResponse *response,
413 WebdavProperty *property, 413 WebdavProperty *property,
414 int statuscode) 414 int statuscode)
415 { 415 {
416 pool_handle_t *pool = response->multistatus->sn->pool; 416 pool_handle_t *pool = response->multistatus->sn->pool;
417 UcxAllocator *a = session_get_allocator(response->multistatus->sn);
418 417
419 response->resource.err++; 418 response->resource.err++;
420 419
421 // MSResponse contains a list of properties for each status code 420 // MSResponse contains a list of properties for each status code
422 // at first find the list for this status code 421 // at first find the list for this status code
455 // we have the list -> add the new element 454 // we have the list -> add the new element
456 if(webdav_plist_add(pool, &errlist->begin, &errlist->end, property)) { 455 if(webdav_plist_add(pool, &errlist->begin, &errlist->end, property)) {
457 return 1; 456 return 1;
458 } 457 }
459 return 0; 458 return 0;
459 }
460
461 static CxHashKey ms_property_key(
462 CxAllocator *a,
463 const xmlChar *href,
464 const char *property_name)
465 {
466 cxmutstr key_data = cx_strcat_a(a, 3, cx_str((const char*)href), (cxstring){ "\0", 1 }, cx_str(property_name));
467 return cx_hash_key_bytes((unsigned char*)key_data.ptr, key_data.length);
460 } 468 }
461 469
462 int msresponse_addproperty( 470 int msresponse_addproperty(
463 WebdavResource *res, 471 WebdavResource *res,
464 WebdavProperty *property, 472 WebdavProperty *property,
484 property->name); 492 property->name);
485 return 1; 493 return 1;
486 } 494 }
487 495
488 // check if the property was already added to the resource 496 // check if the property was already added to the resource
489 UcxAllocator *a = session_get_allocator(sn); 497 CxAllocator *a = pool_allocator(sn->pool);
490 sstr_t key = sstrcat_a( 498 CxHashKey key = ms_property_key(a, property->namespace->href, property->name);
491 a, 499 if(cxMapGet(response->properties, key)) {
492 3, 500 cxFree(a, key.data.bytes);
493 sstr((char*)property->namespace->href),
494 S("\0"),
495 sstr((char*)property->name));
496 if(ucx_map_sstr_get(response->properties, key)) {
497 a->free(a->pool, key.ptr);
498 return 0; 501 return 0;
499 } 502 }
500 if(ucx_map_sstr_put(response->properties, key, property)) { 503 if(cxMapPut(response->properties, key, property)) {
501 return 1; // OOM 504 return 1; // OOM
502 } 505 }
503 a->free(a->pool, key.ptr); 506 cxFree(a, key.data.bytes);
504 507
505 // list of namespace definitions for this property 508 // list of namespace definitions for this property
506 WebdavNSList *nsdef_begin = NULL; 509 WebdavNSList *nsdef_begin = NULL;
507 WebdavNSList *nsdef_end = NULL; 510 WebdavNSList *nsdef_end = NULL;
508 511
509 // add namespace of this property to the namespace map 512 // add namespace of this property to the namespace map
510 // the namespace map will be used for global namespace definitions 513 // the namespace map will be used for global namespace definitions
511 if(property->namespace->prefix) { 514 if(property->namespace->prefix) {
512 WSNamespace *ns = ucx_map_cstr_get( 515 WSNamespace *ns = cxMapGet(
513 response->multistatus->namespaces, 516 response->multistatus->namespaces,
514 (const char*)property->namespace->prefix); 517 cx_hash_key_str((const char*)property->namespace->prefix));
515 if(!ns) { 518 if(!ns) {
516 // prefix is not in use -> we can add the namespace to the ns map 519 // prefix is not in use -> we can add the namespace to the ns map
517 int err = ucx_map_cstr_put( 520 int err = cxMapPut(
518 response->multistatus->namespaces, 521 response->multistatus->namespaces,
519 (const char*)property->namespace->prefix, 522 cx_hash_key_str((const char*)property->namespace->prefix),
520 property->namespace); 523 property->namespace);
521 if(err) { 524 if(err) {
522 return 1; // OOM 525 return 1; // OOM
523 } 526 }
524 } else if( 527 } else if(
620 if(op->response_close(op, res)) { 623 if(op->response_close(op, res)) {
621 ret = REQ_ABORTED; 624 ret = REQ_ABORTED;
622 } 625 }
623 626
624 // add missing properties with status code 404 627 // add missing properties with status code 404
625 UcxAllocator *a = session_get_allocator(ms->sn); 628 CxAllocator *a = pool_allocator(ms->sn->pool);
626 WebdavPList *pl = ms->response.op->reqprops; 629 WebdavPList *pl = ms->response.op->reqprops;
627 while(pl) { 630 while(pl) {
628 sstr_t key = sstrcat_a( 631 CxHashKey key = ms_property_key(a, pl->property->namespace->href, pl->property->name);
629 a, 632 if(!cxMapGet(response->properties, key)) {
630 3,
631 sstr((char*)pl->property->namespace->href),
632 S("\0"),
633 sstr((char*)pl->property->name));
634 if(!ucx_map_sstr_get(response->properties, key)) {
635 // property was not added to this response 633 // property was not added to this response
636 if(ms->proppatch) { 634 if(ms->proppatch) {
637 if(msresponse_addproperty(res, pl->property, 424)) { 635 if(msresponse_addproperty(res, pl->property, 424)) {
638 ret = REQ_ABORTED; 636 ret = REQ_ABORTED;
639 break; 637 break;
666 response->plist_begin = NULL; 664 response->plist_begin = NULL;
667 response->plist_end = NULL; 665 response->plist_end = NULL;
668 } 666 }
669 667
670 // we don't need the properties anymore 668 // we don't need the properties anymore
671 ucx_map_free(response->properties); 669 cxMapDestroy(response->properties);
672 670
673 response->resource.isclosed = TRUE; 671 response->resource.isclosed = TRUE;
674 return ret; 672 return ret;
675 } 673 }

mercurial