Fri, 23 Oct 2015 22:15:12 +0200
fixed large file support
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ucx/buffer.h> #include <ucx/utils.h> #include "utils.h" #include "session.h" #include "resource.h" #include "methods.h" DavSession* dav_session_new(DavContext *context, char *base_url) { if(!base_url) { return NULL; } sstr_t url = sstr(base_url); if(url.length == 0) { return NULL; } DavSession *sn = malloc(sizeof(DavSession)); sn->mp = ucx_mempool_new(DAV_SESSION_MEMPOOL_SIZE); sn->pathcache = ucx_map_new_a(sn->mp->allocator, DAV_PATH_CACHE_SIZE); sn->key = NULL; sn->errorstr = NULL; sn->error = DAV_OK; sn->flags = 0; if(url.ptr[url.length - 1] == '/') { sstr_t url = sstrdup_a(sn->mp->allocator, sstr(base_url)); sn->base_url = url.ptr; } else { char *url_str = malloc(url.length + 2); memcpy(url_str, base_url, url.length); url_str[url.length] = '/'; url_str[url.length + 1] = '\0'; sn->base_url = url_str; } sn->handle = curl_easy_init(); curl_easy_setopt(sn->handle, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(sn->handle, CURLOPT_SSL_VERIFYPEER, 0); // TODO: remove // set proxy DavProxy *proxy = sstrprefix(url, S("https")) ? context->https_proxy : context->http_proxy; if (proxy->url) { curl_easy_setopt(sn->handle, CURLOPT_PROXY, proxy->url); if (proxy->username) { curl_easy_setopt(sn->handle, CURLOPT_PROXYUSERNAME, proxy->username); if (proxy->password) { curl_easy_setopt(sn->handle, CURLOPT_PROXYPASSWORD, proxy->password); } else { // TODO: prompt } } if(proxy->no_proxy) { curl_easy_setopt(sn->handle, CURLOPT_NOPROXY, proxy->no_proxy); } } // set url curl_easy_setopt(sn->handle, CURLOPT_URL, base_url); // add to context context->sessions = ucx_list_append(context->sessions, sn); sn->context = context; return sn; } DavSession* dav_session_new_auth( DavContext *context, char *base_url, char *user, char *password) { DavSession *sn = dav_session_new(context, base_url); if(!sn) { return NULL; } dav_session_set_auth(sn, user, password); return sn; } void dav_session_set_auth(DavSession *sn, char *user, char *password) { if(user && password) { size_t ulen = strlen(user); size_t plen = strlen(password); size_t upwdlen = ulen + plen + 2; char *upwdbuf = malloc(upwdlen); snprintf(upwdbuf, upwdlen, "%s:%s", user, password); curl_easy_setopt(sn->handle, CURLOPT_USERPWD, upwdbuf); free(upwdbuf); } } void dav_session_enable_encryption(DavSession *sn, DavKey *key, int flags) { sn->key = key; // TODO: review sanity if(flags != 0) { sn->flags |= flags; } else { sn->flags |= DAV_SESSION_ENCRYPT_CONTENT; } } void dav_session_set_error(DavSession *sn, CURLcode c, int status) { if(status > 0) { switch(status) { default: { switch(c) { default: sn->error = DAV_ERROR; } break; } case 401: sn->error = DAV_UNAUTHORIZED; break; case 403: sn->error = DAV_FORBIDDEN; break; case 404: sn->error = DAV_NOT_FOUND; break; case 405: sn->error = DAV_METHOD_NOT_ALLOWED; break; case 409: sn->error = DAV_CONFLICT; break; } } else { switch(c) { case CURLE_UNSUPPORTED_PROTOCOL: sn->error = DAV_UNSUPPORTED_PROTOCOL; break; case CURLE_COULDNT_RESOLVE_PROXY: sn->error = DAV_COULDNT_RESOLVE_PROXY; break; case CURLE_COULDNT_RESOLVE_HOST: sn->error = DAV_COULDNT_RESOLVE_HOST; break; case CURLE_COULDNT_CONNECT: sn->error = DAV_COULDNT_CONNECT; break; case CURLE_OPERATION_TIMEDOUT: sn->error = DAV_TIMEOUT; break; case CURLE_SSL_CONNECT_ERROR: case CURLE_PEER_FAILED_VERIFICATION: case CURLE_SSL_ENGINE_NOTFOUND: case CURLE_SSL_ENGINE_SETFAILED: case CURLE_SSL_CERTPROBLEM: case CURLE_SSL_CIPHER: case CURLE_SSL_CACERT: case CURLE_SSL_CACERT_BADFILE: case CURLE_SSL_SHUTDOWN_FAILED: case CURLE_SSL_CRL_BADFILE: case CURLE_SSL_ISSUER_ERROR: sn->error = DAV_SSL_ERROR; break; default: sn->error = DAV_ERROR; break; } } if(c != CURLE_OK) { sn->errorstr = curl_easy_strerror(c); } else { sn->errorstr = NULL; } } void dav_session_destroy(DavSession *sn) { // remove session from context UcxList *sessions = sn->context->sessions; ssize_t i = ucx_list_find(sessions, sn, ucx_ptrcmp, NULL); if(i >= 0) { UcxList *elm = ucx_list_get(sessions, i); if(elm) { sn->context->sessions = ucx_list_remove(sessions, elm); } } ucx_mempool_destroy(sn->mp); curl_easy_cleanup(sn->handle); free(sn); } void* dav_session_malloc(DavSession *sn, size_t size) { return ucx_mempool_malloc(sn->mp, size); } void* dav_session_calloc(DavSession *sn, size_t nelm, size_t size) { return ucx_mempool_calloc(sn->mp, nelm, size); } void* dav_session_realloc(DavSession *sn, void *ptr, size_t size) { return ucx_mempool_realloc(sn->mp, ptr, size); } void dav_session_free(DavSession *sn, void *ptr) { ucx_mempool_free(sn->mp, ptr); } char* dav_session_strdup(DavSession *sn, char *str) { return sstrdup_a(sn->mp->allocator, sstr(str)).ptr; } char* dav_session_create_plain_href(DavSession *sn, char *path) { if(!DAV_ENCRYPT_NAME(sn)) { // non encrypted file names char *url = util_path_to_url(sn, path); char *href = dav_session_strdup(sn, util_url_path(url)); free(url); return href; } else { return NULL; } } char* dav_session_get_href(DavSession *sn, char *path) { if(DAV_ENCRYPT_NAME(sn)) { sstr_t p = sstr(path); UcxBuffer *href = ucx_buffer_new(NULL, 256, UCX_BUFFER_AUTOEXTEND); UcxBuffer *pbuf = ucx_buffer_new(NULL, 256, UCX_BUFFER_AUTOEXTEND); int start = 0; int begin = 0; // check path cache char *cp = strdup(path); //printf("cp: %s\n", cp); while(strlen(cp) > 1) { char *cached = ucx_map_cstr_get(sn->pathcache, cp); if(cached) { start = strlen(cp); begin = start; ucx_buffer_puts(href, cached); break; } else { // check, if the parent path is cached char *f = cp; cp = util_parent_path(cp); free(f); } } free(cp); if(href->pos == 0) { // if there are no cached elements we have to add the base url path // to the href buffer ucx_buffer_puts(href, util_url_path(sn->base_url)); } // create resource for name lookup sstr_t rp = sstrdup(sstrn(path, start)); DavResource *root = dav_resource_new(sn, rp.ptr); free(rp.ptr); resource_set_href(root, sstrn(href->space, href->pos)); // create request buffer for propfind requests UcxBuffer *rqbuf = create_basic_propfind_request(); sstr_t remaining = sstrsubs(p, start); ssize_t nelm = 0; sstr_t *elms = sstrsplit(remaining, S("/"), &nelm); DavResource *res = root; ucx_buffer_puts(pbuf, res->path); // iterate over all remaining path elements for(int i=0;i<nelm;i++) { sstr_t elm = elms[i]; if(elm.length > 0) { //printf("elm: %.*s\n", elm.length, elm.ptr); DavResource *child = dav_find_child(sn, res, rqbuf, elm.ptr); // if necessary add a path separator if(pbuf->space[pbuf->pos-1] != '/') { if(href->space[href->pos-1] != '/') { ucx_buffer_putc(href, '/'); } ucx_buffer_putc(pbuf, '/'); } // add last path/href to the cache sstr_t pp = sstrn(pbuf->space, pbuf->size); sstr_t hh = sstrn(href->space, href->size); dav_session_cache_path(sn, pp, hh); ucx_buffer_write(elm.ptr, 1, elm.length, pbuf); if(child) { ucx_buffer_puts(href, util_resource_name(child->href)); res = child; } else { //printf("random\n"); char *random_name = util_random_str(); ucx_buffer_puts(href, random_name); free(random_name); } } // cleanup free(elm.ptr); } free(elms); // if necessary add a path separator if(p.ptr[p.length-1] == '/') { if(href->space[href->pos-1] != '/') { ucx_buffer_putc(href, '/'); } ucx_buffer_putc(pbuf, '/'); } // add the final path to the cache sstr_t pp = sstrn(pbuf->space, pbuf->size); sstr_t hh = sstrn(href->space, href->size); dav_session_cache_path(sn, pp, hh); sstr_t href_str = sstrdup_a( sn->mp->allocator, sstrn(href->space, href->size)); // cleanup dav_resource_free_all(root); ucx_buffer_free(rqbuf); ucx_buffer_free(pbuf); ucx_buffer_free(href); return href_str.ptr; } else { return dav_session_create_plain_href(sn, path); } } DavResource* dav_find_child(DavSession *sn, DavResource *res, UcxBuffer *rqbuf, char *name) { if(res && !dav_propfind(sn, res, rqbuf)) { DavResource *child = res->children; while(child) { if(!strcmp(child->name, name)) { return child; } child = child->next; } } return NULL; } void dav_session_cache_path(DavSession *sn, sstr_t path, sstr_t href) { char *elm = ucx_map_sstr_get(sn->pathcache, path); if(!elm) { href = sstrdup_a(sn->mp->allocator, href); ucx_map_sstr_put(sn->pathcache, path, href.ptr); } }