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 } |