libidav/session.c

changeset 43
03076907b58a
child 68
f6d3db6113d3
equal deleted inserted replaced
42:6518b035a9df 43:03076907b58a
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2014 Olaf Wintermann. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <ucx/buffer.h>
34 #include <ucx/utils.h>
35
36 #include "utils.h"
37 #include "session.h"
38 #include "resource.h"
39 #include "methods.h"
40
41 DavSession* dav_session_new(DavContext *context, char *base_url) {
42 if(!base_url) {
43 return NULL;
44 }
45 sstr_t url = sstr(base_url);
46 if(url.length == 0) {
47 return NULL;
48 }
49 DavSession *sn = malloc(sizeof(DavSession));
50 sn->mp = ucx_mempool_new(DAV_SESSION_MEMPOOL_SIZE);
51 sn->pathcache = ucx_map_new_a(sn->mp->allocator, DAV_PATH_CACHE_SIZE);
52 sn->key = NULL;
53 sn->errorstr = NULL;
54 sn->error = DAV_OK;
55 sn->flags = 0;
56 if(url.ptr[url.length - 1] == '/') {
57 sstr_t url = sstrdup_a(sn->mp->allocator, sstr(base_url));
58 sn->base_url = url.ptr;
59 } else {
60 char *url_str = malloc(url.length + 2);
61 memcpy(url_str, base_url, url.length);
62 url_str[url.length] = '/';
63 url_str[url.length + 1] = '\0';
64 sn->base_url = url_str;
65 }
66 sn->context = context;
67 sn->handle = curl_easy_init();
68 //curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L);
69 //curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr);
70 curl_easy_setopt(sn->handle, CURLOPT_FOLLOWLOCATION, 1L);
71
72 // set proxy
73 DavProxy *proxy = sstrprefix(url, S("https")) ? context->https_proxy
74 : context->http_proxy;
75
76 if (proxy->url) {
77 curl_easy_setopt(sn->handle, CURLOPT_PROXY, proxy->url);
78 if (proxy->username) {
79 curl_easy_setopt(sn->handle, CURLOPT_PROXYUSERNAME,
80 proxy->username);
81 if (proxy->password) {
82 curl_easy_setopt(sn->handle, CURLOPT_PROXYPASSWORD,
83 proxy->password);
84 } else {
85 // TODO: prompt
86 }
87 }
88 if(proxy->no_proxy) {
89 curl_easy_setopt(sn->handle, CURLOPT_NOPROXY,
90 proxy->no_proxy);
91 }
92 }
93
94 // set url
95 curl_easy_setopt(sn->handle, CURLOPT_URL, base_url);
96
97 context->sessions = ucx_list_append(context->sessions, sn);
98
99 return sn;
100 }
101
102 DavSession* dav_session_new_auth(
103 DavContext *context,
104 char *base_url,
105 char *user,
106 char *password)
107 {
108 DavSession *sn = dav_session_new(context, base_url);
109 if(!sn) {
110 return NULL;
111 }
112 dav_session_set_auth(sn, user, password);
113 return sn;
114 }
115
116 void dav_session_set_auth(DavSession *sn, char *user, char *password) {
117 if(user && password) {
118 size_t ulen = strlen(user);
119 size_t plen = strlen(password);
120 size_t upwdlen = ulen + plen + 2;
121 char *upwdbuf = malloc(upwdlen);
122 snprintf(upwdbuf, upwdlen, "%s:%s\0", user, password);
123 curl_easy_setopt(sn->handle, CURLOPT_USERPWD, upwdbuf);
124 free(upwdbuf);
125 }
126 }
127
128 void dav_session_set_flags(DavSession *sn, uint32_t flags) {
129 sn->flags = flags;
130 }
131
132 uint32_t dav_session_get_flags(DavSession *sn) {
133 return sn->flags;
134 }
135
136 void dav_session_enable_encryption(DavSession *sn, DavKey *key, int flags) {
137 sn->key = key;
138 if(flags != 0) {
139 sn->flags |= flags;
140 } else {
141 sn->flags |= DAV_SESSION_ENCRYPT_CONTENT;
142 }
143 }
144
145 void dav_session_set_error(DavSession *sn, CURLcode c, int status) {
146 if(status > 0) {
147 switch(status) {
148 default: sn->error = DAV_ERROR; break;
149 case 401: sn->error = DAV_UNAUTHORIZED; break;
150 case 403: sn->error = DAV_FORBIDDEN; break;
151 case 404: sn->error = DAV_NOT_FOUND; break;
152 case 405: sn->error = DAV_METHOD_NOT_ALLOWED; break;
153 case 409: sn->error = DAV_CONFLICT; break;
154 }
155 } else {
156 sn->error = DAV_ERROR;
157 }
158 if(c != CURLE_OK) {
159 sn->errorstr = curl_easy_strerror(c);
160 } else {
161 sn->errorstr = NULL;
162 }
163 }
164
165 void dav_session_destroy(DavSession *sn) {
166 // remove session from context
167 UcxList *sessions = sn->context->sessions;
168 ssize_t i = ucx_list_find(sessions, sn, ucx_ptrcmp, NULL);
169 if(i > 0) {
170 UcxList *elm = ucx_list_get(sessions, i);
171 if(elm) {
172 sn->context->sessions = ucx_list_remove(sessions, elm);
173 }
174 }
175
176 ucx_mempool_destroy(sn->mp);
177 curl_easy_cleanup(sn->handle);
178 free(sn);
179 }
180
181
182 void* dav_session_malloc(DavSession *sn, size_t size) {
183 return ucx_mempool_malloc(sn->mp, size);
184 }
185
186 void* dav_session_calloc(DavSession *sn, size_t nelm, size_t size) {
187 return ucx_mempool_calloc(sn->mp, nelm, size);
188 }
189
190 void* dav_session_realloc(DavSession *sn, void *ptr, size_t size) {
191 return ucx_mempool_realloc(sn->mp, ptr, size);
192 }
193
194 void dav_session_free(DavSession *sn, void *ptr) {
195 ucx_mempool_free(sn->mp, ptr);
196 }
197
198 char* dav_session_strdup(DavSession *sn, char *str) {
199 return sstrdup_a(sn->mp->allocator, sstr(str)).ptr;
200 }
201
202
203 char* dav_session_create_plain_href(DavSession *sn, char *path) {
204 if(!DAV_ENCRYPT_NAME(sn)) {
205 // non encrypted file names
206 char *url = util_path_to_url(sn, path);
207 char *href = dav_session_strdup(sn, util_url_path(url));
208 free(url);
209 return href;
210 } else {
211 return NULL;
212 }
213 }
214
215 char* dav_session_get_href(DavSession *sn, char *path) {
216 if(DAV_ENCRYPT_NAME(sn)) {
217 sstr_t p = sstr(path);
218 UcxBuffer *href = ucx_buffer_new(NULL, 256, UCX_BUFFER_AUTOEXTEND);
219 UcxBuffer *pbuf = ucx_buffer_new(NULL, 256, UCX_BUFFER_AUTOEXTEND);
220 int start = 0;
221 int begin = 0;
222
223 // check path cache
224 char *cp = strdup(path);
225 //printf("cp: %s\n", cp);
226 while(strlen(cp) > 1) {
227 char *cached = ucx_map_cstr_get(sn->pathcache, cp);
228 if(cached) {
229 start = strlen(cp);
230 begin = start;
231 ucx_buffer_puts(href, cached);
232 break;
233 } else {
234 // check, if the parent path is cached
235 char *f = cp;
236 cp = util_parent_path(cp);
237 free(f);
238 }
239 }
240 free(cp);
241 if(href->pos == 0) {
242 // if there are no cached elements we have to add the base url path
243 // to the href buffer
244 ucx_buffer_puts(href, util_url_path(sn->base_url));
245 }
246
247 // create resource for name lookup
248 sstr_t rp = sstrdup(sstrn(path, start));
249 DavResource *root = dav_resource_new(sn, rp.ptr);
250 resource_set_href(root, sstrn(href->space, href->pos));
251
252 // create request buffer for propfind requests
253 UcxBuffer *rqbuf = create_basic_propfind_request();
254
255 sstr_t remaining = sstrsubs(p, start);
256 size_t nelm = 0;
257 sstr_t *elms = sstrsplit(remaining, S("/"), &nelm);
258 DavResource *res = root;
259 ucx_buffer_puts(pbuf, res->path);
260 // iterate over all remaining path elements
261 for(int i=0;i<nelm;i++) {
262 sstr_t elm = elms[i];
263 if(elm.length > 0) {
264 //printf("elm: %.*s\n", elm.length, elm.ptr);
265 DavResource *child = dav_find_child(sn, res, rqbuf, elm.ptr);
266
267 // if necessary add a path separator
268 if(pbuf->space[pbuf->pos-1] != '/') {
269 if(href->space[href->pos-1] != '/') {
270 ucx_buffer_putc(href, '/');
271 }
272 ucx_buffer_putc(pbuf, '/');
273 }
274 // add last path/href to the cache
275 sstr_t pp = sstrn(pbuf->space, pbuf->size);
276 sstr_t hh = sstrn(href->space, href->size);
277 dav_session_cache_path(sn, pp, hh);
278
279 ucx_buffer_write(elm.ptr, 1, elm.length, pbuf);
280 if(child) {
281 ucx_buffer_puts(href, util_resource_name(child->href));
282 res = child;
283 } else {
284 //printf("random\n");
285 char *random_name = util_random_str();
286 ucx_buffer_puts(href, random_name);
287 free(random_name);
288 }
289
290 }
291 }
292
293 // if necessary add a path separator
294 if(p.ptr[p.length-1] == '/') {
295 if(href->space[href->pos-1] != '/') {
296 ucx_buffer_putc(href, '/');
297 }
298 ucx_buffer_putc(pbuf, '/');
299 }
300 // add the final path to the cache
301 sstr_t pp = sstrn(pbuf->space, pbuf->size);
302 sstr_t hh = sstrn(href->space, href->size);
303 dav_session_cache_path(sn, pp, hh);
304
305 sstr_t href_str = sstrdup_a(
306 sn->mp->allocator,
307 sstrn(href->space,
308 href->size));
309
310 // cleanup
311 dav_resource_free_all(root);
312 ucx_buffer_free(pbuf);
313 ucx_buffer_free(href);
314
315 return href_str.ptr;
316 } else {
317 return dav_session_create_plain_href(sn, path);
318 }
319 }
320
321 DavResource* dav_find_child(DavSession *sn, DavResource *res, UcxBuffer *rqbuf, char *name) {
322 if(res && !dav_propfind(sn, res, rqbuf, NULL, 0)) {
323 DavResource *child = res->children;
324 while(child) {
325 if(!strcmp(child->name, name)) {
326 return child;
327 }
328 child = child->next;
329 }
330 }
331 return NULL;
332 }
333
334 void dav_session_cache_path(DavSession *sn, sstr_t path, sstr_t href) {
335 char *elm = ucx_map_sstr_get(sn->pathcache, path);
336 if(!elm) {
337 href = sstrdup_a(sn->mp->allocator, href);
338 ucx_map_sstr_put(sn->pathcache, path, href.ptr);
339 }
340 }

mercurial