src/server/webdav/webdav.c

branch
webdav
changeset 212
d7e7ea9c6bc6
parent 211
2160585200ac
child 213
4a6be4f10d5f
equal deleted inserted replaced
211:2160585200ac 212:d7e7ea9c6bc6
51 51
52 static WSNamespace dav_namespace; 52 static WSNamespace dav_namespace;
53 53
54 static WebdavProperty dav_resourcetype_empty; 54 static WebdavProperty dav_resourcetype_empty;
55 static WebdavProperty dav_resourcetype_collection; 55 static WebdavProperty dav_resourcetype_collection;
56 static WSXmlNode dav_resourcetype_collection_value; 56 static WSXmlNode dav_resourcetype_collection_value; // TODO: change type to WSXmlData
57 57
58 static void init_default_backend(void) { 58 static void init_default_backend(void) {
59 memset(&default_backend, 0, sizeof(WebdavBackend)); 59 memset(&default_backend, 0, sizeof(WebdavBackend));
60 default_backend.propfind_init = default_propfind_init; 60 default_backend.propfind_init = default_propfind_init;
61 default_backend.propfind_do = default_propfind_do; 61 default_backend.propfind_do = default_propfind_do;
98 dav_resourcetype_empty.namespace = &dav_namespace; 98 dav_resourcetype_empty.namespace = &dav_namespace;
99 dav_resourcetype_empty.name = "resourcetype"; 99 dav_resourcetype_empty.name = "resourcetype";
100 100
101 dav_resourcetype_collection.namespace = &dav_namespace; 101 dav_resourcetype_collection.namespace = &dav_namespace;
102 dav_resourcetype_collection.name = "resourcetype"; 102 dav_resourcetype_collection.name = "resourcetype";
103 dav_resourcetype_collection.value = &dav_resourcetype_collection_value; 103 dav_resourcetype_collection.value.node = &dav_resourcetype_collection_value;
104 dav_resourcetype_collection.vtype = WS_VALUE_XML_NODE;
104 dav_resourcetype_collection_value.content = (xmlChar*)"<D:collection/>"; 105 dav_resourcetype_collection_value.content = (xmlChar*)"<D:collection/>";
105 dav_resourcetype_collection_value.type = XML_TEXT_NODE; 106 dav_resourcetype_collection_value.type = XML_TEXT_NODE;
106 107
107 108
108 return REQ_PROCEED; 109 return REQ_PROCEED;
125 return saf(pb, sn, rq); 126 return saf(pb, sn, rq);
126 } 127 }
127 128
128 UcxBuffer* rqbody2buffer(Session *sn, Request *rq) { 129 UcxBuffer* rqbody2buffer(Session *sn, Request *rq) {
129 if(!sn->inbuf) { 130 if(!sn->inbuf) {
131 //request body required, set http response code
130 protocol_status(sn, rq, 400, NULL); 132 protocol_status(sn, rq, 400, NULL);
131 return NULL; 133 return NULL;
132 } 134 }
133 135
134 UcxBuffer *buf = ucx_buffer_new( 136 UcxBuffer *buf = ucx_buffer_new(
160 int webdav_propfind(pblock *pb, Session *sn, Request *rq) { 162 int webdav_propfind(pblock *pb, Session *sn, Request *rq) {
161 UcxBuffer *reqbody = rqbody2buffer(sn, rq); 163 UcxBuffer *reqbody = rqbody2buffer(sn, rq);
162 if(!reqbody) { 164 if(!reqbody) {
163 return REQ_ABORTED; 165 return REQ_ABORTED;
164 } 166 }
167
168 UcxAllocator *a = session_get_allocator(sn);
165 169
166 int error = 0; 170 int error = 0;
167 WebdavPropfindRequest *propfind = propfind_parse( 171 WebdavPropfindRequest *propfind = propfind_parse(
168 sn, 172 sn,
169 rq, 173 rq,
176 // TODO: handle all errors 180 // TODO: handle all errors
177 default: return REQ_ABORTED; 181 default: return REQ_ABORTED;
178 } 182 }
179 } 183 }
180 184
181 185 // The multistatus response object contains responses for all
186 // requested resources. At the end the Multistatus object will be
187 // serialized to xml
182 Multistatus *ms = multistatus_response(sn, rq); 188 Multistatus *ms = multistatus_response(sn, rq);
183 if(!ms) { 189 if(!ms) {
184 return REQ_ABORTED; 190 return REQ_ABORTED;
185 } 191 }
192 // WebdavResponse is the public interface used by Backends
193 // for adding resources to the response
186 WebdavResponse *response = (WebdavResponse*)ms; 194 WebdavResponse *response = (WebdavResponse*)ms;
187 195
188 WebdavBackend *dav = 196 WebdavBackend *dav =
189 rq->davCollection ? rq->davCollection : &default_backend; 197 rq->davCollection ? rq->davCollection : &default_backend;
190 198
199 // requested uri path
191 char *path = pblock_findkeyval(pb_key_path, rq->vars); 200 char *path = pblock_findkeyval(pb_key_path, rq->vars);
192 201
202 // Initialize WebDAV Backend Chain
203 //
204 // Call propfind_init of each Backend
205 // propfind_init can return a new property list, which
206 // will be passed to the next backend
207 //
208 // VFS settings are only taken from the first backend
193 uint32_t settings = dav->settings; 209 uint32_t settings = dav->settings;
194 if(dav->propfind_init(propfind, path)) { 210
195 return REQ_ABORTED; 211 // list of individual WebdavPropfindRequest objects for each Backend
196 } 212 UcxList *backendPropfind = NULL;
197 213
214 // new properties after init, start with clone of original plist
215 WebdavPList *newProp = webdav_plist_clone(sn->pool, propfind->properties);
216 size_t newPropCount = propfind->propcount;
217
218 WebdavBackend *davList = dav;
219 while(davList) {
220 // create WebdavPropfindRequest copy
221 WebdavPropfindRequest *pReq = pool_malloc(
222 sn->pool,
223 sizeof(WebdavPropfindRequest));
224 memcpy(propfind, pReq, sizeof(WebdavPropfindRequest));
225 // use new plist after previous init (or orig. plist in the first run)
226 pReq->properties = newProp;
227 pReq->propcount = newPropCount;
228
229 // add new WebdavPropfindRequest object to list for later use
230 backendPropfind = ucx_list_append_a(a, backendPropfind, pReq);
231 if(!backendPropfind) {
232 return REQ_ABORTED; // OOM
233 }
234
235 // create plist copy as out-plist for init
236 newProp = webdav_plist_clone(sn->pool, newProp);
237
238 // run init: this can generate a new properties list (newProp)
239 // which will be passed to the next backend
240 if(dav->propfind_init(pReq, path, &newProp)) {
241 return REQ_ABORTED;
242 }
243
244 newPropCount = webdav_plist_count(newProp);
245
246 davList = davList->next;
247 }
248
249 // some Backends can list all children by themselves, but some
250 // require the VFS for this
198 WSBool usevfs = (settings & WS_PROPFIND_NO_VFS) != WS_PROPFIND_NO_VFS; 251 WSBool usevfs = (settings & WS_PROPFIND_NO_VFS) != WS_PROPFIND_NO_VFS;
199 struct stat s; 252 struct stat s;
200 struct stat *statptr = NULL; 253 struct stat *statptr = NULL;
201 254
202 VFSContext *vfs = NULL; 255 VFSContext *vfs = NULL;
203 if(usevfs) { 256 if(usevfs) {
204 vfs = vfs_request_context(sn, rq); 257 vfs = vfs_request_context(sn, rq);
205 258
206 if(vfs_stat(vfs, path, &s)) { 259 if(vfs_stat(vfs, path, &s)) {
260 protocol_status(sn, rq, util_errno2status(vfs->vfs_errno), NULL);
207 return REQ_ABORTED; 261 return REQ_ABORTED;
208 } 262 }
209 statptr = &s; 263 statptr = &s;
210 if(!S_ISDIR(s.st_mode)) { 264 if(!S_ISDIR(s.st_mode)) {
265 // the file is not a directory, therefore we don't need the VFS
211 usevfs = FALSE; 266 usevfs = FALSE;
212 } 267 }
213 } 268 }
214 if(propfind->depth == 0) { 269 if(propfind->depth == 0) {
215 usevfs = FALSE; 270 usevfs = FALSE;
216 } 271 }
217 272
218 int ret = REQ_ABORTED; 273 int ret = REQ_ABORTED;
219 if(!dav->propfind_do(propfind, response, NULL, path, statptr)) { 274 if(!webdav_propfind_do(dav, backendPropfind, response, NULL, path, statptr)) {
220 // propfind for the requested resource was successful 275 // propfind for the requested resource was successful
221 276
222 // usevfsdir is TRUE if 277 // usevfsdir is TRUE if
223 // the webdav backend has not disabled vfs usage 278 // the webdav backend has not disabled vfs usage
224 // the file is a directory 279 // the file is a directory
225 // depth is not 0 280 // depth is not 0
226 // in this case we need to execute propfind_do for all children 281 // in this case we need to execute propfind_do for all children
227 if(usevfs && !propfind_children(dav, propfind, response, vfs, path)) { 282 if(usevfs && !propfind_children(dav, backendPropfind, response, vfs, path)) {
228 ret = REQ_PROCEED; 283 ret = REQ_PROCEED;
229 } 284 }
230 } 285 }
231 286
232 // finish the propfind request 287 // finish the propfind request
237 } 292 }
238 293
239 return ret; 294 return ret;
240 } 295 }
241 296
297 /*
298 * Executes propfind_do for each Backend
299 * The list requests must contain all WebdavPropfindRequest objects
300 * of all backends
301 */
302 int webdav_propfind_do(
303 WebdavBackend *webdav,
304 UcxList *requests,
305 WebdavResponse *response,
306 VFS_DIR parent,
307 const char *path,
308 struct stat *s)
309 {
310 while(webdav && requests) {
311 if(webdav->propfind_do(requests->data, response, parent, path, s)) {
312 return REQ_ABORTED;
313 }
314
315 webdav = webdav->next;
316 requests = requests->next;
317 }
318 return REQ_PROCEED;
319 }
320
321 /*
322 * Executes propfind_finish for each Backend
323 */
324 int webdav_propfind_finish(WebdavBackend *webdav, UcxList *requests) {
325 int ret = REQ_PROCEED;
326 while(webdav && requests) {
327 if(webdav->propfind_finish(requests->data)) {
328 ret = REQ_ABORTED;
329 }
330
331 webdav = webdav->next;
332 requests = requests->next;
333 }
334 return ret;
335 }
336
337
338 /*
339 * Uses the VFS to iterate over all children of the requsted resource
340 * and executes propfind for each child
341 */
242 int propfind_children( 342 int propfind_children(
243 WebdavBackend *dav, 343 WebdavBackend *dav,
244 WebdavPropfindRequest *request, 344 UcxList *requests,
245 WebdavResponse *response, 345 WebdavResponse *response,
246 VFSContext *vfs, 346 VFSContext *vfs,
247 char *path) 347 char *path)
248 { 348 {
349 WebdavPropfindRequest *request = requests->data;
350
249 UcxAllocator *a = session_get_allocator(request->sn); 351 UcxAllocator *a = session_get_allocator(request->sn);
250 pool_handle_t *pool = request->sn->pool; 352 pool_handle_t *pool = request->sn->pool;
251 UcxList *stack = ucx_list_prepend_a(a, NULL, path); 353 UcxList *stack = ucx_list_prepend_a(a, NULL, path);
252 UcxList *stack_end = stack; 354 UcxList *stack_end = stack;
253 if(!stack) { 355 if(!stack) {
319 } 421 }
320 memcpy(newpath+parent_len+1, f.name, child_len); 422 memcpy(newpath+parent_len+1, f.name, child_len);
321 newpath[childpathlen] = 0; 423 newpath[childpathlen] = 0;
322 424
323 // propfind for this child 425 // propfind for this child
324 if(dav->propfind_do(request, response, dir, newpath, &f.stat)) { 426 if(webdav_propfind_do(dav, requests, response, dir, newpath, &f.stat)) {
325 err = 1; 427 err = 1;
326 break; 428 break;
327 } 429 }
328 430
329 // depth of -1 means infinity 431 // depth of -1 means infinity
409 511
410 /* ------------------------ default webdav backend ------------------------ */ 512 /* ------------------------ default webdav backend ------------------------ */
411 513
412 int default_propfind_init( 514 int default_propfind_init(
413 WebdavPropfindRequest *rq, 515 WebdavPropfindRequest *rq,
414 const char* path) 516 const char* path,
517 WebdavPList **outplist)
415 { 518 {
416 DefaultWebdavData *data = pool_malloc( 519 DefaultWebdavData *data = pool_malloc(
417 rq->sn->pool, 520 rq->sn->pool,
418 sizeof(DefaultWebdavData)); 521 sizeof(DefaultWebdavData));
419 if(!data) { 522 if(!data) {
482 } 585 }
483 } 586 }
484 return depth; 587 return depth;
485 } 588 }
486 589
590 WebdavPList* webdav_plist_clone(pool_handle_t *pool, WebdavPList *list) {
591 WebdavPList *new_list = NULL; // start of the new list
592 WebdavPList *new_list_end = NULL; // end of the new list
593
594 WebdavPList *elm = list;
595 while(elm) {
596 // copy list item
597 WebdavPList *new_elm = pool_malloc(pool, sizeof(WebdavPList));
598 if(!new_elm) {
599 return NULL;
600 }
601 new_elm->property = elm->property; // new list contains original ptr
602 new_elm->prev = NULL;
603 new_elm->next = NULL;
604
605 if(new_list_end) {
606 new_list_end->next = elm;
607 elm->prev = new_list_end;
608
609 new_list_end = elm;
610 } else {
611 new_list = new_elm;
612 new_list_end = new_elm;
613 }
614
615 elm = elm->next;
616 }
617
618 return new_list;
619 }
620
621 size_t webdav_plist_count(WebdavPList *list) {
622 size_t count = 0;
623 WebdavPList *elm = list;
624 while(elm) {
625 count++;
626 elm = elm->next;
627 }
628 return count;
629 }
630
487 WSNamespace* webdav_dav_namespace(void) { 631 WSNamespace* webdav_dav_namespace(void) {
488 return &dav_namespace; 632 return &dav_namespace;
489 } 633 }
490 634
491 WebdavProperty* webdav_dav_property( 635 WebdavProperty* webdav_dav_property(
494 { 638 {
495 WebdavProperty *property = pool_malloc(pool, sizeof(WebdavProperty)); 639 WebdavProperty *property = pool_malloc(pool, sizeof(WebdavProperty));
496 if(!property) { 640 if(!property) {
497 return NULL; 641 return NULL;
498 } 642 }
643 memset(property, 0, sizeof(WebdavProperty));
499 644
500 property->namespace = &dav_namespace; 645 property->namespace = &dav_namespace;
501 property->lang = NULL;
502 property->name = name; 646 property->name = name;
503 property->value = NULL;
504 return property; 647 return property;
505 } 648 }
506 649
507 int webdav_property_set_value( 650 int webdav_property_set_value(
508 WebdavProperty *p, 651 WebdavProperty *p,
516 ZERO(node, sizeof(WSXmlNode)); 659 ZERO(node, sizeof(WSXmlNode));
517 660
518 node->content = (xmlChar*)value; 661 node->content = (xmlChar*)value;
519 node->type = XML_TEXT_NODE; 662 node->type = XML_TEXT_NODE;
520 663
521 p->value = node; 664 p->value.node = node;
665 p->vtype = WS_VALUE_XML_NODE;
522 return 0; 666 return 0;
523 } 667 }
524 668
525 WebdavVFSProperties webdav_vfs_properties( 669 WebdavVFSProperties webdav_vfs_properties(
526 WebdavPropfindRequest *rq, 670 WebdavPropfindRequest *rq,
554 } else { 698 } else {
555 removethis = NULL; 699 removethis = NULL;
556 } 700 }
557 701
558 if(removefromlist && removethis) { 702 if(removefromlist && removethis) {
703
559 if(prev) { 704 if(prev) {
560 prev->next = next; 705 prev->next = next;
561 } else { 706 } else {
562 rq->properties = next; 707 rq->properties = next;
563 } 708 }

mercurial