src/server/webdav/webdav.c

branch
webdav
changeset 217
8ed14d76db42
parent 216
ce2866ec97f6
child 220
2915b6c11aec
equal deleted inserted replaced
216:ce2866ec97f6 217:8ed14d76db42
37 37
38 #include "search.h" 38 #include "search.h"
39 #include "versioning.h" 39 #include "versioning.h"
40 #include "multistatus.h" 40 #include "multistatus.h"
41 #include "requestparser.h" 41 #include "requestparser.h"
42 #include "operation.h"
42 43
43 #include "../util/pblock.h" 44 #include "../util/pblock.h"
44 #include "../util/util.h" 45 #include "../util/util.h"
45 #include "../daemon/session.h" 46 #include "../daemon/session.h"
46 #include "../daemon/http.h" 47 #include "../daemon/http.h"
180 // TODO: handle all errors 181 // TODO: handle all errors
181 default: return REQ_ABORTED; 182 default: return REQ_ABORTED;
182 } 183 }
183 } 184 }
184 185
186 WebdavBackend *dav = rq->davCollection ?
187 rq->davCollection : &default_backend;
188
189
190 // requested uri path
191 char *path = pblock_findkeyval(pb_key_path, rq->vars);
192
193 // VFS settings are only taken from the first backend
194 uint32_t settings = dav->settings;
195
196 // list of individual WebdavPropfindRequest objects for each Backend
197 UcxList *requestObjects = NULL;
198
199 // Initialize all Webdav Backends
200 if(webdav_propfind_init(dav, propfind, path, &requestObjects)) {
201 return REQ_ABORTED;
202 }
203
185 // The multistatus response object contains responses for all 204 // The multistatus response object contains responses for all
186 // requested resources. At the end the Multistatus object will be 205 // requested resources. At the end the Multistatus object will be
187 // serialized to xml 206 // serialized to xml
188 Multistatus *ms = multistatus_response(sn, rq); 207 Multistatus *ms = multistatus_response(sn, rq);
189 if(!ms) { 208 if(!ms) {
191 } 210 }
192 // WebdavResponse is the public interface used by Backends 211 // WebdavResponse is the public interface used by Backends
193 // for adding resources to the response 212 // for adding resources to the response
194 WebdavResponse *response = (WebdavResponse*)ms; 213 WebdavResponse *response = (WebdavResponse*)ms;
195 214
196 WebdavBackend *dav = 215 WebdavOperation *op = webdav_operation_create(
197 rq->davCollection ? rq->davCollection : &default_backend; 216 sn->pool,
198 217 dav,
199 // requested uri path 218 requestObjects,
200 char *path = pblock_findkeyval(pb_key_path, rq->vars); 219 response);
201
202 // VFS settings are only taken from the first backend
203 uint32_t settings = dav->settings;
204
205 // list of individual WebdavPropfindRequest objects for each Backend
206 UcxList *requestObjects = NULL;
207
208 // Initialize all Webdav Backends
209 if(webdav_propfind_init(dav, propfind, path, &requestObjects)) {
210 return REQ_ABORTED;
211 }
212 220
213 // some Backends can list all children by themselves, but some 221 // some Backends can list all children by themselves, but some
214 // require the VFS for this 222 // require the VFS for this
215 WSBool usevfs = (settings & WS_PROPFIND_NO_VFS) != WS_PROPFIND_NO_VFS; 223 WSBool usevfs = (settings & WS_PROPFIND_NO_VFS) != WS_PROPFIND_NO_VFS;
216 struct stat s; 224 struct stat s;
232 } 240 }
233 if(propfind->depth == 0) { 241 if(propfind->depth == 0) {
234 usevfs = FALSE; 242 usevfs = FALSE;
235 } 243 }
236 244
237 int ret = REQ_ABORTED; 245 int ret = REQ_PROCEED;
238 if(!webdav_propfind_do(dav, requestObjects, response, NULL, path, statptr)) { 246
247 // create WebdavResource object for requested resource
248 if(!webdav_op_propfind_begin(op, path, NULL, statptr)) {
239 // propfind for the requested resource was successful 249 // propfind for the requested resource was successful
240 250
241 // usevfsdir is TRUE if 251 // usevfsdir is TRUE if
242 // the webdav backend has not disabled vfs usage 252 // the webdav backend has not disabled vfs usage
243 // the file is a directory 253 // the file is a directory
244 // depth is not 0 254 // depth is not 0
245 // in this case we need to execute propfind_do for all children 255 // in this case we need to execute propfind_do for all children
246 if(usevfs && !propfind_children(dav, requestObjects, response, vfs, path)) { 256 if(usevfs) {
247 ret = REQ_PROCEED; 257 if(!webdav_op_propfind_children(op, vfs, path)) {
258 ret = REQ_ABORTED;
259 }
248 } 260 }
249 } 261 }
250 262
251 // finish the propfind request 263 // finish the propfind request
252 // this function should cleanup all resources, therefore we execute it 264 // this function should cleanup all resources, therefore we execute it
253 // even if a previous function failed 265 // even if a previous function failed
254 if(dav->propfind_finish(propfind)) { 266 if(webdav_op_propfind_finish(op)) {
255 ret = REQ_ABORTED; 267 ret = REQ_ABORTED;
256 } 268 }
257 269
258 return ret; 270 return ret;
259 } 271 }
318 *out_req = requestObjects; 330 *out_req = requestObjects;
319 return REQ_PROCEED; 331 return REQ_PROCEED;
320 } 332 }
321 333
322 334
323 /*
324 * Executes propfind_do for each Backend
325 * The list requests must contain all WebdavPropfindRequest objects
326 * of all backends
327 */
328 int webdav_propfind_do(
329 WebdavBackend *dav,
330 UcxList *requests,
331 WebdavResponse *response,
332 VFS_DIR parent,
333 const char *path,
334 struct stat *s)
335 {
336 while(dav && requests) {
337 if(dav->propfind_do(requests->data, response, parent, path, s)) {
338 return REQ_ABORTED;
339 }
340
341 dav = dav->next;
342 requests = requests->next;
343 }
344 return REQ_PROCEED;
345 }
346
347 /*
348 * Executes propfind_finish for each Backend
349 */
350 int webdav_propfind_finish(WebdavBackend *dav, UcxList *requests) {
351 int ret = REQ_PROCEED;
352 while(dav && requests) {
353 if(dav->propfind_finish(requests->data)) {
354 ret = REQ_ABORTED;
355 }
356
357 dav = dav->next;
358 requests = requests->next;
359 }
360 return ret;
361 }
362
363
364 /*
365 * Uses the VFS to iterate over all children of the requsted resource
366 * and executes propfind for each child
367 */
368 int propfind_children(
369 WebdavBackend *dav,
370 UcxList *requests,
371 WebdavResponse *response,
372 VFSContext *vfs,
373 char *path)
374 {
375 WebdavPropfindRequest *request = requests->data;
376
377 UcxAllocator *a = session_get_allocator(request->sn);
378 pool_handle_t *pool = request->sn->pool;
379 UcxList *stack = ucx_list_prepend_a(a, NULL, path);
380 UcxList *stack_end = stack;
381 if(!stack) {
382 return 1;
383 }
384
385 // reusable buffer for full child path
386 char *newpath = NULL;
387 size_t newpathlen = 0;
388
389 int err = 0;
390 while(stack && !err) {
391 char *cur_path = stack->data;
392 size_t parent_len = strlen(cur_path);
393 if(parent_len > WEBDAV_PATH_MAX) {
394 log_ereport(LOG_FAILURE, "webdav: maximal path length exceeded");
395 err = 1;
396 break;
397 }
398 if(cur_path[parent_len-1] == '/') {
399 parent_len--;
400 }
401 size_t max_child_len = WEBDAV_PATH_MAX - parent_len;
402
403 // when newpath is initialized with the parent path
404 // set path_buf_init to TRUE
405 WSBool path_buf_init = FALSE;
406
407 VFS_DIR dir = vfs_opendir(vfs, path);
408 if(!dir) {
409 log_ereport(
410 LOG_FAILURE,
411 "webdav: propfind: cannot open directory %d",
412 vfs->vfs_errno);
413 err = 1;
414 break;
415 }
416
417 VFS_ENTRY f;
418 while(vfs_readdir_stat(dir, &f)) {
419 if(f.stat_errno != 0) {
420 continue;
421 }
422
423 size_t child_len = strlen(f.name);
424 if(child_len > max_child_len) {
425 log_ereport(LOG_FAILURE, "webdav: maximal path length exceeded");
426 err = 1;
427 break;
428 }
429 size_t childpathlen = parent_len + child_len + 1; // +1 '/'
430 if(childpathlen > newpathlen) {
431 // we're gonna need a bigger boa^H^H^Hbuffer
432 if(newpath) {
433 pool_free(pool, newpath);
434 }
435 newpath = pool_malloc(pool, childpathlen + 1);
436 if(!newpath) {
437 err = 1;
438 break;
439 }
440 newpathlen = childpathlen;
441 path_buf_init = FALSE;
442 }
443 // create full path string for this child
444 if(!path_buf_init) {
445 memcpy(newpath, cur_path, parent_len);
446 newpath[parent_len] = '/';
447 }
448 memcpy(newpath+parent_len+1, f.name, child_len);
449 newpath[childpathlen] = 0;
450
451 // propfind for this child
452 if(webdav_propfind_do(dav, requests, response, dir, newpath, &f.stat)) {
453 err = 1;
454 break;
455 }
456
457 // depth of -1 means infinity
458 if(request->depth == -1 && S_ISDIR(f.stat.st_mode)) {
459 char *pathcp = pool_malloc(pool, childpathlen + 1);
460 memcpy(pathcp, newpath, childpathlen + 1);
461
462 // add the newpath copy to the stack
463 // stack_end is always not NULL here, because we remove
464 // the first stack element at the end of the loop
465 UcxList *newlistelm = ucx_list_append_a(a, stack_end, pathcp);
466 if(!newlistelm) {
467 err = 1;
468 break;
469 }
470 stack_end = newlistelm;
471 }
472 }
473
474 vfs_closedir(dir);
475
476 if(cur_path != path) {
477 pool_free(pool, cur_path);
478 }
479 stack = ucx_list_remove_a(a, stack, stack);
480 }
481
482 // in case of an error, we have to free all remaining stack elements
483 UCX_FOREACH(elm, stack) {
484 char *data = elm->data;
485 if(data != path) {
486 pool_free(pool, data);
487 }
488 }
489
490 return err;
491 }
492
493 int webdav_proppatch(pblock *pb, Session *sn, Request *rq) { 335 int webdav_proppatch(pblock *pb, Session *sn, Request *rq) {
494 return REQ_ABORTED; 336 return REQ_ABORTED;
495 } 337 }
496 338
497 int webdav_mkcol(pblock *pb, Session *sn, Request *rq) { 339 int webdav_mkcol(pblock *pb, Session *sn, Request *rq) {
557 399
558 int default_propfind_do( 400 int default_propfind_do(
559 WebdavPropfindRequest *request, 401 WebdavPropfindRequest *request,
560 WebdavResponse *response, 402 WebdavResponse *response,
561 VFS_DIR parent, 403 VFS_DIR parent,
562 const char *path, 404 WebdavResource *resource,
563 struct stat *s) 405 struct stat *s)
564 { 406 {
565 DefaultWebdavData *data = request->userdata; 407 DefaultWebdavData *data = request->userdata;
566 408
567 // add a resource to the response 409 // TODO: rework
568 // usually this will lead to a <response> ... </response> tag in the
569 // multistatus response
570 WebdavResource *resource = response->addresource(response, path);
571 if(!resource) {
572 return 1;
573 }
574 410
575 // add all requested vfs properties like getcontentlength ... 411 // add all requested vfs properties like getcontentlength ...
576 if(webdav_add_vfs_properties( 412 if(webdav_add_vfs_properties(
577 resource, 413 resource,
578 request->sn->pool, 414 request->sn->pool,

mercurial