libidav/webdav.c

changeset 43
03076907b58a
parent 41
1c598ee0d3d9
child 45
e3839719b079
equal deleted inserted replaced
42:6518b035a9df 43:03076907b58a
31 #include <string.h> 31 #include <string.h>
32 #include <libxml/tree.h> 32 #include <libxml/tree.h>
33 33
34 #include "utils.h" 34 #include "utils.h"
35 #include "webdav.h" 35 #include "webdav.h"
36 #include "session.h"
36 #include "methods.h" 37 #include "methods.h"
37 #include "davql.h" 38 #include "davql.h"
38 #include "ucx/buffer.h" 39 #include "ucx/buffer.h"
39 #include "ucx/utils.h" 40 #include "ucx/utils.h"
40
41 41
42 42
43 DavContext* dav_context_new() { 43 DavContext* dav_context_new() {
44 DavContext *context = malloc(sizeof(DavContext)); 44 DavContext *context = malloc(sizeof(DavContext));
45 if(!context) { 45 if(!context) {
66 free(davns); 66 free(davns);
67 ucx_map_free(context->namespaces); 67 ucx_map_free(context->namespaces);
68 free(context); 68 free(context);
69 return NULL; 69 return NULL;
70 } 70 }
71
72 DavNamespace *idavns = malloc(sizeof(DavNamespace));
73 if(!idavns) {
74 free(davns);
75 ucx_map_free(context->namespaces);
76 free(context);
77 return NULL;
78 }
79 idavns->prefix = "idav";
80 davns->name = DAV_NS;
81 if(ucx_map_cstr_put(context->namespaces, "idav", idavns)) {
82 free(davns);
83 free(idavns);
84 ucx_map_free(context->namespaces);
85 free(context);
86 return NULL;
87 }
88
71 89
72 return context; 90 return context;
73 } 91 }
74 92
75 void dav_context_destroy(DavContext *ctx) { 93 void dav_context_destroy(DavContext *ctx) {
91 void dav_context_add_key(DavContext *context, DavKey *key) { 109 void dav_context_add_key(DavContext *context, DavKey *key) {
92 ucx_map_cstr_put(context->keys, key->name, key); 110 ucx_map_cstr_put(context->keys, key->name, key);
93 } 111 }
94 112
95 DavKey* dav_context_get_key(DavContext *context, char *name) { 113 DavKey* dav_context_get_key(DavContext *context, char *name) {
96 return ucx_map_cstr_get(context->keys, name); 114 if(name) {
115 return ucx_map_cstr_get(context->keys, name);
116 } else {
117 return NULL;
118 }
97 } 119 }
98 120
99 int dav_add_namespace(DavContext *context, char *prefix, char *name) { 121 int dav_add_namespace(DavContext *context, char *prefix, char *name) {
100 DavNamespace *namespace = malloc(sizeof(DavNamespace)); 122 DavNamespace *namespace = malloc(sizeof(DavNamespace));
101 if(!namespace) { 123 if(!namespace) {
133 } 155 }
134 *ns = pns; 156 *ns = pns;
135 *name = pname; 157 *name = pname;
136 } 158 }
137 159
138 DavSession* dav_session_new(DavContext *context, char *base_url) {
139 if(!base_url) {
140 return NULL;
141 }
142 sstr_t url = sstr(base_url);
143 if(url.length == 0) {
144 return NULL;
145 }
146 DavSession *sn = malloc(sizeof(DavSession));
147 sn->mp = ucx_mempool_new(1024);
148 sn->key = NULL;
149 sn->errorstr = NULL;
150 sn->error = DAV_OK;
151 sn->flags = 0;
152 if(url.ptr[url.length - 1] == '/') {
153 sstr_t url = sstrdup_a(sn->mp->allocator, sstr(base_url));
154 sn->base_url = url.ptr;
155 } else {
156 char *url_str = malloc(url.length + 2);
157 memcpy(url_str, base_url, url.length);
158 url_str[url.length] = '/';
159 url_str[url.length + 1] = '\0';
160 sn->base_url = url_str;
161 }
162 sn->context = context;
163 sn->handle = curl_easy_init();
164 //curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L);
165 //curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr);
166 curl_easy_setopt(sn->handle, CURLOPT_FOLLOWLOCATION, 1L);
167
168 // set proxy
169 DavProxy *proxy = sstrprefix(url, S("https")) ? context->https_proxy
170 : context->http_proxy;
171
172 if (proxy->url) {
173 curl_easy_setopt(sn->handle, CURLOPT_PROXY, proxy->url);
174 if (proxy->username) {
175 curl_easy_setopt(sn->handle, CURLOPT_PROXYUSERNAME,
176 proxy->username);
177 if (proxy->password) {
178 curl_easy_setopt(sn->handle, CURLOPT_PROXYPASSWORD,
179 proxy->password);
180 } else {
181 // TODO: prompt
182 }
183 }
184 if(proxy->no_proxy) {
185 curl_easy_setopt(sn->handle, CURLOPT_NOPROXY,
186 proxy->no_proxy);
187 }
188 }
189
190 // set url
191 curl_easy_setopt(sn->handle, CURLOPT_URL, base_url);
192
193 context->sessions = ucx_list_append(context->sessions, sn);
194
195 return sn;
196 }
197
198 DavSession* dav_session_new_auth(
199 DavContext *context,
200 char *base_url,
201 char *user,
202 char *password)
203 {
204 DavSession *sn = dav_session_new(context, base_url);
205 if(!sn) {
206 return NULL;
207 }
208 dav_session_set_auth(sn, user, password);
209 return sn;
210 }
211
212 void dav_session_set_auth(DavSession *sn, char *user, char *password) {
213 if(user && password) {
214 size_t ulen = strlen(user);
215 size_t plen = strlen(password);
216 size_t upwdlen = ulen + plen + 2;
217 char *upwdbuf = malloc(upwdlen);
218 snprintf(upwdbuf, upwdlen, "%s:%s\0", user, password);
219 curl_easy_setopt(sn->handle, CURLOPT_USERPWD, upwdbuf);
220 free(upwdbuf);
221 }
222 }
223
224 void session_set_error(DavSession *sn, CURLcode c, int status) {
225 if(status > 0) {
226 switch(status) {
227 default: sn->error = DAV_ERROR; break;
228 case 401: sn->error = DAV_UNAUTHORIZED; break;
229 case 403: sn->error = DAV_FORBIDDEN; break;
230 case 404: sn->error = DAV_NOT_FOUND; break;
231 case 405: sn->error = DAV_METHOD_NOT_ALLOWED; break;
232 case 409: sn->error = DAV_CONFLICT; break;
233 }
234 } else {
235 sn->error = DAV_ERROR;
236 }
237 if(c != CURLE_OK) {
238 sn->errorstr = curl_easy_strerror(c);
239 } else {
240 sn->errorstr = NULL;
241 }
242 }
243
244 void dav_session_destroy(DavSession *sn) {
245 // remove session from context
246 UcxList *sessions = sn->context->sessions;
247 ssize_t i = ucx_list_find(sessions, sn, ucx_ptrcmp, NULL);
248 if(i > 0) {
249 UcxList *elm = ucx_list_get(sessions, i);
250 if(elm) {
251 sn->context->sessions = ucx_list_remove(sessions, elm);
252 }
253 }
254
255 ucx_mempool_destroy(sn->mp);
256 curl_easy_cleanup(sn->handle);
257 free(sn);
258 }
259
260
261 void* dav_session_malloc(DavSession *sn, size_t size) {
262 return ucx_mempool_malloc(sn->mp, size);
263 }
264
265 void* dav_session_calloc(DavSession *sn, size_t nelm, size_t size) {
266 return ucx_mempool_calloc(sn->mp, nelm, size);
267 }
268
269 void* dav_session_realloc(DavSession *sn, void *ptr, size_t size) {
270 return ucx_mempool_realloc(sn->mp, ptr, size);
271 }
272
273 void dav_session_free(DavSession *sn, void *ptr) {
274 ucx_mempool_free(sn->mp, ptr);
275 }
276
277 160
278 DavResource* dav_get(DavSession *sn, char *path, char *properties) { 161 DavResource* dav_get(DavSession *sn, char *path, char *properties) {
279 CURL *handle = sn->handle; 162 CURL *handle = sn->handle;
280 util_set_url(sn, path); 163 char *href = dav_session_get_href(sn, path);
164 util_set_url(sn, href);
165 dav_session_free(sn, href);
281 166
282 UcxList *proplist = NULL; 167 UcxList *proplist = NULL;
283 if(properties) { 168 if(properties) {
284 proplist = parse_properties_string(sn->context, sstr(properties)); 169 proplist = parse_properties_string(sn->context, sstr(properties));
285 } 170 }
286 UcxBuffer *rqbuf = create_propfind_request(proplist); 171 UcxBuffer *rqbuf = create_propfind_request(sn, proplist);
287 UcxBuffer *rpbuf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND); 172 UcxBuffer *rpbuf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND);
288 173
289 //fwrite(rqbuf->space, 1, rqbuf->size, stdout); 174 //fwrite(rqbuf->space, 1, rqbuf->size, stdout);
290 //printf("\n"); 175 //printf("\n");
291 176
296 if(ret == CURLE_OK && status == 207) { 181 if(ret == CURLE_OK && status == 207) {
297 //printf("response\n%s\n", rpbuf->space); 182 //printf("response\n%s\n", rpbuf->space);
298 resource = parse_propfind_response(sn, NULL, rpbuf, NULL, 0); 183 resource = parse_propfind_response(sn, NULL, rpbuf, NULL, 0);
299 sn->error = DAV_OK; 184 sn->error = DAV_OK;
300 } else { 185 } else {
301 session_set_error(sn, ret, status); 186 dav_session_set_error(sn, ret, status);
302 } 187 }
188
189 ucx_buffer_free(rqbuf);
190 ucx_buffer_free(rpbuf);
191
303 return resource; 192 return resource;
304 } 193 }
305 194
306 DavResource* dav_propfind(DavSession *sn, DavResource *root, UcxBuffer *rqbuf, char *path, DavQOp *cond, size_t len) { 195 int dav_propfind(DavSession *sn, DavResource *root, UcxBuffer *rqbuf, DavQOp *cond, size_t len) {
196 // clean resource properties
197 DavResourceData *data = root->data;
198 if(data->properties->count > 0) {
199 UcxKey key;
200 void *value;
201 UcxMapIterator i = ucx_map_iterator(data->properties);
202 UCX_MAP_FOREACH(key, value, i) {
203 ucx_map_remove(data->properties, key);
204 }
205 }
206
307 CURL *handle = sn->handle; 207 CURL *handle = sn->handle;
308 util_set_url(sn, path); 208 util_set_url(sn, dav_resource_get_href(root));
309 209
310 UcxBuffer *rpbuf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND); 210 UcxBuffer *rpbuf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND);
311 DavResource *resource = root; 211 DavResource *resource = root;
312 CURLcode ret = do_propfind_request(handle, rqbuf, rpbuf); 212 CURLcode ret = do_propfind_request(handle, rqbuf, rpbuf);
313 int status = 0; 213 int status = 0;
214 int error = 0;
314 curl_easy_getinfo (handle, CURLINFO_RESPONSE_CODE, &status); 215 curl_easy_getinfo (handle, CURLINFO_RESPONSE_CODE, &status);
315 if(ret == CURLE_OK && status == 207) { 216 if(ret == CURLE_OK && status == 207) {
316 //printf("response\n%s\n", rpbuf->space); 217 //printf("response\n%s\n", rpbuf->space);
317 resource = parse_propfind_response(sn, resource, rpbuf, cond, len); 218 resource = parse_propfind_response(sn, resource, rpbuf, cond, len);
318 sn->error = DAV_OK; 219 sn->error = DAV_OK;
319 } else { 220 } else {
320 session_set_error(sn, ret, status); 221 dav_session_set_error(sn, ret, status);
321 resource = NULL; 222 error = 1;
322 } 223 }
323 ucx_buffer_free(rpbuf); 224 ucx_buffer_free(rpbuf);
324 return resource; 225 return error;
325 } 226 }
326 227
327 UcxList* propfind_stack_push(UcxList *stack, DavResource *children) { 228 UcxList* propfind_stack_push(UcxList *stack, DavResource *children) {
328 while(children) { 229 while(children) {
329 if(children->iscollection) { 230 if(children->iscollection) {
335 } 236 }
336 237
337 DavResource* dav_query_get(DavSession *sn, DavGetQuery *query) { 238 DavResource* dav_query_get(DavSession *sn, DavGetQuery *query) {
338 char *path; 239 char *path;
339 int depth = 0; 240 int depth = 0;
241 /*
340 if(parse_path_query(query->from, &path, &depth)) { 242 if(parse_path_query(query->from, &path, &depth)) {
341 sn->error = DAV_ERROR; 243 sn->error = DAV_ERROR;
342 return NULL; 244 return NULL;
343 } 245 }
246 */
247 path = sstrdup(query->from).ptr;
344 248
345 sstr_t ps = query->properties; 249 sstr_t ps = query->properties;
346 UcxBuffer *rqbuf; 250 UcxBuffer *rqbuf;
347 if(!sstrcmp(ps, S("*"))) { 251 if(!sstrcmp(ps, S("*"))) {
348 rqbuf = create_allprop_propfind_request(); 252 rqbuf = create_allprop_propfind_request();
349 } else if(!sstrcmp(ps, S("-"))) { 253 } else if(!sstrcmp(ps, S("-"))) {
350 rqbuf = create_propfind_request(NULL); 254 rqbuf = create_propfind_request(sn, NULL);
351 } else { 255 } else {
352 UcxList *proplist = parse_properties_string(sn->context, ps); 256 UcxList *proplist = parse_properties_string(sn->context, ps);
353 rqbuf = create_propfind_request(proplist); 257 rqbuf = create_propfind_request(sn, proplist);
354 } 258 }
355 259
356 //fwrite(rqbuf->space, 1, rqbuf->size, stdout); 260 //fwrite(rqbuf->space, 1, rqbuf->size, stdout);
357 //printf("\n"); 261 //printf("\n");
358 262
359 DavResource *resource = dav_propfind(sn, NULL, rqbuf, path, query->condition, query->condlen); 263 DavResource *resource = dav_resource_new(sn, path);
360 free(path); 264 free(path);
265 if(dav_propfind(sn, resource, rqbuf, query->condition, query->condlen)) {
266 dav_resource_free(resource);
267 resource = NULL;
268 }
269 ucx_buffer_free(rqbuf);
270
361 int error = 0; 271 int error = 0;
362 if(resource && depth == -1) { 272 if(resource && depth == -1) {
363 UcxList *stack = NULL; // stack with DavResource* elements 273 UcxList *stack = NULL; // stack with DavResource* elements
364 stack = propfind_stack_push(stack, resource->children); 274 stack = propfind_stack_push(stack, resource->children);
365 while(stack) { 275 while(stack) {
366 DavResource *sr = stack->data; // get first element from the stack 276 DavResource *sr = stack->data; // get first element from the stack
367 stack = ucx_list_remove(stack, stack); // remove first element 277 stack = ucx_list_remove(stack, stack); // remove first element
368 // do propfind request for sr 278 // do propfind request for sr
369 sr = dav_propfind(sn, sr, rqbuf, sr->path, query->condition, query->condlen); 279 if(dav_propfind(sn, sr, rqbuf, query->condition, query->condlen)) {
370 if(!sr) {
371 error = 1; 280 error = 1;
372 printf("subrequest failed\n"); 281 printf("subrequest failed\n");
373 break; 282 break;
374 } 283 }
375 stack = propfind_stack_push(stack, sr->children); // add children 284 stack = propfind_stack_push(stack, sr->children); // add children
418 case DAV_QUERY_GET: { 327 case DAV_QUERY_GET: {
419 res = dav_query_get(sn, q.command_data); 328 res = dav_query_get(sn, q.command_data);
420 free_get_query(q.command_data); 329 free_get_query(q.command_data);
421 break; 330 break;
422 } 331 }
332 case DAV_QUERY_ERROR: {
333 // TODO
334 break;
335 }
423 } 336 }
424 return res; 337 return res;
425 } 338 }
426 339
427 340

mercurial