Mon, 26 Aug 2013 14:44:21 +0200
removed debug code
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2013 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 "utils.h" #include "methods.h" #include "davql.h" #define xstreq(a,b) xmlStrEqual(BAD_CAST a, BAD_CAST b) /* ----------------------------- PROPFIND ----------------------------- */ CURLcode do_propfind_request( CURL *handle, UcxBuffer *request, UcxBuffer *response) { curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "PROPFIND"); struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "Content-Type: text/xml"); headers = curl_slist_append(headers, "Depth: 1"); curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(handle, CURLOPT_UPLOAD, 1); curl_easy_setopt(handle, CURLOPT_READFUNCTION, ucx_buffer_read); curl_easy_setopt(handle, CURLOPT_READDATA, request); curl_easy_setopt(handle, CURLOPT_INFILESIZE, request->size); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, ucx_buffer_write); curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); ucx_buffer_seek(request, 0, SEEK_SET); return curl_easy_perform(handle); } UcxBuffer* create_allprop_propfind_request() { UcxBuffer *buf = ucx_buffer_new(NULL, 512, 0); sstr_t s; s = S("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S("<D:propfind xmlns:D=\"DAV:\">\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S("<D:allprop/></D:propfind>\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); return buf; } UcxBuffer* create_propfind_request(UcxList *properties) { UcxBuffer *buf = ucx_buffer_new(NULL, 512, 0); sstr_t s; UcxMap *namespaces = ucx_map_new(8); UCX_FOREACH(elm, properties) { DavProperty *p = elm->data; if(strcmp(p->ns->name, "DAV:")) { ucx_map_cstr_put(namespaces, p->ns->prefix, p->ns); } } s = S("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); // write root element and namespaces s = S("<D:propfind xmlns:D=\"DAV:\""); ucx_buffer_write(s.ptr, 1, s.length, buf); UcxMapIterator mapi = ucx_map_iterator(namespaces); UcxKey key; DavNamespace *ns; UCX_MAP_FOREACH(key, ns, mapi) { s = S(" xmlns:"); ucx_buffer_write(s.ptr, 1, s.length, buf); s = sstr(ns->prefix); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S("=\""); ucx_buffer_write(s.ptr, 1, s.length, buf); s = sstr(ns->name); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S("\""); ucx_buffer_write(s.ptr, 1, s.length, buf); } s = S(">\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); // default properties s = S("<D:prop>\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S("<D:creationdate />\n<D:getlastmodified />\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S("<D:getcontentlength />\n<D:getcontenttype />\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S("<D:resourcetype />\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); // extra properties UCX_FOREACH(elm, properties) { DavProperty *prop = elm->data; s = S("<"); ucx_buffer_write(s.ptr, 1, s.length, buf); s = sstr(prop->ns->prefix); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S(":"); ucx_buffer_write(s.ptr, 1, s.length, buf); s = sstr(prop->name); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S(" />\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); } // end s = S("</D:prop>\n</D:propfind>\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); return buf; } DavResource* parse_propfind_response(DavSession *sn, DavResource *root, UcxBuffer *response, DavQOp *cond, size_t len) { char *url = NULL; curl_easy_getinfo(sn->handle, CURLINFO_EFFECTIVE_URL, &url); if(!root) { root = dav_resource_new_href(sn, util_url_path(url)); } xmlDoc *doc = xmlReadMemory(response->space, response->size, url, NULL, 0); if(!doc) { // TODO: free stuff sn->error = DAV_ERROR; return NULL; } xmlNode *xml_root = xmlDocGetRootElement(doc); xmlNode *node = xml_root->children; while(node) { if(node->type == XML_ELEMENT_NODE) { if(xstreq(node->name, "response")) { parse_response_tag(root, node, cond, len); } } node = node->next; } return root; } int parse_response_tag(DavResource *resource, xmlNode *node, DavQOp *cond, size_t clen) { DavResource *res = resource; node = node->children; while(node) { if(node->type == XML_ELEMENT_NODE) { if(xstreq(node->name, "href")) { xmlNode *href_node = node->children; if(href_node->type != XML_TEXT_NODE) { // error resource->session->error = DAV_ERROR; return 1; } char *href = (char*)href_node->content; href = util_url_path(href); if(xstreq(resource->href, href)) { res = resource; } else { res = dav_resource_new_href(resource->session, href); res->parent = resource; } } else if(xstreq(node->name, "propstat")) { xmlNode *n = node->children; xmlNode *prop_node = NULL; int ok = 0; // get the status code while(n) { if(n->type == XML_ELEMENT_NODE) { if(xstreq(n->name, "prop")) { prop_node = n; } else if(xstreq(n->name, "status")) { xmlNode *status_node = n->children; if(status_node->type != XML_TEXT_NODE) { resource->session->error = DAV_ERROR; return 1; } sstr_t status_str = sstr((char*)status_node->content); if(status_str.length < 13) { resource->session->error = DAV_ERROR; return 1; } status_str = sstrsubsl(status_str, 9, 3); if(!sstrcmp(status_str, S("200"))) { ok = 1; } } } n = n->next; } // if status is ok, get all properties if(ok) { n = prop_node->children; while(n) { if(n->type == XML_ELEMENT_NODE) { if(xstreq(n->name, "resourcetype")) { xmlNode *rsnode = n->children; if(rsnode && rsnode->type == XML_ELEMENT_NODE) { // TODO: this is a ugly lazy hack resource_add_property(res, "DAV:", (char*)n->name, "collection"); res->iscollection = 1; } } else { xmlNode *content = n->children; if(content) { resource_add_property( res, (char*)n->ns->href, (char*)n->name, (char*)content->content); } } } n = n->next; } } } } node = node->next; } set_davprops(res); if(res != resource) { if(clen > 0) { if(!condition_eval(res, cond, clen)) { // skip resource return 0; } } resource_add_child(resource, res); } return 0; } void set_davprops(DavResource *res) { char *cl = dav_get_property_ns(res, "DAV:", "getcontentlength"); char *ct = dav_get_property_ns(res, "DAV:", "getcontenttype"); char *cd = dav_get_property_ns(res, "DAV:", "creationdate"); char *lm = dav_get_property_ns(res, "DAV:", "getlastmodified"); res->contenttype = ct; if(cl) { char *end = NULL; res->contentlength = strtoull(cl, &end, 0); } res->creationdate = util_parse_creationdate(cd); res->lastmodified = util_parse_lastmodified(lm); } /* ----------------------------- PROPPATCH ----------------------------- */ CURLcode do_proppatch_request( CURL *handle, UcxBuffer *request, UcxBuffer *response) { curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "PROPPATCH"); struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "Content-Type: text/xml"); curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(handle, CURLOPT_UPLOAD, 1); curl_easy_setopt(handle, CURLOPT_READFUNCTION, ucx_buffer_read); curl_easy_setopt(handle, CURLOPT_READDATA, request); curl_easy_setopt(handle, CURLOPT_INFILESIZE, request->size); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, ucx_buffer_write); curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); ucx_buffer_seek(request, 0, SEEK_SET); return curl_easy_perform(handle); } UcxBuffer* create_proppatch_request(DavResourceData *data) { UcxBuffer *buf = ucx_buffer_new(NULL, 512, 0); sstr_t s; UcxMap *namespaces = ucx_map_new(8); char prefix[8]; int pfxnum = 0; UCX_FOREACH(elm, data->set) { DavProperty *p = elm->data; if(strcmp(p->ns->name, "DAV:")) { snprintf(prefix, 8, "x%d\0", pfxnum++); ucx_map_cstr_put(namespaces, p->ns->name, prefix); } } UCX_FOREACH(elm, data->remove) { DavProperty *p = elm->data; if(strcmp(p->ns->name, "DAV:")) { snprintf(prefix, 8, "x%d\0", pfxnum++); ucx_map_cstr_put(namespaces, p->ns->name, prefix); } } s = S("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); // write root element and namespaces s = S("<D:propertyupdate xmlns:D=\"DAV:\""); ucx_buffer_write(s.ptr, 1, s.length, buf); UcxMapIterator mapi = ucx_map_iterator(namespaces); UcxKey key; char *pfxval; UCX_MAP_FOREACH(key, pfxval, mapi) { s = S(" xmlns:"); ucx_buffer_write(s.ptr, 1, s.length, buf); s = sstr(pfxval); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S("=\""); ucx_buffer_write(s.ptr, 1, s.length, buf); s = sstrn(key.data, key.len); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S("\""); ucx_buffer_write(s.ptr, 1, s.length, buf); } s = S(">\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); if(data->set) { s = S("<D:set>\n<D:prop>\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); UCX_FOREACH(elm, data->set) { DavProperty *property = elm->data; char *prefix = ucx_map_cstr_get(namespaces, property->ns->name); s = S("<"); ucx_buffer_write(s.ptr, 1, s.length, buf); s = sstr(prefix); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S(":"); ucx_buffer_write(s.ptr, 1, s.length, buf); s = sstr(property->name); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S(">"); ucx_buffer_write(s.ptr, 1, s.length, buf); s = sstr(property->value); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S("</"); ucx_buffer_write(s.ptr, 1, s.length, buf); s = sstr(prefix); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S(":"); ucx_buffer_write(s.ptr, 1, s.length, buf); s = sstr(property->name); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S(">\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); } s = S("</D:prop>\n</D:set>\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); } if(data->remove) { s = S("<D:set>\n<D:prop>\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); UCX_FOREACH(elm, data->set) { DavProperty *property = elm->data; char *prefix = ucx_map_cstr_get(namespaces, property->ns->name); s = S("<"); ucx_buffer_write(s.ptr, 1, s.length, buf); s = sstr(prefix); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S(":"); ucx_buffer_write(s.ptr, 1, s.length, buf); s = sstr(property->name); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S(">"); ucx_buffer_write(s.ptr, 1, s.length, buf); s = sstr(property->value); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S("</"); ucx_buffer_write(s.ptr, 1, s.length, buf); s = sstr(prefix); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S(":"); ucx_buffer_write(s.ptr, 1, s.length, buf); s = sstr(property->name); ucx_buffer_write(s.ptr, 1, s.length, buf); s = S(">\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); } s = S("</D:prop>\n</D:set>\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); } s = S("</D:propertyupdate>\n"); ucx_buffer_write(s.ptr, 1, s.length, buf); return buf; } /* ----------------------------- PUT ----------------------------- */ static size_t dummy_write(void *buf, size_t s, size_t n, void *data) { fwrite(buf, s, n, stdout); return s*n; } CURLcode do_put_request(CURL *handle, void *data, dav_read_func read_func, size_t length) { curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, NULL); curl_easy_setopt(handle, CURLOPT_PUT, 1L); curl_easy_setopt(handle, CURLOPT_UPLOAD, 1L); curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); UcxBuffer *buf = NULL; if(!read_func) { buf = ucx_buffer_new(data, length, 0); buf->size = length; data = buf; read_func = (dav_read_func)ucx_buffer_read; curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)length); } else if(length == 0) { struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "Transfer-Encoding: chunked"); curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)1); curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); } else { curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)length); } curl_easy_setopt(handle, CURLOPT_READFUNCTION, read_func); curl_easy_setopt(handle, CURLOPT_READDATA, data); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, dummy_write); curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL); CURLcode ret = curl_easy_perform(handle); if(buf) { ucx_buffer_free(buf); } return ret; } CURLcode do_delete_request(CURL *handle, UcxBuffer *response) { curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "DELETE"); curl_easy_setopt(handle, CURLOPT_PUT, 0L); curl_easy_setopt(handle, CURLOPT_UPLOAD, 0L); curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, ucx_buffer_write); curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); CURLcode ret = curl_easy_perform(handle); return ret; } CURLcode do_mkcol_request(CURL *handle) { curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "MKCOL"); curl_easy_setopt(handle, CURLOPT_PUT, 0L); curl_easy_setopt(handle, CURLOPT_UPLOAD, 0L); curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, dummy_write); curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL); CURLcode ret = curl_easy_perform(handle); return ret; } CURLcode do_head_request(CURL *handle) { curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "HEAD"); curl_easy_setopt(handle, CURLOPT_PUT, 0L); curl_easy_setopt(handle, CURLOPT_UPLOAD, 0L); curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(handle, CURLOPT_NOBODY, 1L); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, dummy_write); curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL); CURLcode ret = curl_easy_perform(handle); curl_easy_setopt(handle, CURLOPT_NOBODY, 0L); return ret; }