src/server/webdav/webdav.c

changeset 107
7e81699d1f77
parent 94
6b15a094d996
child 211
2160585200ac
equal deleted inserted replaced
106:b122f34ddc80 107:7e81699d1f77
29 #include <stdio.h> 29 #include <stdio.h>
30 #include <stdlib.h> 30 #include <stdlib.h>
31 #include <string.h> 31 #include <string.h>
32 32
33 #include "webdav.h" 33 #include "webdav.h"
34 #include <ucx/list.h>
35 #include <ucx/string.h>
36 #include "../util/pool.h"
37 #include "../util/pblock.h"
38 #include "../util/date.h"
39 #include "../util/util.h"
40
41 #include "../daemon/vfs.h"
42 #include "../daemon/protocol.h"
43
44 #include "davparser.h"
45 #include "parser.h"
46 #include "persistence.h"
47
48 static UcxMap *pmgr_map; // char*, PersistenceManager
49
50 int webdav_init(pblock *pb, Session *sn, Request *rq) {
51 pmgr_map = ucx_map_new(8);
52 PersistenceManager *defaultmgr = create_property_backend();
53 ucx_map_cstr_put(pmgr_map, "default", defaultmgr);
54 return REQ_PROCEED;
55 }
56
57 void webdav_add_persistence_manager(char *name, PersistenceManager *mgr) {
58 if(!pmgr_map) {
59 webdav_init(NULL, NULL, NULL);
60 }
61 ucx_map_cstr_put(pmgr_map, name, mgr);
62 }
63
64 int webdav_setcollection(pblock *pb, Session *sn, Request *rq) {
65 //char *name = pblock_findkeyval(pb_key_name, pb);
66 char *db = pblock_findval("db", pb);
67
68 if(!db) {
69 db = "default";
70 }
71
72 // setup DavCollection
73 DavCollection *dav = pool_malloc(sn->pool, sizeof(DavCollection));
74 dav->mgr = ucx_map_cstr_get(pmgr_map, db);
75 rq->davCollection = dav;
76
77 return REQ_NOACTION;
78 }
79
80 int webdav_service(pblock *pb, Session *sn, Request *rq) {
81 char *method = pblock_findkeyval(pb_key_method, rq->reqpb);
82 if(method == NULL) {
83 return REQ_ABORTED;
84 }
85
86 if(!strcmp(method, "PROPFIND")) {
87 return webdav_propfind(pb, sn, rq);
88 } else if(!strcmp(method, "PROPPATCH")) {
89 return webdav_proppatch(pb, sn, rq);
90 } else if(!strcmp(method, "PUT")) {
91 return webdav_put(pb, sn, rq);
92 } else if(!strcmp(method, "DELETE")) {
93 return webdav_delete(pb, sn, rq);
94 } else if(!strcmp(method, "MKCOL")) {
95 return webdav_mkcol(pb, sn, rq);
96 }
97
98 return REQ_NOACTION;
99 }
100
101 int webdav_put(pblock *pb, Session *sn, Request *rq) {
102 int length = 0;
103
104 char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars);
105 char *ctlen = pblock_findkeyval(pb_key_content_length, rq->headers);
106 if(ctlen) {
107 length = atoi(ctlen);
108 } else {
109 /* invalid request */
110 printf("invalid request\n");
111 return REQ_ABORTED;
112 }
113
114 printf("PUT length: %d\n", length);
115
116 //int status = 201;
117 //FILE *out = fopen(ppath, "w");
118
119 VFSContext *vfs = vfs_request_context(sn, rq);
120 SYS_FILE out = vfs_openWO(vfs, ppath);
121 if(out == NULL) {
122 fprintf(stderr, "vfs_openWO(%s, \"w\") failed\n", ppath);
123 //protocol_status(sn, rq, 500, NULL);
124 return REQ_ABORTED;
125 }
126
127 if(length > 0) {
128 size_t len = (length > 4096) ? (4096) : (length);
129 char *buffer = pool_malloc(sn->pool, len);
130
131 int r;
132 int r2 = 0;
133 while(r2 < length) {
134 r = netbuf_getbytes(sn->inbuf, buffer, len);
135 if(r == NETBUF_EOF) {
136 break;
137 }
138 system_fwrite(out, buffer, r);
139
140 r2 += r;
141 }
142
143 pool_free(sn->pool, buffer);
144 } else {
145
146 }
147 vfs_close(out);
148
149 protocol_status(sn, rq, 201, NULL);
150 pblock_removekey(pb_key_content_type, rq->srvhdrs);
151 pblock_nninsert("content-length", 0, rq->srvhdrs);
152 http_start_response(sn, rq);
153
154 return REQ_PROCEED;
155 }
156
157 int webdav_delete(pblock *pb, Session *sn, Request *rq) {
158 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
159 char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars);
160
161 VFSContext *vfs = vfs_request_context(sn, rq);
162
163 int status = 204;
164
165 struct stat st;
166 if(vfs_stat(vfs, ppath, &st)) {
167 return REQ_ABORTED;
168 }
169
170 if(!strcmp(uri, "/")) {
171 status = 403;
172 } else if((st.st_mode & S_IFDIR) == S_IFDIR) {
173 if(rmdir(ppath) != 0) {
174 /* ERROR */
175 status = 403;
176 }
177 } else {
178 if(vfs_unlink(vfs, ppath)) {
179 /* ERROR */
180 return REQ_ABORTED;
181 }
182 }
183
184 protocol_status(sn, rq, status, NULL);
185 pblock_removekey(pb_key_content_type, rq->srvhdrs);
186 pblock_nninsert("content-length", 0, rq->srvhdrs);
187 http_start_response(sn, rq);
188
189 return REQ_PROCEED;
190 }
191
192 int webdav_mkcol(pblock *pb, Session *sn, Request *rq) {
193 char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars);
194
195 VFSContext *vfs = vfs_request_context(sn, rq);
196 if(vfs_mkdir(vfs, ppath)) {
197 return REQ_ABORTED;
198 }
199
200 protocol_status(sn, rq, 201, NULL);
201 pblock_removekey(pb_key_content_type, rq->srvhdrs);
202 pblock_nninsert("content-length", 0, rq->srvhdrs);
203 http_start_response(sn, rq);
204
205 return REQ_ABORTED;
206 }
207
208 int webdav_copy(pblock *pb, Session *sn, Request *rq) {
209 return REQ_ABORTED;
210 }
211
212 int webdav_move(pblock *pb, Session *sn, Request *rq) {
213 return REQ_ABORTED;
214 }
215
216 int webdav_propfind(pblock *pb, Session *sn, Request *rq) {
217 /* TODO: clean up if errors occurs */
218
219 /* Get request body which contains the webdav XML request */
220 char *xml_body;
221 size_t xml_len = 0;
222
223 char *ctlen = pblock_findkeyval(pb_key_content_length, rq->headers);
224 if(ctlen) {
225 xml_len = atoi(ctlen);
226 } else {
227 /* invalid request */
228 printf("invalid request\n");
229 return REQ_ABORTED;
230 }
231
232 xml_body = pool_malloc(sn->pool, xml_len + 1);
233 if(xml_body == NULL) {
234 return REQ_ABORTED;
235 }
236 xml_body[xml_len] = 0;
237 if(!xml_body) {
238 /* server error */
239 printf("server error\n");
240 return REQ_ABORTED;
241 }
242
243 /* get request body */
244 int r = 0;
245 char *xb = xml_body;
246 size_t xl = xml_len;
247 while((r = netbuf_getbytes(sn->inbuf, xb, xl)) != NETBUF_EOF) {
248 xb += r;
249 xl -= r;
250 }
251
252 /*
253 * get requested properties and initialize some stuff
254 */
255 DavCollection *collection = rq->davCollection;
256 if(!collection) {
257 collection = pool_malloc(sn->pool, sizeof(DavCollection));
258 collection->mgr = ucx_map_cstr_get(pmgr_map, "default");
259 }
260
261 PropfindRequest *davrq = dav_parse_propfind2(sn, rq, xml_body, xml_len);
262 davrq->sn = sn;
263 davrq->rq = rq;
264 davrq->out = sbuf_new(512);
265 davrq->persistencemgr = collection->mgr;
266
267 /* begin multistatus response */
268 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
269 char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars);
270 davrq->uri = uri;
271 davrq->path = ppath;
272
273 VFSContext *vfs = vfs_request_context(sn, rq);
274
275 struct stat st;
276 if(vfs_stat(vfs, ppath, &st) != 0) {
277 return REQ_ABORTED;
278 }
279
280 // begin propfind
281 davrq->isdir = S_ISDIR(st.st_mode);
282 davrq->persistencemgr->propfind_begin(davrq->persistencemgr, davrq);
283
284 // create the response for the requested resource
285 dav_resource_response(davrq, sstr(ppath), sstr(uri));
286
287 /*
288 * if the requested webdav resource(file) is a directory, we create
289 * a response for every child
290 */
291 if(S_ISDIR(st.st_mode)) {
292 VFS_DIR dir = vfs_opendir(vfs, ppath);
293 if(dir == NULL) {
294 return REQ_ABORTED;
295 }
296
297 VFS_ENTRY entry;
298 while(vfs_readdir(dir, &entry)) {
299 sstr_t newpath = util_path_append(sn->pool, ppath, entry.name);
300 sstr_t newuri = util_path_append(sn->pool, uri, entry.name);
301 // child response
302 dav_resource_response(davrq, newpath, newuri);
303 }
304 }
305
306 // end propfind
307 davrq->persistencemgr->propfind_begin(davrq->persistencemgr, davrq);
308
309 // end xml
310 sbuf_puts(davrq->out, "</D:multistatus>\n");
311
312 //printf("%s\n", davrq->out->ptr);
313
314 // write xml response header
315 sbuf_t *out = sbuf_new(256);
316 sbuf_puts(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
317 sbuf_puts(out, "<D:multistatus");
318 UcxMapIterator nsiter = ucx_map_iterator(davrq->nsmap->map);
319 XmlNs *ns;
320 UCX_MAP_FOREACH(key, ns, nsiter) {
321 sbuf_puts(out, " xmlns:");
322 sbuf_puts(out, ns->prefix);
323 sbuf_puts(out, "=\"");
324 sbuf_puts(out, ns->xmlns);
325 sbuf_puts(out, "\"");
326 }
327 sbuf_puts(out, ">\n");
328
329 // send the xml response to the client
330 protocol_status(sn, rq, 207, "Multi Status");
331 pblock_removekey(pb_key_content_type, rq->srvhdrs);
332 pblock_nvinsert("content-type", "text/xml", rq->srvhdrs);
333 pblock_nninsert(
334 "content-length",
335 out->length + davrq->out->length,
336 rq->srvhdrs);
337
338 http_start_response(sn, rq);
339
340 // write content
341 size_t nr;
342 nr = net_write(sn->csd, out->ptr, out->length);
343 nr = net_write(sn->csd, davrq->out->ptr, davrq->out->length);
344
345 sbuf_free(out);
346 dav_free_propfind(davrq);
347
348 return REQ_PROCEED;
349 }
350
351 int webdav_proppatch(pblock *pb, Session *sn, Request *rq) {
352 printf("webdav-proppatch\n");
353 /* TODO: clean up if errors occurs */
354 /* TODO: this is the same code as in propfind */
355 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
356 if(uri == NULL) {
357 /* TODO: error */
358 return REQ_ABORTED;
359 }
360
361 // Get request body which contains the webdav XML request
362 char *xml_body;
363 size_t xml_len = 0;
364
365 char *ctlen = pblock_findkeyval(pb_key_content_length, rq->headers);
366 if(ctlen) {
367 xml_len = atoi(ctlen);
368 } else {
369 // invalid request
370 printf("invalid request\n");
371 return REQ_ABORTED;
372 }
373
374 xml_body = pool_malloc(sn->pool, xml_len + 1);
375 if(xml_body == NULL) {
376 return REQ_ABORTED;
377 }
378 xml_body[xml_len] = 0;
379 if(!xml_body) {
380 // server error
381 printf("server error\n");
382 return REQ_ABORTED;
383 }
384
385 // get request body
386 int r = 0;
387 char *xb = xml_body;
388 size_t xl = xml_len;
389 while((r = netbuf_getbytes(sn->inbuf, xb, xl)) != NETBUF_EOF) {
390 xb += r;
391 xl -= r;
392 }
393
394 /*
395 * parse the xml request and create the proppatch object
396 */
397 DavCollection *collection = rq->davCollection;
398 if(!collection) {
399 collection = pool_malloc(sn->pool, sizeof(DavCollection));
400 collection->mgr = ucx_map_cstr_get(pmgr_map, "default");
401 }
402
403 ProppatchRequest *davrq = dav_parse_proppatch(sn, rq, xml_body, xml_len);
404 davrq->sn = sn;
405 davrq->rq = rq;
406 davrq->out = sbuf_new(512);
407 davrq->backend = collection->mgr;
408 davrq->propstat = propstat_create(sn->pool);
409
410
411 /*
412 * begin multistatus response
413 *
414 * The webdav backend does the most work. The backend->proppatch function
415 * modifies the properties and adds status informations to the propstat
416 * member of the ProppatchRequest. All we have to do here is to create
417 * the xml response and send it to the client
418 */
419
420 /* write xml response header */
421 sbuf_puts(davrq->out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
422 //sbuf_puts(davrq->out, "<D:multistatus xmlns:D=\"DAV:\">\n");
423 sbuf_puts(davrq->out, "<D:multistatus");
424 UcxMapIterator nsiter = ucx_map_iterator(davrq->nsmap->map);
425 XmlNs *ns;
426 UCX_MAP_FOREACH(key, ns, nsiter) {
427 sbuf_puts(davrq->out, " xmlns:");
428 sbuf_puts(davrq->out, ns->prefix);
429 sbuf_puts(davrq->out, "=\"");
430 sbuf_puts(davrq->out, ns->xmlns);
431 sbuf_puts(davrq->out, "\"");
432 }
433 sbuf_puts(davrq->out, ">\n");
434
435 sbuf_puts(davrq->out, "<D:response>\n<D:href>");
436 sbuf_puts(davrq->out, uri);
437 sbuf_puts(davrq->out, "</D:href>\n");
438
439 /* do proppatch operation */
440 davrq->backend->proppatch(davrq->backend, davrq);
441
442 propstat_write(davrq->propstat, davrq->out, 0);
443
444 sbuf_puts(davrq->out, "</D:response>\n");
445 sbuf_puts(davrq->out, "</D:multistatus>\n");
446
447
448 /* send the xml response to the client */
449 protocol_status(sn, rq, 207, "Multi Status");
450 pblock_removekey(pb_key_content_type, rq->srvhdrs);
451 pblock_nvinsert("content-type", "text/xml", rq->srvhdrs);
452 pblock_nninsert("content-length", davrq->out->length, rq->srvhdrs);
453
454 //pblock_nvinsert("connection", "close", rq->srvhdrs);
455 http_start_response(sn, rq);
456
457 net_write(sn->csd, davrq->out->ptr, davrq->out->length);
458
459 dav_free_proppatch(davrq);
460
461 return REQ_PROCEED;
462 }
463
464 void dav_resource_response(PropfindRequest *davrq, sstr_t path, sstr_t uri) {
465 printf("dav_resource_response %s %s\n", sstrdup(path).ptr, sstrdup(uri).ptr);
466
467 sbuf_puts(davrq->out, "<D:response>\n");
468 sbuf_puts(davrq->out, "<D:href>");
469 sbuf_append(davrq->out, uri);
470 sbuf_puts(davrq->out, "</D:href>\n");
471
472 if(davrq->persistencemgr->vfs_props) {
473 // get some DAV properties from the file system
474 dav_rq_propfind(davrq->persistencemgr, davrq, path.ptr);
475 }
476 davrq->persistencemgr->propfind(davrq->persistencemgr, davrq, path.ptr);
477
478 if(davrq->prop) {
479 /*
480 * there are some properties written, so we close the
481 * prop and propstat tag
482 */
483 sbuf_puts(davrq->out, "</D:prop>\n");
484 sbuf_puts(davrq->out, "<D:status>HTTP/1.1 200 OK</D:status>\n");
485 sbuf_puts(davrq->out, "</D:propstat>\n");
486 }
487
488 if(davrq->notFoundProps != NULL) {
489 sbuf_puts(davrq->out, "<D:propstat>\n<D:prop>\n");
490 DAV_FOREACH(elm, davrq->notFoundProps) {
491 DavProperty *prop = (DavProperty*)elm->data;
492 sbuf_put(davrq->out, '<');
493 sbuf_puts(davrq->out, prop->xmlns->prefix);
494 sbuf_put(davrq->out, ':');
495
496 sbuf_puts(davrq->out, prop->name);
497 sbuf_puts(davrq->out, " />\n");
498 }
499 sbuf_puts(davrq->out, "</D:prop>\n");
500 sbuf_puts(davrq->out, "<D:status>HTTP/1.1 404 Not Found</D:status>\n");
501 sbuf_puts(davrq->out, "</D:propstat>\n");
502 }
503
504 sbuf_puts(davrq->out, "</D:response>\n");
505
506 /* reset */
507 davrq->prop = 0;
508 davrq->notFoundProps = NULL;
509 davrq->forbiddenProps = NULL;
510
511 }
512
513 void dav_propfind_add_str_prop(
514 PropfindRequest *davrq,
515 DavProperty* prop,
516 char *str,
517 size_t len)
518 {
519 if(!davrq->prop) {
520 sbuf_puts(davrq->out, "<D:propstat>\n<D:prop>\n");
521 davrq->prop = 1;
522 }
523
524 sbuf_put(davrq->out, '<');
525 sbuf_puts(davrq->out, prop->xmlns->prefix);
526 sbuf_put(davrq->out, ':');
527 sbuf_puts(davrq->out, prop->name);
528 sbuf_put(davrq->out, '>');
529
530 sbuf_append(davrq->out, sstrn(str, len));
531
532 sbuf_puts(davrq->out, "</");
533 sbuf_puts(davrq->out, prop->xmlns->prefix);
534 sbuf_put(davrq->out, ':');
535 sbuf_puts(davrq->out, prop->name);
536 sbuf_puts(davrq->out, ">\n");
537 }
538
539 void dav_propfind_add_prop_error(
540 PropfindRequest *davrq,
541 DavProperty *prop,
542 int error)
543 {
544 // TODO: different errors
545 davrq->notFoundProps = ucx_list_append(davrq->notFoundProps, prop);
546 }
547 34
548 35
549
550
551 /* WebDAV Default Backend */
552 static PersistenceManager dav_file_backend = {
553 dav_rq_propfind_begin,
554 dav_rq_propfind_end,
555 dav_rq_propfind,
556 dav_rq_proppatch,
557 0
558 };
559
560 PersistenceManager* create_property_backend() {
561 return &dav_file_backend;
562 }
563
564 void dav_rq_propfind_begin(PersistenceManager *mgr, PropfindRequest *rq) {
565
566 }
567
568 void dav_rq_propfind_end(PersistenceManager *mgr, PropfindRequest *rq) {
569
570 }
571
572 void dav_rq_propfind(PersistenceManager *b, PropfindRequest *rq ,char *path) {
573 struct stat st;
574 if(stat(path, &st) != 0) {
575 perror("dav_be_propfind");
576 fprintf(stderr, "Cannot get stat of file: %s\n", path);
577 }
578
579 if(rq->allprop) {
580 DavProperty prop;
581 prop.xmlns = xmlnsmap_get(rq->nsmap, "DAV:");
582
583 prop.name = "resourcetype";
584 if(S_ISDIR(st.st_mode)) {
585 dav_propfind_add_str_prop(rq, &prop, "<D:collection/>", 15);
586 } else {
587 dav_propfind_add_str_prop(rq, &prop, NULL, 0);
588 }
589
590 if(!S_ISDIR(st.st_mode)) {
591 prop.name = "getcontentlength";
592 char buf[32];
593 size_t n = snprintf(buf, 32, "%jd", st.st_size);
594 dav_propfind_add_str_prop(rq, &prop, buf, n);
595 }
596
597 prop.name = "getlastmodified";
598
599 sstr_t s = date_format_http(st.st_mtime, rq->sn->pool);
600 dav_propfind_add_str_prop(rq, &prop, s.ptr, s.length);
601
602 prop.name = "creationdate";
603 s = date_format_iso8601(st.st_ctime, rq->sn->pool);
604 dav_propfind_add_str_prop(rq, &prop, s.ptr, s.length);
605
606 return;
607 }
608
609 DAV_FOREACH(elm, rq->properties) {
610 DavProperty *prop = (DavProperty*)elm->data;
611
612 char *s = prop->name;
613 if(!strcmp(s, "resourcetype")) {
614 if(S_ISDIR(st.st_mode)) {
615 dav_propfind_add_str_prop(rq, prop, "<D:collection/>", 15);
616 } else {
617 dav_propfind_add_str_prop(rq, prop, NULL, 0);
618 }
619 } else if(!strcmp(s, "getcontentlength") && !S_ISDIR(st.st_mode)) {
620 char buf[32];
621 size_t n = snprintf(buf, 32, "%jd", st.st_size);
622 dav_propfind_add_str_prop(rq, prop, buf, n);
623 } else if(!strcmp(s, "getlastmodified")) {
624 sstr_t s = date_format_http(st.st_mtime, rq->sn->pool);
625 dav_propfind_add_str_prop(rq, prop, s.ptr, s.length);
626 } else if(!strcmp(s, "creationdate")) {
627 sstr_t s = date_format_iso8601(st.st_ctime, rq->sn->pool);
628 dav_propfind_add_str_prop(rq, prop, s.ptr, s.length);
629 } else {
630 dav_propfind_add_prop_error(rq, prop, 404);
631 }
632 }
633 }
634
635 void dav_rq_proppatch(PersistenceManager *b, ProppatchRequest *rq) {
636 DAV_FOREACH(p, rq->setProps) {
637 XmlElement *prop = (XmlElement*)p->data;
638 propstat_add(rq->propstat, 403, prop);
639 }
640
641 DAV_FOREACH(p, rq->removeProps) {
642 XmlElement *prop = (XmlElement*)p->data;
643 propstat_add(rq->propstat, 403, prop);
644 }
645 }
646
647
648
649 /*---------------------------------- utils ----------------------------------*/
650
651 /* XmlNsMap */
652
653 XmlNsMap* xmlnsmap_create(pool_handle_t *pool) {
654 XmlNsMap *map = pool_malloc(pool, sizeof(XmlNsMap));
655 UcxMap *uxm = ucx_map_new(16); // TODO: use pool for map
656 if(map == NULL || uxm == NULL) {
657 return NULL;
658 }
659 map->map = uxm;
660 map->pool = pool;
661 map->num = 0;
662
663 // create DAV: namespace
664 XmlNs *ns = pool_malloc(map->pool, sizeof(XmlNs));
665 ns->xmlns = "DAV:";
666 ns->prefix = "D";
667 ns->nslen = 4;
668 ns->prelen = 1;
669
670 ucx_map_cstr_put(uxm, "DAV:", ns);
671
672 return map;
673 }
674
675 void xmlnsmap_free(XmlNsMap *map) {
676 ucx_map_free(map->map);
677 }
678
679 XmlNs* xmlnsmap_put(XmlNsMap *map, char *ns) {
680 if(!ns) {
681 return NULL;
682 }
683
684 XmlNs *xmlns = xmlnsmap_get(map, ns);
685 if(xmlns != NULL) {
686 return xmlns;
687 }
688
689 xmlns = pool_malloc(map->pool, sizeof(XmlNs));
690 if(xmlns == NULL) {
691 return NULL;
692 }
693
694 sstr_t newns = sstrdup(sstr(ns));
695
696 xmlns->xmlns = newns.ptr;
697 xmlns->nslen = newns.length;
698
699 xmlns->prefix = pool_calloc(map->pool, 1, 8);
700 xmlns->prelen = snprintf(xmlns->prefix, 7, "x%d", map->num);
701
702 ucx_map_cstr_put(map->map, ns, xmlns); // TODO: check return value
703 map->num++;
704 return xmlns;
705 }
706
707 XmlNs* xmlnsmap_get(XmlNsMap *map, char *ns) {
708 return ucx_map_cstr_get(map->map, ns);
709 }
710
711
712 /* XmlElement */
713
714 void xmlelm_add_child(XmlElement *parent, XmlElement *child) {
715 if(parent->ctlen == 0) {
716 parent->content = ucx_list_append(parent->content, child);
717 }
718 }
719
720 void xmlelm_write(XmlElement *elm, Buffer *out, int wv) {
721 sbuf_append(out, sstrn("<", 1));
722 sbuf_append(out, sstrn(elm->xmlns->prefix, elm->xmlns->prelen));
723 sbuf_append(out, sstrn(":", 1));
724 sbuf_append(out, sstr(elm->name));
725
726 if(wv) {
727 if(elm->ctlen == 0) {
728 if(elm->content == NULL) {
729 sbuf_append(out, sstrn(" />", 3));
730 } else {
731 sbuf_append(out, sstrn(">", 1));
732 DAV_FOREACH(pr, (UcxList*)elm->content) {
733 xmlelm_write((XmlElement*)pr->data, out, 1);
734 }
735 sbuf_append(out, sstrn("</", 2));
736 sbuf_append(out, sstrn(elm->xmlns->prefix, elm->xmlns->prelen));
737 sbuf_append(out, sstrn(":", 1));
738 sbuf_append(out, sstr(elm->name));
739 sbuf_append(out, sstrn(">", 1));
740 }
741 } else {
742 sbuf_append(out, sstrn(" />", 3));
743 sbuf_append(out, sstrn((char*)elm->content, elm->ctlen));
744 sbuf_append(out, sstrn("</", 2));
745 sbuf_append(out, sstrn(elm->xmlns->prefix, elm->xmlns->prelen));
746 sbuf_append(out, sstrn(":", 1));
747 sbuf_append(out, sstr(elm->name));
748 sbuf_append(out, sstrn(">", 1));
749 }
750 } else {
751 sbuf_append(out, sstrn(" />", 3));
752 }
753 }
754
755
756 /* PropstatMap */
757
758 Propstat* propstat_create(pool_handle_t *pool) {
759 Propstat *propstat = (Propstat*)pool_malloc(pool, sizeof(Propstat));
760 propstat->map = ucx_map_new(8);
761 propstat->okprop = NULL;
762 propstat->pool = pool;
763 return propstat;
764 }
765
766 void propstat_add(Propstat *propstat, int status, XmlElement *prop) {
767 if(status == 200) {
768 propstat->okprop = ucx_list_append(propstat->okprop, prop);
769 } else {
770 UcxKey key;
771 key.data = &status;
772 key.len = sizeof(int);
773
774 UcxList *list = ucx_map_get(propstat->map, key);
775 list = ucx_list_append(list, prop);
776
777 ucx_map_put(propstat->map, key, list);
778 }
779 }
780
781 void propstat_write(Propstat *propstat, Buffer *out, int wv) {
782 if(propstat->okprop) {
783 sbuf_puts(out, "<D:propstat>\n<D:prop>\n");
784
785 DAV_FOREACH(prop, propstat->okprop) {
786 xmlelm_write((XmlElement*)prop->data, out, wv);
787 }
788
789 sbuf_puts(out, "\n</D:prop>\n<D:status>HTTP/1.1 200 OK</D:status>\n");
790 sbuf_puts(out, "</D:propstat>\n");
791 }
792
793 UcxMapIterator iter = ucx_map_iterator(propstat->map);
794 UcxList *proplist;
795 UCX_MAP_FOREACH(key, proplist, iter) {
796 if(proplist) {
797 sbuf_puts(out, "<D:propstat>\n<D:prop>\n");
798
799 DAV_FOREACH(prop, proplist) {
800 xmlelm_write((XmlElement*)prop->data, out, wv);
801 }
802
803 sbuf_puts(out, "\n</D:prop>\n<D:status>");
804
805 int status = *(int*)iter.cur->key.data;
806 if(status < 1000 && status > 0) {
807 char buf[5];
808 buf[4] = 0;
809 sprintf(buf, "%d ", status);
810 sbuf_puts(out, "HTTP/1.1 ");
811 sbuf_puts(out, buf);
812 sbuf_puts(out, (char*)protocol_status_message(status));
813 }
814
815 sbuf_puts(out, "</D:status>\n</D:propstat>\n");
816 }
817 }
818 }

mercurial