33 |
33 |
34 #include "utils.h" |
34 #include "utils.h" |
35 #include "webdav.h" |
35 #include "webdav.h" |
36 #include "session.h" |
36 #include "session.h" |
37 #include "methods.h" |
37 #include "methods.h" |
38 #include "ucx/buffer.h" |
38 #include <cx/buffer.h> |
39 #include "ucx/utils.h" |
39 #include <cx/utils.h> |
|
40 #include <cx/linked_list.h> |
|
41 #include <cx/hash_map.h> |
|
42 #include <cx/compare.h> |
40 #include "davqlparser.h" |
43 #include "davqlparser.h" |
41 #include "davqlexec.h" |
44 #include "davqlexec.h" |
42 |
45 |
43 |
46 |
44 DavContext* dav_context_new(void) { |
47 DavContext* dav_context_new(void) { |
45 // initialize |
48 // initialize |
46 DavContext *context = calloc(1, sizeof(DavContext)); |
49 DavContext *context = calloc(1, sizeof(DavContext)); |
47 if(!context) { |
50 if(!context) { |
48 return NULL; |
51 return NULL; |
49 } |
52 } |
50 context->sessions = NULL; |
53 context->sessions = cxLinkedListCreate(cxDefaultAllocator, cx_cmp_intptr, CX_STORE_POINTERS); |
51 context->http_proxy = calloc(1, sizeof(DavProxy)); |
54 context->http_proxy = calloc(1, sizeof(DavProxy)); |
52 if(!context->http_proxy) { |
55 if(!context->http_proxy) { |
53 dav_context_destroy(context); |
56 dav_context_destroy(context); |
54 return NULL; |
57 return NULL; |
55 } |
58 } |
56 context->https_proxy = calloc(1, sizeof(DavProxy)); |
59 context->https_proxy = calloc(1, sizeof(DavProxy)); |
57 if(!context->https_proxy) { |
60 if(!context->https_proxy) { |
58 dav_context_destroy(context); |
61 dav_context_destroy(context); |
59 return NULL; |
62 return NULL; |
60 } |
63 } |
61 context->namespaces = ucx_map_new(16); |
64 context->namespaces = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); |
62 if(!context->namespaces) { |
65 if(!context->namespaces) { |
63 dav_context_destroy(context); |
66 dav_context_destroy(context); |
64 return NULL; |
67 return NULL; |
65 } |
68 } |
66 context->namespaceinfo = ucx_map_new(16); |
69 context->namespaceinfo = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); |
67 if(!context->namespaceinfo) { |
70 if(!context->namespaceinfo) { |
68 dav_context_destroy(context); |
71 dav_context_destroy(context); |
69 } |
72 } |
70 context->keys = ucx_map_new(16); |
73 context->keys = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); |
71 if(!context->keys) { |
74 if(!context->keys) { |
72 dav_context_destroy(context); |
75 dav_context_destroy(context); |
73 return NULL; |
76 return NULL; |
74 } |
77 } |
75 |
78 |
95 return context; |
98 return context; |
96 } |
99 } |
97 |
100 |
98 void dav_context_destroy(DavContext *ctx) { |
101 void dav_context_destroy(DavContext *ctx) { |
99 // destroy all sessions assoziated with this context |
102 // destroy all sessions assoziated with this context |
100 UcxList *elm = ctx->sessions; |
103 CxIterator i = cxListIterator(ctx->sessions); |
101 while(elm) { |
104 cx_foreach(DavSession*, sn, i) { |
102 DavSession *sn = elm->data; |
|
103 elm = elm->next; |
|
104 dav_session_destroy(sn); |
105 dav_session_destroy(sn); |
105 } |
106 } |
|
107 cxListDestroy(ctx->sessions); |
106 if(ctx->http_proxy) { |
108 if(ctx->http_proxy) { |
107 free(ctx->http_proxy); |
109 free(ctx->http_proxy); |
108 } |
110 } |
109 if(ctx->https_proxy) { |
111 if(ctx->https_proxy) { |
110 free(ctx->https_proxy); |
112 free(ctx->https_proxy); |
111 } |
113 } |
112 |
114 |
113 if(ctx->namespaces) { |
115 if(ctx->namespaces) { |
114 UcxMapIterator i = ucx_map_iterator(ctx->namespaces); |
116 i = cxMapIteratorValues(ctx->namespaces); |
115 UcxKey k; |
117 cx_foreach(DavNamespace*, ns, i) { |
116 DavNamespace *ns; |
|
117 UCX_MAP_FOREACH(k, ns, i) { |
|
118 if(!ns) continue; |
118 if(!ns) continue; |
119 if(ns->prefix) { |
119 if(ns->prefix) { |
120 free(ns->prefix); |
120 free(ns->prefix); |
121 } |
121 } |
122 if(ns->name) { |
122 if(ns->name) { |
123 free(ns->name); |
123 free(ns->name); |
124 } |
124 } |
125 free(ns); |
125 free(ns); |
126 } |
126 } |
127 ucx_map_free(ctx->namespaces); |
127 cxMapDestroy(ctx->namespaces); |
128 } |
128 } |
129 if(ctx->namespaceinfo) { |
129 if(ctx->namespaceinfo) { |
130 // TODO: implement |
130 // TODO: implement |
131 } |
131 } |
132 if(ctx->keys) { |
132 if(ctx->keys) { |
133 UcxMapIterator i = ucx_map_iterator(ctx->keys); |
133 i = cxMapIteratorValues(ctx->keys); |
134 UcxKey k; |
134 cx_foreach(DavKey*, key, i) { |
135 DavKey *key; |
|
136 UCX_MAP_FOREACH(k, key, i) { |
|
137 if(!key) continue; |
135 if(!key) continue; |
138 if(key->name) { |
136 if(key->name) { |
139 free(key->name); |
137 free(key->name); |
140 } |
138 } |
141 if(key->data) { |
139 if(key->data) { |
142 free(key->data); |
140 free(key->data); |
143 } |
141 } |
144 free(key); |
142 free(key); |
145 } |
143 } |
146 ucx_map_free(ctx->keys); |
144 cxMapDestroy(ctx->keys); |
147 } |
145 } |
148 |
146 |
149 free(ctx); |
147 free(ctx); |
150 } |
148 } |
151 |
149 |
152 void dav_context_add_key(DavContext *context, DavKey *key) { |
150 void dav_context_add_key(DavContext *context, DavKey *key) { |
153 ucx_map_cstr_put(context->keys, key->name, key); |
151 cxMapPut(context->keys, cx_hash_key_str(key->name), key); |
154 } |
152 } |
155 |
153 |
156 DavKey* dav_context_get_key(DavContext *context, char *name) { |
154 DavKey* dav_context_get_key(DavContext *context, const char *name) { |
157 if(name) { |
155 if(name) { |
158 return ucx_map_cstr_get(context->keys, name); |
156 return cxMapGet(context->keys, cx_hash_key_str(name)); |
159 } |
157 } |
160 return NULL; |
158 return NULL; |
161 } |
159 } |
162 |
160 |
163 int dav_add_namespace(DavContext *context, const char *prefix, const char *name) { |
161 int dav_add_namespace(DavContext *context, const char *prefix, const char *name) { |
184 |
182 |
185 return err; |
183 return err; |
186 } |
184 } |
187 |
185 |
188 DavNamespace* dav_get_namespace(DavContext *context, const char *prefix) { |
186 DavNamespace* dav_get_namespace(DavContext *context, const char *prefix) { |
189 return ucx_map_cstr_get(context->namespaces, prefix); |
187 return cxMapGet(context->namespaces, cx_hash_key_str(prefix)); |
190 } |
188 } |
191 |
189 |
192 DavNamespace* dav_get_namespace_s(DavContext *context, sstr_t prefix) { |
190 DavNamespace* dav_get_namespace_s(DavContext *context, cxstring prefix) { |
193 return ucx_map_sstr_get(context->namespaces, prefix); |
191 return cxMapGet(context->namespaces, cx_hash_key(prefix.ptr, prefix.length)); |
194 } |
192 } |
195 |
193 |
196 int dav_enable_namespace_encryption(DavContext *context, const char *ns, DavBool encrypt) { |
194 int dav_enable_namespace_encryption(DavContext *context, const char *ns, DavBool encrypt) { |
197 DavNSInfo *info = ucx_map_cstr_get(context->namespaceinfo, ns); |
195 CxHashKey hkey = cx_hash_key_str(ns); |
|
196 DavNSInfo *info = cxMapGet(context->namespaceinfo, hkey); |
198 if(!info) { |
197 if(!info) { |
199 info = calloc(1, sizeof(DavNSInfo)); |
198 info = calloc(1, sizeof(DavNSInfo)); |
200 info->encrypt = encrypt; |
199 info->encrypt = encrypt; |
201 ucx_map_cstr_put(context->namespaceinfo, ns, info); |
200 cxMapPut(context->namespaceinfo, hkey, info); |
202 } else { |
201 } else { |
203 info->encrypt = encrypt; |
202 info->encrypt = encrypt; |
204 } |
203 } |
205 return 0; |
204 return 0; |
206 } |
205 } |
207 |
206 |
208 int dav_namespace_is_encrypted(DavContext *context, const char *ns) { |
207 int dav_namespace_is_encrypted(DavContext *context, const char *ns) { |
209 DavNSInfo *info = ucx_map_cstr_get(context->namespaceinfo, ns); |
208 DavNSInfo *info = cxMapGet(context->namespaceinfo, cx_hash_key_str(ns)); |
210 if(info) { |
209 if(info) { |
211 return info->encrypt; |
210 return info->encrypt; |
212 } |
211 } |
213 return 0; |
212 return 0; |
214 } |
213 } |
248 { |
247 { |
249 char *pname = strchr(prefixed_name, ':'); |
248 char *pname = strchr(prefixed_name, ':'); |
250 if(pname) { |
249 if(pname) { |
251 DavNamespace *ns = dav_get_namespace_s( |
250 DavNamespace *ns = dav_get_namespace_s( |
252 ctx, |
251 ctx, |
253 sstrn(prefixed_name, pname-prefixed_name)); |
252 cx_strn(prefixed_name, pname-prefixed_name)); |
254 if(ns) { |
253 if(ns) { |
255 *name = pname +1; |
254 *name = pname +1; |
256 return ns; |
255 return ns; |
257 } else { |
256 } else { |
258 *name = NULL; |
257 *name = NULL; |
259 return NULL; |
258 return NULL; |
260 } |
259 } |
261 } else { |
260 } else { |
262 *name = prefixed_name; |
261 *name = prefixed_name; |
263 return dav_get_namespace_s(ctx, S("D")); |
262 return dav_get_namespace_s(ctx, cx_str("D")); |
264 } |
263 } |
265 } |
264 } |
266 |
265 |
267 // TODO: add sstr_t version of dav_get_property_ns |
266 // TODO: add sstr_t version of dav_get_property_ns |
268 |
267 |
269 void dav_set_effective_href(DavSession *sn, DavResource *resource) { |
268 void dav_set_effective_href(DavSession *sn, DavResource *resource) { |
270 char *eff_url; |
269 char *eff_url; |
271 curl_easy_getinfo(sn->handle, CURLINFO_EFFECTIVE_URL, &eff_url); |
270 curl_easy_getinfo(sn->handle, CURLINFO_EFFECTIVE_URL, &eff_url); |
272 if(eff_url) { |
271 if(eff_url) { |
273 char *href = util_url_path(eff_url); |
272 const char *href = util_url_path(eff_url); |
274 if(strcmp(href, resource->href)) { |
273 if(strcmp(href, resource->href)) { |
275 dav_session_free(sn, resource->href); |
274 dav_session_free(sn, resource->href); |
276 resource->href = dav_session_strdup(sn, href); |
275 resource->href = dav_session_strdup(sn, href); |
277 } |
276 } |
278 } |
277 } |
279 } |
278 } |
280 |
279 |
281 DavResource* dav_get(DavSession *sn, char *path, char *properties) { |
280 DavResource* dav_get(DavSession *sn, char *path, const char *properties) { |
282 CURL *handle = sn->handle; |
281 CURL *handle = sn->handle; |
283 DavResource *resource = dav_resource_new(sn, path); |
282 DavResource *resource = dav_resource_new(sn, path); |
284 util_set_url(sn, dav_resource_get_href(resource)); |
283 util_set_url(sn, dav_resource_get_href(resource)); |
285 |
284 |
286 UcxList *proplist = NULL; |
285 CxList *proplist = NULL; |
287 if(properties) { |
286 if(properties) { |
288 proplist = parse_properties_string(sn->context, sstr(properties)); |
287 proplist = parse_properties_string(sn->context, cx_str(properties)); |
289 } |
288 } |
290 UcxBuffer *rqbuf = create_propfind_request(sn, proplist, "propfind", 0); |
289 CxBuffer *rqbuf = create_propfind_request(sn, proplist, "propfind", 0); |
291 UcxBuffer *rpbuf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND); |
290 CxBuffer *rpbuf = cxBufferCreate(NULL, 4096, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); |
292 |
291 |
293 //fwrite(rqbuf->space, 1, rqbuf->size, stdout); |
292 //fwrite(rqbuf->space, 1, rqbuf->size, stdout); |
294 //printf("\n"); |
293 //printf("\n"); |
295 |
294 |
296 CURLcode ret = do_propfind_request(sn, rqbuf, rpbuf); |
295 CURLcode ret = do_propfind_request(sn, rqbuf, rpbuf); |
308 dav_session_set_error(sn, ret, status); |
307 dav_session_set_error(sn, ret, status); |
309 dav_resource_free(resource); |
308 dav_resource_free(resource); |
310 resource = NULL; |
309 resource = NULL; |
311 } |
310 } |
312 |
311 |
313 ucx_buffer_free(rqbuf); |
312 cxBufferFree(rqbuf); |
314 ucx_buffer_free(rpbuf); |
313 cxBufferFree(rpbuf); |
315 while(proplist) { |
314 |
316 DavProperty *p = proplist->data; |
315 if(proplist) { |
317 free(p->name); |
316 CxIterator i = cxListIterator(proplist); |
318 free(p); |
317 cx_foreach(DavProperty*, p, i) { |
319 UcxList *next = proplist->next; |
318 free(p->name); |
320 free(proplist); |
319 } |
321 proplist = next; |
320 cxListDestroy(proplist); |
322 } |
321 } |
323 |
322 |
324 return resource; |
323 return resource; |
325 } |
324 } |
326 |
325 |
327 |
326 |
328 int dav_propfind(DavSession *sn, DavResource *root, UcxBuffer *rqbuf) { |
327 int dav_propfind(DavSession *sn, DavResource *root, CxBuffer *rqbuf) { |
329 // clean resource properties |
328 // clean resource properties |
330 DavResourceData *data = root->data; |
329 DavResourceData *data = root->data; |
331 ucx_map_clear(data->properties); // TODO: free existing content |
330 cxMapClear(data->properties); // TODO: free existing content |
332 |
331 |
333 CURL *handle = sn->handle; |
332 CURL *handle = sn->handle; |
334 util_set_url(sn, dav_resource_get_href(root)); |
333 util_set_url(sn, dav_resource_get_href(root)); |
335 |
334 |
336 UcxBuffer *rpbuf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND); |
335 CxBuffer *rpbuf = cxBufferCreate(NULL, 4096, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); |
337 DavResource *resource = root; |
336 DavResource *resource = root; |
338 CURLcode ret = do_propfind_request(sn, rqbuf, rpbuf); |
337 CURLcode ret = do_propfind_request(sn, rqbuf, rpbuf); |
339 long status = 0; |
338 long status = 0; |
340 long error = 0; |
339 long error = 0; |
341 curl_easy_getinfo (handle, CURLINFO_RESPONSE_CODE, &status); |
340 curl_easy_getinfo (handle, CURLINFO_RESPONSE_CODE, &status); |
348 root->exists = 1; |
347 root->exists = 1; |
349 } else { |
348 } else { |
350 dav_session_set_error(sn, ret, status); |
349 dav_session_set_error(sn, ret, status); |
351 error = 1; |
350 error = 1; |
352 } |
351 } |
353 ucx_buffer_free(rpbuf); |
352 cxBufferFree(rpbuf); |
354 return error; |
353 return error; |
355 } |
354 } |
356 |
355 |
357 UcxList* parse_properties_string(DavContext *context, sstr_t str) { |
356 CxList* parse_properties_string(DavContext *context, cxstring str) { |
358 UcxList *proplist = NULL; |
357 CxList *proplist = cxLinkedListCreateSimple(sizeof(DavProperty)); |
359 ssize_t nprops = 0; |
358 |
360 sstr_t *props = sstrsplit(str, S(","), &nprops); |
359 CxStrtokCtx tok = cx_strtok(str, cx_str(","), INT_MAX); |
361 for(int i=0;i<nprops;i++) { |
360 cxstring s; |
362 sstr_t s = props[i]; |
361 while(cx_strtok_next(&tok, &s)) { |
363 sstr_t nsname = sstrchr(s, ':'); |
362 cxstring nsname = cx_strchr(s, ':'); |
364 if(nsname.length > 0) { |
363 if(nsname.length > 0) { |
365 sstr_t nspre = sstrsubsl(s, 0, nsname.ptr - s.ptr); |
364 cxstring nspre = cx_strsubsl(s, 0, nsname.ptr - s.ptr); |
366 nsname.ptr++; |
365 nsname.ptr++; |
367 nsname.length--; |
366 nsname.length--; |
368 |
367 |
369 DavProperty *dp = malloc(sizeof(DavProperty)); |
368 DavProperty dp; |
370 sstr_t pre = sstrtrim(nspre); |
369 cxstring pre = cx_strtrim(nspre); |
371 dp->ns = dav_get_namespace_s(context, pre); |
370 dp.ns = dav_get_namespace_s(context, pre); |
372 dp->name = sstrdup(nsname).ptr; |
371 dp.name = cx_strdup(nsname).ptr; |
373 if(dp->ns && dp->name) { |
372 dp.value = NULL; |
374 proplist = ucx_list_append(proplist, dp); |
373 if(dp.ns && dp.name) { |
|
374 cxListAdd(proplist, &dp); |
375 } else { |
375 } else { |
376 free(dp->name); |
376 free(dp.name); |
377 free(dp); |
|
378 } |
377 } |
379 } |
378 } |
380 free(s.ptr); |
379 } |
381 } |
380 |
382 free(props); |
|
383 return proplist; |
381 return proplist; |
384 } |
382 } |
385 |
383 |
386 DavResource* dav_query(DavSession *sn, char *query, ...) { |
384 DavResource* dav_query(DavSession *sn, char *query, ...) { |
387 DavQLStatement *stmt = dav_parse_statement(sstr(query)); |
385 DavQLStatement *stmt = dav_parse_statement(cx_str(query)); |
388 if(!stmt) { |
386 if(!stmt) { |
389 sn->error = DAV_ERROR; |
387 sn->error = DAV_ERROR; |
390 return NULL; |
388 return NULL; |
391 } |
389 } |
392 if(stmt->errorcode != 0) { |
390 if(stmt->errorcode != 0) { |