39 |
39 |
40 #include "../daemon/vfs.h" |
40 #include "../daemon/vfs.h" |
41 #include "../daemon/protocol.h" |
41 #include "../daemon/protocol.h" |
42 |
42 |
43 #include "davparser.h" |
43 #include "davparser.h" |
|
44 #include "persistence.h" |
|
45 |
|
46 static UcxMap *pmgr_map; // char*, PersistenceManager |
|
47 |
|
48 int webdav_init(pblock *pb, Session *sn, Request *rq) { |
|
49 pmgr_map = ucx_map_new(8); |
|
50 PersistenceManager *defaultmgr = create_property_backend(); |
|
51 ucx_map_cstr_put(pmgr_map, "default", defaultmgr); |
|
52 return REQ_PROCEED; |
|
53 } |
|
54 |
|
55 void webdav_add_persistence_manager(char *name, PersistenceManager *mgr) { |
|
56 if(!pmgr_map) { |
|
57 webdav_init(NULL, NULL, NULL); |
|
58 } |
|
59 ucx_map_cstr_put(pmgr_map, name, mgr); |
|
60 } |
|
61 |
|
62 int webdav_setcollection(pblock *pb, Session *sn, Request *rq) { |
|
63 //char *name = pblock_findkeyval(pb_key_name, pb); |
|
64 char *db = pblock_findval("db", pb); |
|
65 |
|
66 if(!db) { |
|
67 db = "default"; |
|
68 } |
|
69 |
|
70 // setup DavCollection |
|
71 DavCollection *dav = pool_malloc(sn->pool, sizeof(DavCollection)); |
|
72 dav->mgr = ucx_map_cstr_get(pmgr_map, db); |
|
73 rq->davCollection = dav; |
|
74 |
|
75 return REQ_NOACTION; |
|
76 } |
44 |
77 |
45 int webdav_service(pblock *pb, Session *sn, Request *rq) { |
78 int webdav_service(pblock *pb, Session *sn, Request *rq) { |
46 char *method = pblock_findkeyval(pb_key_method, rq->reqpb); |
79 char *method = pblock_findkeyval(pb_key_method, rq->reqpb); |
47 if(method == NULL) { |
80 if(method == NULL) { |
48 return REQ_ABORTED; |
81 return REQ_ABORTED; |
215 } |
248 } |
216 |
249 |
217 /* |
250 /* |
218 * get requested properties and initialize some stuff |
251 * get requested properties and initialize some stuff |
219 */ |
252 */ |
|
253 DavCollection *collection = rq->davCollection; |
|
254 |
220 PropfindRequest *davrq = dav_parse_propfind(sn, rq, xml_body, xml_len); |
255 PropfindRequest *davrq = dav_parse_propfind(sn, rq, xml_body, xml_len); |
221 davrq->sn = sn; |
256 davrq->sn = sn; |
222 davrq->rq = rq; |
257 davrq->rq = rq; |
223 davrq->out = sbuf_new(512); |
258 davrq->out = sbuf_new(512); |
224 davrq->propertyBackend = create_property_backend(); |
259 davrq->persistencemgr = collection->mgr; |
225 |
|
226 /* write xml response header */ |
|
227 sbuf_puts(davrq->out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); |
|
228 sbuf_puts(davrq->out, "<D:multistatus xmlns:D=\"DAV:\">\n"); |
|
229 |
260 |
230 /* begin multistatus response */ |
261 /* begin multistatus response */ |
231 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb); |
262 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb); |
232 char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars); |
263 char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars); |
|
264 davrq->uri = uri; |
|
265 davrq->path = ppath; |
233 |
266 |
234 VFSContext *vfs = vfs_request_context(sn, rq); |
267 VFSContext *vfs = vfs_request_context(sn, rq); |
235 |
268 |
236 struct stat st; |
269 struct stat st; |
237 if(vfs_stat(vfs, ppath, &st) != 0) { |
270 if(vfs_stat(vfs, ppath, &st) != 0) { |
238 return REQ_ABORTED; |
271 return REQ_ABORTED; |
239 } |
272 } |
|
273 |
|
274 // begin propfind |
|
275 davrq->isdir = S_ISDIR(st.st_mode); |
|
276 davrq->persistencemgr->propfind_begin(davrq->persistencemgr, davrq); |
240 |
277 |
241 /* |
278 /* |
242 * if the requested webdav resource(file) is a directory, we create |
279 * if the requested webdav resource(file) is a directory, we create |
243 * a response for every child |
280 * a response for every child |
244 */ |
281 */ |
255 // child response |
292 // child response |
256 dav_resource_response(davrq, newpath, newuri); |
293 dav_resource_response(davrq, newpath, newuri); |
257 } |
294 } |
258 } |
295 } |
259 |
296 |
260 /* create the response for the requested resource */ |
297 // create the response for the requested resource |
261 dav_resource_response(davrq, sstr(ppath), sstr(uri)); |
298 dav_resource_response(davrq, sstr(ppath), sstr(uri)); |
262 |
299 |
263 /* end xml */ |
300 // end propfind |
|
301 davrq->persistencemgr->propfind_begin(davrq->persistencemgr, davrq); |
|
302 |
|
303 // end xml |
264 sbuf_puts(davrq->out, "</D:multistatus>\n"); |
304 sbuf_puts(davrq->out, "</D:multistatus>\n"); |
265 |
305 |
266 /* send the xml response to the client */ |
306 //printf("%s\n", davrq->out->ptr); |
|
307 |
|
308 // write xml response header |
|
309 sbuf_t *out = sbuf_new(256); |
|
310 sbuf_puts(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); |
|
311 sbuf_puts(out, "<D:multistatus"); |
|
312 UcxMapIterator nsiter = ucx_map_iterator(davrq->nsmap->map); |
|
313 XmlNs *ns; |
|
314 UCX_MAP_FOREACH(ns, nsiter) { |
|
315 sbuf_puts(out, " xmlns:"); |
|
316 sbuf_puts(out, ns->prefix); |
|
317 sbuf_puts(out, "=\""); |
|
318 sbuf_puts(out, ns->xmlns); |
|
319 sbuf_puts(out, "\""); |
|
320 } |
|
321 sbuf_puts(out, ">\n"); |
|
322 |
|
323 // send the xml response to the client |
267 protocol_status(sn, rq, 207, "Multi Status"); |
324 protocol_status(sn, rq, 207, "Multi Status"); |
268 pblock_removekey(pb_key_content_type, rq->srvhdrs); |
325 pblock_removekey(pb_key_content_type, rq->srvhdrs); |
269 pblock_nvinsert("content-type", "text/xml", rq->srvhdrs); |
326 pblock_nvinsert("content-type", "text/xml", rq->srvhdrs); |
270 pblock_nninsert("content-length", davrq->out->length, rq->srvhdrs); |
327 pblock_nninsert( |
271 |
328 "content-length", |
272 //pblock_nvinsert("connection", "close", rq->srvhdrs); |
329 out->length + davrq->out->length, |
|
330 rq->srvhdrs); |
|
331 |
273 http_start_response(sn, rq); |
332 http_start_response(sn, rq); |
274 |
333 |
275 //printf("%s\n", davrq->out->ptr); |
334 // write content |
276 ssize_t nr = net_write(sn->csd, davrq->out->ptr, davrq->out->length); |
335 size_t nr; |
277 //printf("net_write returned: %d\n", r); |
336 nr = net_write(sn->csd, out->ptr, out->length); |
278 |
337 nr = net_write(sn->csd, davrq->out->ptr, davrq->out->length); |
279 |
338 |
|
339 sbuf_free(out); |
280 dav_free_propfind(davrq); |
340 dav_free_propfind(davrq); |
281 |
341 |
282 return REQ_PROCEED; |
342 return REQ_PROCEED; |
283 } |
343 } |
284 |
344 |
290 if(uri == NULL) { |
350 if(uri == NULL) { |
291 /* TODO: error */ |
351 /* TODO: error */ |
292 return REQ_ABORTED; |
352 return REQ_ABORTED; |
293 } |
353 } |
294 |
354 |
295 /* Get request body which contains the webdav XML request */ |
355 // Get request body which contains the webdav XML request |
296 char *xml_body; |
356 char *xml_body; |
297 size_t xml_len = 0; |
357 size_t xml_len = 0; |
298 |
358 |
299 char *ctlen = pblock_findkeyval(pb_key_content_length, rq->headers); |
359 char *ctlen = pblock_findkeyval(pb_key_content_length, rq->headers); |
300 if(ctlen) { |
360 if(ctlen) { |
301 xml_len = atoi(ctlen); |
361 xml_len = atoi(ctlen); |
302 } else { |
362 } else { |
303 /* invalid request */ |
363 // invalid request |
304 printf("invalid request\n"); |
364 printf("invalid request\n"); |
305 return REQ_ABORTED; |
365 return REQ_ABORTED; |
306 } |
366 } |
307 |
367 |
308 xml_body = pool_malloc(sn->pool, xml_len + 1); |
368 xml_body = pool_malloc(sn->pool, xml_len + 1); |
309 if(xml_body == NULL) { |
369 if(xml_body == NULL) { |
310 return REQ_ABORTED; |
370 return REQ_ABORTED; |
311 } |
371 } |
312 xml_body[xml_len] = 0; |
372 xml_body[xml_len] = 0; |
313 if(!xml_body) { |
373 if(!xml_body) { |
314 /* server error */ |
374 // server error |
315 printf("server error\n"); |
375 printf("server error\n"); |
316 return REQ_ABORTED; |
376 return REQ_ABORTED; |
317 } |
377 } |
318 |
378 |
319 /* get request body */ |
379 // get request body |
320 int r = 0; |
380 int r = 0; |
321 char *xb = xml_body; |
381 char *xb = xml_body; |
322 size_t xl = xml_len; |
382 size_t xl = xml_len; |
323 while((r = netbuf_getbytes(sn->inbuf, xb, xl)) != NETBUF_EOF) { |
383 while((r = netbuf_getbytes(sn->inbuf, xb, xl)) != NETBUF_EOF) { |
324 xb += r; |
384 xb += r; |
326 } |
386 } |
327 |
387 |
328 /* |
388 /* |
329 * parse the xml request and create the proppatch object |
389 * parse the xml request and create the proppatch object |
330 */ |
390 */ |
|
391 DavCollection *collection = rq->davCollection; |
|
392 |
331 ProppatchRequest *davrq = dav_parse_proppatch(sn, rq, xml_body, xml_len); |
393 ProppatchRequest *davrq = dav_parse_proppatch(sn, rq, xml_body, xml_len); |
332 davrq->sn = sn; |
394 davrq->sn = sn; |
333 davrq->rq = rq; |
395 davrq->rq = rq; |
334 davrq->out = sbuf_new(512); |
396 davrq->out = sbuf_new(512); |
335 davrq->backend = create_property_backend(); |
397 davrq->backend = collection->mgr; |
336 davrq->propstat = propstat_create(sn->pool); |
398 davrq->propstat = propstat_create(sn->pool); |
337 |
399 |
338 /* TODO: create prefixes for every namespace */ |
|
339 XmlNs *ns = xmlnsmap_get(davrq->nsmap, "DAV:"); |
|
340 ns->prefix = "D"; |
|
341 ns->prelen = 1; |
|
342 |
400 |
343 /* |
401 /* |
344 * begin multistatus response |
402 * begin multistatus response |
345 * |
403 * |
346 * The webdav backend does the most work. The backend->proppatch function |
404 * The webdav backend does the most work. The backend->proppatch function |
348 * member of the ProppatchRequest. All we have to do here is to create |
406 * member of the ProppatchRequest. All we have to do here is to create |
349 * the xml response and send it to the client |
407 * the xml response and send it to the client |
350 */ |
408 */ |
351 |
409 |
352 /* write xml response header */ |
410 /* write xml response header */ |
353 /* TODO: add possible xml namespaces */ |
|
354 sbuf_puts(davrq->out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); |
411 sbuf_puts(davrq->out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); |
355 sbuf_puts(davrq->out, "<D:multistatus xmlns:D=\"DAV:\">\n"); |
412 //sbuf_puts(davrq->out, "<D:multistatus xmlns:D=\"DAV:\">\n"); |
|
413 sbuf_puts(davrq->out, "<D:multistatus"); |
|
414 UcxMapIterator nsiter = ucx_map_iterator(davrq->nsmap->map); |
|
415 XmlNs *ns; |
|
416 UCX_MAP_FOREACH(ns, nsiter) { |
|
417 sbuf_puts(davrq->out, " xmlns:"); |
|
418 sbuf_puts(davrq->out, ns->prefix); |
|
419 sbuf_puts(davrq->out, "=\""); |
|
420 sbuf_puts(davrq->out, ns->xmlns); |
|
421 sbuf_puts(davrq->out, "\""); |
|
422 } |
|
423 sbuf_puts(davrq->out, ">\n"); |
356 |
424 |
357 sbuf_puts(davrq->out, "<D:response>\n<D:href>"); |
425 sbuf_puts(davrq->out, "<D:response>\n<D:href>"); |
358 sbuf_puts(davrq->out, uri); |
426 sbuf_puts(davrq->out, uri); |
359 sbuf_puts(davrq->out, "</D:href>\n"); |
427 sbuf_puts(davrq->out, "</D:href>\n"); |
360 |
428 |
389 sbuf_puts(davrq->out, "<D:response>\n"); |
457 sbuf_puts(davrq->out, "<D:response>\n"); |
390 sbuf_puts(davrq->out, "<D:href>"); |
458 sbuf_puts(davrq->out, "<D:href>"); |
391 sbuf_append(davrq->out, uri); |
459 sbuf_append(davrq->out, uri); |
392 sbuf_puts(davrq->out, "</D:href>\n"); |
460 sbuf_puts(davrq->out, "</D:href>\n"); |
393 |
461 |
394 davrq->propertyBackend->propfind(davrq->propertyBackend, davrq, path.ptr); |
462 if(davrq->persistencemgr->vfs_props) { |
|
463 // get some DAV properties from the file system |
|
464 dav_rq_propfind(davrq->persistencemgr, davrq, path.ptr); |
|
465 } |
|
466 davrq->persistencemgr->propfind(davrq->persistencemgr, davrq, path.ptr); |
395 |
467 |
396 if(davrq->prop) { |
468 if(davrq->prop) { |
397 /* |
469 /* |
398 * there are some properties written, so we close the |
470 * there are some properties written, so we close the |
399 * prop and propstat tag |
471 * prop and propstat tag |
405 |
477 |
406 if(davrq->notFoundProps != NULL) { |
478 if(davrq->notFoundProps != NULL) { |
407 sbuf_puts(davrq->out, "<D:propstat>\n<D:prop>\n"); |
479 sbuf_puts(davrq->out, "<D:propstat>\n<D:prop>\n"); |
408 DAV_FOREACH(elm, davrq->notFoundProps) { |
480 DAV_FOREACH(elm, davrq->notFoundProps) { |
409 DavProperty *prop = (DavProperty*)elm->data; |
481 DavProperty *prop = (DavProperty*)elm->data; |
410 sbuf_puts(davrq->out, "<D:"); |
482 sbuf_put(davrq->out, '<'); |
|
483 sbuf_puts(davrq->out, prop->xmlns->prefix); |
|
484 sbuf_put(davrq->out, ':'); |
|
485 |
411 sbuf_puts(davrq->out, prop->name); |
486 sbuf_puts(davrq->out, prop->name); |
412 sbuf_puts(davrq->out, " />\n"); |
487 sbuf_puts(davrq->out, " />\n"); |
413 } |
488 } |
414 sbuf_puts(davrq->out, "</D:prop>\n"); |
489 sbuf_puts(davrq->out, "</D:prop>\n"); |
415 sbuf_puts(davrq->out, "<D:status>HTTP/1.1 404 Not Found</D:status>\n"); |
490 sbuf_puts(davrq->out, "<D:status>HTTP/1.1 404 Not Found</D:status>\n"); |
434 if(!davrq->prop) { |
509 if(!davrq->prop) { |
435 sbuf_puts(davrq->out, "<D:propstat>\n<D:prop>\n"); |
510 sbuf_puts(davrq->out, "<D:propstat>\n<D:prop>\n"); |
436 davrq->prop = 1; |
511 davrq->prop = 1; |
437 } |
512 } |
438 |
513 |
439 sbuf_puts(davrq->out, "<D:"); |
514 sbuf_put(davrq->out, '<'); |
|
515 sbuf_puts(davrq->out, prop->xmlns->prefix); |
|
516 sbuf_put(davrq->out, ':'); |
440 sbuf_puts(davrq->out, prop->name); |
517 sbuf_puts(davrq->out, prop->name); |
441 sbuf_puts(davrq->out, ">"); |
518 sbuf_put(davrq->out, '>'); |
442 |
519 |
443 sbuf_append(davrq->out, sstrn(str, len)); |
520 sbuf_append(davrq->out, sstrn(str, len)); |
444 |
521 |
445 sbuf_puts(davrq->out, "</D:"); |
522 sbuf_puts(davrq->out, "</"); |
|
523 sbuf_puts(davrq->out, prop->xmlns->prefix); |
|
524 sbuf_put(davrq->out, ':'); |
446 sbuf_puts(davrq->out, prop->name); |
525 sbuf_puts(davrq->out, prop->name); |
447 sbuf_puts(davrq->out, ">\n"); |
526 sbuf_puts(davrq->out, ">\n"); |
448 } |
527 } |
449 |
528 |
450 void dav_propfind_add_prop_error( |
529 void dav_propfind_add_prop_error( |
458 |
537 |
459 |
538 |
460 |
539 |
461 |
540 |
462 /* WebDAV Default Backend */ |
541 /* WebDAV Default Backend */ |
463 static DAVPropertyBackend dav_file_backend = { |
542 static PersistenceManager dav_file_backend = { |
|
543 NULL, |
|
544 NULL, |
464 dav_rq_propfind, |
545 dav_rq_propfind, |
465 dav_rq_proppatch |
546 dav_rq_proppatch, |
|
547 0 |
466 }; |
548 }; |
467 |
549 |
468 DAVPropertyBackend* create_property_backend() { |
550 PersistenceManager* create_property_backend() { |
469 return &dav_file_backend; |
551 return &dav_file_backend; |
470 } |
552 } |
471 |
553 |
472 void dav_rq_propfind(DAVPropertyBackend *b, PropfindRequest *rq ,char *path) { |
554 void dav_rq_propfind(PersistenceManager *b, PropfindRequest *rq ,char *path) { |
473 struct stat st; |
555 struct stat st; |
474 if(stat(path, &st) != 0) { |
556 if(stat(path, &st) != 0) { |
475 perror("dav_be_propfind"); |
557 perror("dav_be_propfind"); |
476 fprintf(stderr, "Cannot get stat of file: %s\n", path); |
558 fprintf(stderr, "Cannot get stat of file: %s\n", path); |
477 } |
559 } |
478 |
560 |
479 if(rq->allprop) { |
561 if(rq->allprop) { |
480 DavProperty prop; |
562 DavProperty prop; |
481 prop.xmlns = "DAV:"; |
563 prop.xmlns = xmlnsmap_get(rq->nsmap, "DAV:"); |
482 |
564 |
483 prop.name = "resourcetype"; |
565 prop.name = "resourcetype"; |
484 if(S_ISDIR(st.st_mode)) { |
566 if(S_ISDIR(st.st_mode)) { |
485 dav_propfind_add_str_prop(rq, &prop, "<D:collection/>", 15); |
567 dav_propfind_add_str_prop(rq, &prop, "<D:collection/>", 15); |
486 } else { |
568 } else { |
529 dav_propfind_add_prop_error(rq, prop, 404); |
611 dav_propfind_add_prop_error(rq, prop, 404); |
530 } |
612 } |
531 } |
613 } |
532 } |
614 } |
533 |
615 |
534 void dav_rq_proppatch(DAVPropertyBackend *b, ProppatchRequest *rq) { |
616 void dav_rq_proppatch(PersistenceManager *b, ProppatchRequest *rq) { |
535 DAV_FOREACH(p, rq->setProps) { |
617 DAV_FOREACH(p, rq->setProps) { |
536 XmlElement *prop = (XmlElement*)p->data; |
618 XmlElement *prop = (XmlElement*)p->data; |
537 propstat_add(rq->propstat, 403, prop); |
619 propstat_add(rq->propstat, 403, prop); |
538 } |
620 } |
539 |
621 |
573 xmlns = pool_malloc(map->pool, sizeof(XmlNs)); |
666 xmlns = pool_malloc(map->pool, sizeof(XmlNs)); |
574 if(xmlns == NULL) { |
667 if(xmlns == NULL) { |
575 return NULL; |
668 return NULL; |
576 } |
669 } |
577 |
670 |
578 xmlns->xmlns = ns; |
671 sstr_t newns = sstrdup(sstr(ns)); |
579 xmlns->nslen = strlen(ns); |
672 |
580 |
673 xmlns->xmlns = newns.ptr; |
581 xmlns->prefix = NULL; |
674 xmlns->nslen = newns.length; |
582 xmlns->prelen = 0; |
675 |
|
676 xmlns->prefix = pool_calloc(map->pool, 1, 8); |
|
677 xmlns->prelen = snprintf(xmlns->prefix, 7, "x%d", map->num); |
583 |
678 |
584 ucx_map_cstr_put(map->map, ns, xmlns); /* TODO: check return value */ |
679 ucx_map_cstr_put(map->map, ns, xmlns); /* TODO: check return value */ |
|
680 map->num++; |
585 return xmlns; |
681 return xmlns; |
586 } |
682 } |
587 |
683 |
588 XmlNs* xmlnsmap_get(XmlNsMap *map, char *ns) { |
684 XmlNs* xmlnsmap_get(XmlNsMap *map, char *ns) { |
589 return ucx_map_cstr_get(map->map, ns); |
685 return ucx_map_cstr_get(map->map, ns); |
596 if(parent->ctlen == 0) { |
692 if(parent->ctlen == 0) { |
597 parent->content = ucx_dlist_append(parent->content, child); |
693 parent->content = ucx_dlist_append(parent->content, child); |
598 } |
694 } |
599 } |
695 } |
600 |
696 |
601 void xmlelm_write(XmlElement *elm, sbuf_t *out, int wv) { |
697 void xmlelm_write(XmlElement *elm, Buffer *out, int wv) { |
602 sbuf_append(out, sstrn("<", 1)); |
698 sbuf_append(out, sstrn("<", 1)); |
603 sbuf_append(out, sstrn(elm->xmlns->prefix, elm->xmlns->prelen)); |
699 sbuf_append(out, sstrn(elm->xmlns->prefix, elm->xmlns->prelen)); |
604 sbuf_append(out, sstrn(":", 1)); |
700 sbuf_append(out, sstrn(":", 1)); |
605 sbuf_append(out, elm->name); |
701 sbuf_append(out, sstr(elm->name)); |
606 |
702 |
607 if(wv) { |
703 if(wv) { |
608 if(elm->ctlen == 0) { |
704 if(elm->ctlen == 0) { |
609 if(elm->content == NULL) { |
705 if(elm->content == NULL) { |
610 sbuf_append(out, sstrn(" />", 3)); |
706 sbuf_append(out, sstrn(" />", 3)); |
614 xmlelm_write((XmlElement*)pr->data, out, 1); |
710 xmlelm_write((XmlElement*)pr->data, out, 1); |
615 } |
711 } |
616 sbuf_append(out, sstrn("</", 2)); |
712 sbuf_append(out, sstrn("</", 2)); |
617 sbuf_append(out, sstrn(elm->xmlns->prefix, elm->xmlns->prelen)); |
713 sbuf_append(out, sstrn(elm->xmlns->prefix, elm->xmlns->prelen)); |
618 sbuf_append(out, sstrn(":", 1)); |
714 sbuf_append(out, sstrn(":", 1)); |
619 sbuf_append(out, elm->name); |
715 sbuf_append(out, sstr(elm->name)); |
620 sbuf_append(out, sstrn(">", 1)); |
716 sbuf_append(out, sstrn(">", 1)); |
621 } |
717 } |
622 } else { |
718 } else { |
623 sbuf_append(out, sstrn(" />", 3)); |
719 sbuf_append(out, sstrn(" />", 3)); |
624 sbuf_append(out, sstrn((char*)elm->content, elm->ctlen)); |
720 sbuf_append(out, sstrn((char*)elm->content, elm->ctlen)); |
625 sbuf_append(out, sstrn("</", 2)); |
721 sbuf_append(out, sstrn("</", 2)); |
626 sbuf_append(out, sstrn(elm->xmlns->prefix, elm->xmlns->prelen)); |
722 sbuf_append(out, sstrn(elm->xmlns->prefix, elm->xmlns->prelen)); |
627 sbuf_append(out, sstrn(":", 1)); |
723 sbuf_append(out, sstrn(":", 1)); |
628 sbuf_append(out, elm->name); |
724 sbuf_append(out, sstr(elm->name)); |
629 sbuf_append(out, sstrn(">", 1)); |
725 sbuf_append(out, sstrn(">", 1)); |
630 } |
726 } |
631 } else { |
727 } else { |
632 sbuf_append(out, sstrn(" />", 3)); |
728 sbuf_append(out, sstrn(" />", 3)); |
633 } |
729 } |
657 |
753 |
658 ucx_map_put(propstat->map, key, list); |
754 ucx_map_put(propstat->map, key, list); |
659 } |
755 } |
660 } |
756 } |
661 |
757 |
662 void propstat_write(Propstat *propstat, sbuf_t *out, int wv) { |
758 void propstat_write(Propstat *propstat, Buffer *out, int wv) { |
663 if(propstat->okprop) { |
759 if(propstat->okprop) { |
664 sbuf_puts(out, "<D:propstat>\n<D:prop>\n"); |
760 sbuf_puts(out, "<D:propstat>\n<D:prop>\n"); |
665 |
761 |
666 DAV_FOREACH(prop, propstat->okprop) { |
762 DAV_FOREACH(prop, propstat->okprop) { |
667 xmlelm_write((XmlElement*)prop->data, out, wv); |
763 xmlelm_write((XmlElement*)prop->data, out, wv); |