87 |
90 |
88 int webdav_register_backend(const char *name, webdav_init_func webdavInit, webdav_create_func webdavCreate) { |
91 int webdav_register_backend(const char *name, webdav_init_func webdavInit, webdav_create_func webdavCreate) { |
89 WebdavType *webdavType = malloc(sizeof(WebdavType)); |
92 WebdavType *webdavType = malloc(sizeof(WebdavType)); |
90 webdavType->init = webdavInit; |
93 webdavType->init = webdavInit; |
91 webdavType->create = webdavCreate; |
94 webdavType->create = webdavCreate; |
92 return ucx_map_cstr_put(webdav_type_map, name, webdavType); |
95 return cxMapPut(webdav_type_map, cx_hash_key_str(name), webdavType); |
93 } |
96 } |
94 |
97 |
95 WebdavType* webdav_get_type(scstr_t dav_class) { |
98 WebdavType* webdav_get_type(cxstring dav_class) { |
96 return ucx_map_sstr_get(webdav_type_map, dav_class); |
99 return cxMapGet(webdav_type_map, cx_hash_key_bytes((unsigned const char *)dav_class.ptr, dav_class.length)); |
97 } |
100 } |
98 |
101 |
99 void* webdav_init_backend(ServerConfiguration *cfg, pool_handle_t *pool, WebdavType *dav_class, WSConfigNode *config, int *error) { |
102 void* webdav_init_backend(ServerConfiguration *cfg, pool_handle_t *pool, WebdavType *dav_class, WSConfigNode *config, int *error) { |
100 *error = 0; |
103 *error = 0; |
101 if(dav_class->init) { |
104 if(dav_class->init) { |
125 if(webdav_is_initialized) { |
128 if(webdav_is_initialized) { |
126 return REQ_NOACTION; |
129 return REQ_NOACTION; |
127 } |
130 } |
128 webdav_is_initialized = TRUE; |
131 webdav_is_initialized = TRUE; |
129 |
132 |
130 webdav_type_map = ucx_map_new(8); |
133 webdav_type_map = cxHashMapCreate(cxDefaultAllocator, 8); |
131 if(!webdav_type_map) { |
134 if(!webdav_type_map) { |
132 return REQ_ABORTED; |
135 return REQ_ABORTED; |
133 } |
136 } |
134 |
137 |
135 method_handler_map = ucx_map_new(64); |
138 method_handler_map = cxHashMapCreate(cxDefaultAllocator, 64); |
136 if(!method_handler_map) { |
139 if(!method_handler_map) { |
137 return REQ_ABORTED; |
140 return REQ_ABORTED; |
138 } |
141 } |
139 |
142 |
140 init_default_backend(); |
143 init_default_backend(); |
141 ucx_map_cstr_put(webdav_type_map, "default", &default_backend); |
144 cxMapPut(webdav_type_map, cx_hash_key_str("default"), &default_backend); |
142 |
145 |
143 ucx_map_cstr_put(method_handler_map, "OPTIONS", webdav_options); |
146 cxMapPut(method_handler_map, cx_hash_key_str("OPTIONS"), webdav_options); |
144 ucx_map_cstr_put(method_handler_map, "PROPFIND", webdav_propfind); |
147 cxMapPut(method_handler_map, cx_hash_key_str("PROPFIND"), webdav_propfind); |
145 ucx_map_cstr_put(method_handler_map, "PROPPATCH", webdav_proppatch); |
148 cxMapPut(method_handler_map, cx_hash_key_str("PROPPATCH"), webdav_proppatch); |
146 ucx_map_cstr_put(method_handler_map, "MKCOL", webdav_mkcol); |
149 cxMapPut(method_handler_map, cx_hash_key_str("MKCOL"), webdav_mkcol); |
147 ucx_map_cstr_put(method_handler_map, "POST", webdav_post); |
150 cxMapPut(method_handler_map, cx_hash_key_str("POST"), webdav_post); |
148 ucx_map_cstr_put(method_handler_map, "DELETE", webdav_delete); |
151 cxMapPut(method_handler_map, cx_hash_key_str("DELETE"), webdav_delete); |
149 ucx_map_cstr_put(method_handler_map, "PUT", webdav_put); |
152 cxMapPut(method_handler_map, cx_hash_key_str("PUT"), webdav_put); |
150 ucx_map_cstr_put(method_handler_map, "COPY", webdav_copy); |
153 cxMapPut(method_handler_map, cx_hash_key_str("COPY"), webdav_copy); |
151 ucx_map_cstr_put(method_handler_map, "MOVE", webdav_move); |
154 cxMapPut(method_handler_map, cx_hash_key_str("MOVE"), webdav_move); |
152 ucx_map_cstr_put(method_handler_map, "LOCK", webdav_lock); |
155 cxMapPut(method_handler_map, cx_hash_key_str("LOCK"), webdav_lock); |
153 ucx_map_cstr_put(method_handler_map, "UNLOCK", webdav_unlock); |
156 cxMapPut(method_handler_map, cx_hash_key_str("UNLOCK"), webdav_unlock); |
154 ucx_map_cstr_put(method_handler_map, "REPORT", webdav_report); |
157 cxMapPut(method_handler_map, cx_hash_key_str("REPORT"), webdav_report); |
155 ucx_map_cstr_put(method_handler_map, "ACL", webdav_acl); |
158 cxMapPut(method_handler_map, cx_hash_key_str("ACL"), webdav_acl); |
156 |
159 |
157 ucx_map_cstr_put(method_handler_map, "SEARCH", webdav_search); |
160 cxMapPut(method_handler_map, cx_hash_key_str("SEARCH"), webdav_search); |
158 |
161 |
159 ucx_map_cstr_put(method_handler_map, "VERSION-CONTROL", webdav_version_control); |
162 cxMapPut(method_handler_map, cx_hash_key_str("VERSION-CONTROL"), webdav_version_control); |
160 ucx_map_cstr_put(method_handler_map, "CHECKOUT", webdav_checkout); |
163 cxMapPut(method_handler_map, cx_hash_key_str("CHECKOUT"), webdav_checkout); |
161 ucx_map_cstr_put(method_handler_map, "CHECKIN", webdav_checkin); |
164 cxMapPut(method_handler_map, cx_hash_key_str("CHECKIN"), webdav_checkin); |
162 ucx_map_cstr_put(method_handler_map, "UNCHECKOUT", webdav_uncheckout); |
165 cxMapPut(method_handler_map, cx_hash_key_str("UNCHECKOUT"), webdav_uncheckout); |
163 ucx_map_cstr_put(method_handler_map, "MKWORKSPACE", webdav_mkworkspace); |
166 cxMapPut(method_handler_map, cx_hash_key_str("MKWORKSPACE"), webdav_mkworkspace); |
164 ucx_map_cstr_put(method_handler_map, "UPDATE", webdav_update); |
167 cxMapPut(method_handler_map, cx_hash_key_str("UPDATE"), webdav_update); |
165 ucx_map_cstr_put(method_handler_map, "LABEL", webdav_label); |
168 cxMapPut(method_handler_map, cx_hash_key_str("LABEL"), webdav_label); |
166 ucx_map_cstr_put(method_handler_map, "MERGE", webdav_merge); |
169 cxMapPut(method_handler_map, cx_hash_key_str("MERGE"), webdav_merge); |
167 |
170 |
168 dav_namespace.href = (xmlChar*)"DAV:"; |
171 dav_namespace.href = (xmlChar*)"DAV:"; |
169 dav_namespace.prefix = (xmlChar*)"D"; |
172 dav_namespace.prefix = (xmlChar*)"D"; |
170 |
173 |
171 dav_resourcetype_empty.namespace = &dav_namespace; |
174 dav_resourcetype_empty.namespace = &dav_namespace; |
189 protocol_status(sn, rq, 500, NULL); |
192 protocol_status(sn, rq, 500, NULL); |
190 return REQ_ABORTED; |
193 return REQ_ABORTED; |
191 } |
194 } |
192 char *method = pblock_findkeyval(pb_key_method, rq->reqpb); |
195 char *method = pblock_findkeyval(pb_key_method, rq->reqpb); |
193 |
196 |
194 FuncPtr saf = (FuncPtr)ucx_map_cstr_get(method_handler_map, method); |
197 FuncPtr saf = (FuncPtr)cxMapGet(method_handler_map, cx_hash_key_str(method)); |
195 if(!saf) { |
198 if(!saf) { |
196 return REQ_NOACTION; |
199 return REQ_NOACTION; |
197 } |
200 } |
198 |
201 |
199 return saf(pb, sn, rq); |
202 return saf(pb, sn, rq); |
200 } |
203 } |
201 |
204 |
202 UcxBuffer* rqbody2buffer(Session *sn, Request *rq) { |
205 int rqbody2buffer(Session *sn, Request *rq, CxBuffer *buf) { |
203 if(!sn->inbuf) { |
206 if(!sn->inbuf) { |
204 //request body required, set http response code |
207 //request body required, set http response code |
205 protocol_status(sn, rq, 400, NULL); |
208 protocol_status(sn, rq, 400, NULL); |
206 return NULL; |
209 return 1; |
207 } |
210 } |
208 |
211 |
209 UcxBuffer *buf = ucx_buffer_new( |
212 CxAllocator *a = pool_allocator(sn->pool); |
210 NULL, |
213 if(cxBufferInit(buf, NULL, sn->inbuf->maxsize, a, CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS)) { |
211 sn->inbuf->maxsize, |
|
212 UCX_BUFFER_AUTOEXTEND); |
|
213 if(!buf) { |
|
214 protocol_status(sn, rq, 500, NULL); |
214 protocol_status(sn, rq, 500, NULL); |
215 return NULL; |
215 return 1; |
216 } |
216 } |
217 |
217 |
218 char in[2048]; |
218 char in[2048]; |
219 int r; |
219 int r; |
220 while((r = netbuf_getbytes(sn->inbuf, in, 2048)) > 0) { |
220 while((r = netbuf_getbytes(sn->inbuf, in, 2048)) > 0) { |
221 if(ucx_buffer_write(in, 1, r, buf) != r) { |
221 if(cxBufferWrite(in, 1, r, buf) != r) { |
222 protocol_status(sn, rq, 500, NULL); |
222 protocol_status(sn, rq, 500, NULL); |
223 ucx_buffer_free(buf); |
223 cxBufferDestroy(buf); |
224 return NULL; |
224 return 1; |
225 } |
225 } |
226 } |
226 } |
227 |
227 |
228 return buf; |
228 return 0; |
229 } |
229 } |
230 |
230 |
231 int webdav_options(pblock *pb, Session *sn, Request *rq) { |
231 int webdav_options(pblock *pb, Session *sn, Request *rq) { |
232 return REQ_ABORTED; |
232 return REQ_ABORTED; |
233 } |
233 } |
316 int webdav_propfind_init( |
316 int webdav_propfind_init( |
317 WebdavBackend *dav, |
317 WebdavBackend *dav, |
318 WebdavPropfindRequest *propfind, |
318 WebdavPropfindRequest *propfind, |
319 const char *path, |
319 const char *path, |
320 const char *uri, |
320 const char *uri, |
321 UcxList **out_req) |
321 WebdavPropfindRequestList **out_req) |
322 { |
322 { |
323 pool_handle_t *pool = propfind->sn->pool; |
323 pool_handle_t *pool = propfind->sn->pool; |
324 UcxAllocator *a = session_get_allocator(propfind->sn); |
324 CxAllocator *a = pool_allocator(pool); |
325 |
325 |
326 // list of individual WebdavPropfindRequest objects for each Backend |
326 // list of individual WebdavPropfindRequest objects for each Backend |
327 UcxList *requestObjects = NULL; |
327 WebdavPropfindRequestList *requestObjectsBegin = NULL; |
|
328 WebdavPropfindRequestList *requestObjectsEnd = NULL; |
328 |
329 |
329 // new properties after init, start with clone of original plist |
330 // new properties after init, start with clone of original plist |
330 WebdavPList *newProp = webdav_plist_clone(pool, propfind->properties); |
331 WebdavPList *newProp = webdav_plist_clone(pool, propfind->properties); |
331 size_t newPropCount = propfind->propcount; |
332 size_t newPropCount = propfind->propcount; |
332 |
333 |
345 pReq->properties = newProp; |
346 pReq->properties = newProp; |
346 pReq->propcount = newPropCount; |
347 pReq->propcount = newPropCount; |
347 pReq->dav = davList; |
348 pReq->dav = davList; |
348 |
349 |
349 // add new WebdavPropfindRequest object to list for later use |
350 // add new WebdavPropfindRequest object to list for later use |
350 requestObjects = ucx_list_append_a(a, requestObjects, pReq); |
351 WebdavPropfindRequestList *reqListElm = pool_malloc(pool, sizeof(WebdavPropfindRequestList)); |
351 if(!requestObjects) { |
352 if(!reqListElm) { |
352 return REQ_ABORTED; // OOM |
353 return REQ_ABORTED; // OOM |
353 } |
354 } |
|
355 reqListElm->propfind = pReq; |
|
356 reqListElm->next = NULL; |
|
357 cx_linked_list_add( |
|
358 (void**)&requestObjectsBegin, |
|
359 (void**)&requestObjectsEnd, |
|
360 -1, |
|
361 offsetof(WebdavPropfindRequestList, next), |
|
362 reqListElm); |
354 |
363 |
355 // create plist copy as out-plist for init |
364 // create plist copy as out-plist for init |
356 newProp = webdav_plist_clone(pool, newProp); |
365 newProp = webdav_plist_clone(pool, newProp); |
357 |
366 |
358 // run init: this can generate a new properties list (newProp) |
367 // run init: this can generate a new properties list (newProp) |
606 void *userdata) |
617 void *userdata) |
607 { |
618 { |
608 DeleteOp *op = userdata; |
619 DeleteOp *op = userdata; |
609 |
620 |
610 // create object for this file |
621 // create object for this file |
611 DeleteFile *file = almalloc(op->a, sizeof(DeleteFile)); |
622 DeleteFile *file = cxMalloc(op->a, sizeof(DeleteFile)); |
612 if(!file) { |
623 if(!file) { |
613 return 1; |
624 return 1; |
614 } |
625 } |
615 file->path = sstrdup_a(op->a, sstr((char*)path)).ptr; |
626 file->path = cx_strdup_a(op->a, cx_str((char*)path)).ptr; |
616 if(!file->path) { |
627 if(!file->path) { |
617 return 1; |
628 return 1; |
618 } |
629 } |
619 file->s = *s; |
630 file->s = *s; |
|
631 file->next = NULL; |
620 |
632 |
621 // determine which list to use |
633 // determine which list to use |
622 UcxList **begin; |
634 DeleteFile **begin; |
623 UcxList **end; |
635 DeleteFile **end; |
624 if(S_ISDIR(s->st_mode)) { |
636 if(S_ISDIR(s->st_mode)) { |
625 begin = &op->dirs_begin; |
637 begin = &op->dirs_begin; |
626 end = &op->dirs_end; |
638 end = &op->dirs_end; |
627 } else { |
639 } else { |
628 begin = &op->files_begin; |
640 begin = &op->files_begin; |
629 end = &op->files_end; |
641 end = &op->files_end; |
630 } |
642 } |
631 |
643 |
632 // add file to list |
644 // add file to list |
633 UcxList *elm = ucx_list_append_a(op->a, NULL, file); |
645 cx_linked_list_add( |
634 if(!elm) { |
646 (void**)begin, (void**)end, |
635 alfree(op->a, file->path); // at least do some cleanup, although it |
647 offsetof(DeleteFile, prev), offsetof(DeleteFile, next), |
636 alfree(op->a, file); // isn't really necessary |
648 file); |
637 return 1; |
|
638 } |
|
639 if(*begin == NULL) { |
|
640 *begin = elm; |
|
641 *end = elm; |
|
642 } else { |
|
643 ucx_list_concat(*end, elm); |
|
644 *end = elm; |
|
645 } |
|
646 |
649 |
647 return 0; |
650 return 0; |
648 } |
651 } |
649 |
652 |
650 static int webdav_delete_collection(WebdavVFSOperation *op) |
653 static int webdav_delete_collection(WebdavVFSOperation *op) |
651 { |
654 { |
652 DeleteOp del; |
655 DeleteOp del; |
653 ZERO(&del, sizeof(DeleteOp)); |
656 ZERO(&del, sizeof(DeleteOp)); |
654 del.a = session_get_allocator(op->sn); |
657 del.a = pool_allocator(op->sn->pool); |
655 |
658 |
656 // get a list of all files |
659 // get a list of all files |
657 if(webdav_op_iterate_children(op->vfs, -1, NULL, op->path, |
660 if(webdav_op_iterate_children(op->vfs, -1, NULL, op->path, |
658 deletelist_add, &del)) |
661 deletelist_add, &del)) |
659 { |
662 { |
662 |
665 |
663 // add root to list of dir list |
666 // add root to list of dir list |
664 DeleteFile root; |
667 DeleteFile root; |
665 root.path = op->path; |
668 root.path = op->path; |
666 root.s = *op->stat; |
669 root.s = *op->stat; |
667 UcxList root_elm; |
670 root.prev = NULL; |
668 root_elm.data = &root; |
671 root.next = del.dirs_begin; |
669 root_elm.prev = NULL; |
|
670 root_elm.next = del.dirs_begin; |
|
671 |
672 |
672 if(del.dirs_begin) { |
673 if(del.dirs_begin) { |
673 del.dirs_begin->prev = &root_elm; |
674 del.dirs_begin->prev = &root; |
674 del.dirs_begin = &root_elm; |
|
675 } else { |
675 } else { |
676 del.dirs_begin = &root_elm; |
676 del.dirs_end = &root; |
677 del.dirs_end = &root_elm; |
677 } |
678 } |
678 del.dirs_begin = &root; |
679 |
679 |
680 // delete files first |
680 // delete files first |
681 UCX_FOREACH(elm, del.files_begin) { |
681 for(DeleteFile *file=del.files_begin;file;file=file->next) { |
682 DeleteFile *file = elm->data; |
|
683 WebdavVFSOperation sub = webdav_vfs_sub_op(op, file->path, &file->s); |
682 WebdavVFSOperation sub = webdav_vfs_sub_op(op, file->path, &file->s); |
684 if(webdav_vfs_op_do(&sub, WEBDAV_VFS_DELETE)) { |
683 if(webdav_vfs_op_do(&sub, WEBDAV_VFS_DELETE)) { |
685 return 1; |
684 return 1; |
686 } |
685 } |
687 } |
686 } |
688 |
687 |
689 // delete directories, reverse order |
688 // delete directories, reverse order |
690 for(UcxList *elm=del.dirs_end;elm;elm=elm->prev) { |
689 for(DeleteFile *file=del.dirs_end;file;file=file->prev) { |
691 DeleteFile *file = elm->data; |
|
692 WebdavVFSOperation sub = webdav_vfs_sub_op(op, file->path, &file->s); |
690 WebdavVFSOperation sub = webdav_vfs_sub_op(op, file->path, &file->s); |
693 if(webdav_vfs_op_do(&sub, WEBDAV_VFS_DELETE)) { |
691 if(webdav_vfs_op_do(&sub, WEBDAV_VFS_DELETE)) { |
694 return 1; |
692 return 1; |
695 } |
693 } |
696 } |
694 } |