added depth header workaround for Microsoft IIS (tested with sharepoint)

Thu, 15 Oct 2015 15:36:26 +0200

author
Mike Becker <universe@uap-core.de>
date
Thu, 15 Oct 2015 15:36:26 +0200
changeset 170
cf054cded046
parent 169
08adb4f87160
child 171
254326cbc1bc

added depth header workaround for Microsoft IIS (tested with sharepoint)

libidav/methods.c file | annotate | diff | comparison | revisions
libidav/utils.c file | annotate | diff | comparison | revisions
libidav/utils.h file | annotate | diff | comparison | revisions
--- a/libidav/methods.c	Thu Oct 15 15:01:50 2015 +0200
+++ b/libidav/methods.c	Thu Oct 15 15:36:26 2015 +0200
@@ -54,6 +54,9 @@
     curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 0L);
     const int maxredirect = 16;
     
+    // always try to get information about possible children
+    int depth = 1;
+    
     struct curl_slist *headers = NULL;
     CURLcode ret = 0;
     
@@ -64,6 +67,8 @@
     
     curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, ucx_buffer_write);
     curl_easy_setopt(handle, CURLOPT_WRITEDATA, response);
+    UcxMap *respheaders = ucx_map_new(32);
+    util_capture_header(handle, respheaders);
     
     for(int i=0;i<=maxredirect;i++) {
         char *url = NULL;
@@ -71,7 +76,7 @@
         if(url) {
             size_t ulen = strlen(url);
             if(ulen > 0) {
-                if(url[ulen-1] == '/') {
+                if (depth == 1) {
                     headers = curl_slist_append(headers, "Depth: 1");
                 } else {
                     headers = curl_slist_append(headers, "Depth: 0");
@@ -92,17 +97,35 @@
         curl_slist_free_all(headers);
         headers = NULL;
         
-        // continue work with URL we get from the server!
+        /*
+         * Handle three cases:
+         * 1. We get a Location header (it's a redirect)
+         *    => follow the URL we get from the server
+         * 2. We communicate with IIS and get a X-MSDAVEXT_Error: 589831
+         *    => try with depth 0 next time, it's not a collection
+         * 3. Other cases
+         *    => the server handled our request and we can stop requesting
+         */
         char *location = NULL;
+        char *msdavexterror;
         curl_easy_getinfo(handle, CURLINFO_REDIRECT_URL, &location);
+        msdavexterror = ucx_map_cstr_get(respheaders, "x-msdavext_error");
+        int iishack =  depth == 1 &&
+            msdavexterror && !strncmp(msdavexterror, "589831;", 7);
+        
         if(location) {
             // redirect
             curl_easy_setopt(handle, CURLOPT_URL, location);
+        } else if(iishack) {
+            depth = 0;
         } else {
             break;
         }
     }
     
+    ucx_map_free_content(respheaders, free);
+    ucx_map_free(respheaders);
+    
     // reset followlocation option
     curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, follow);
     
--- a/libidav/utils.c	Thu Oct 15 15:01:50 2015 +0200
+++ b/libidav/utils.c	Thu Oct 15 15:36:26 2015 +0200
@@ -283,6 +283,81 @@
     return ret;
 }
 
+static size_t util_header_callback(char *buffer, size_t size,
+        size_t nitems, void *data) {
+    
+    char *duped; // local variable for string duplicates
+    
+    UcxMap *map = (UcxMap*) data;
+    
+    // if we get a status line, clear the map and exit
+    if(size*nitems >= 5 && !strncmp("HTTP/", buffer, 5)) {
+        ucx_map_free_content(map, free);
+        ucx_map_clear(map);
+        return size*nitems;
+    }
+    
+    // if we get the terminating CRLF, just exit
+    if (size*nitems == 2 && !strncmp("\r\n", buffer, 2)) {
+        return 2;
+    }
+    
+    
+    // get header key
+    size_t s = 0;
+    do {
+        s++;
+    } while(buffer[s] != ':');
+    char *value = buffer+s+1;
+    
+    // remove trailing spaces
+    while(isspace(buffer[s-1])) {
+        s--;
+    }
+    
+    // save key as all lower case
+    duped = malloc(s);
+    for(size_t i = 0;i<s;i++) {
+        duped[i] = tolower(buffer[i]);
+    }
+    UcxKey key = ucx_key(duped, s);
+    
+    // get trimmed header value
+    while(isspace(*value)) {
+        value++;
+    }
+    s = size*nitems - (value - buffer);
+    while(isspace(value[s-1])) {
+        s--;
+    }
+    
+    // copy header value and append NULL byte (curl does not provide one)
+    duped = malloc(s+1);
+    memcpy(duped, value, s+1);
+    duped[s] = '\0';
+    
+    char *oldval = ucx_map_get(map, key);
+    if(oldval) {
+        free(oldval);
+    }
+    
+    ucx_map_put(map, key, duped);
+    free(key.data); // ucx_map_put made a copy, so we free this memory
+    
+    return nitems * size;    
+}
+
+void util_capture_header(CURL *handle, UcxMap* map) {
+    if(!map) {
+        // deactivate capturing
+        curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, NULL);
+        return;
+    }
+    
+    curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, util_header_callback);
+    curl_easy_setopt(handle, CURLOPT_HEADERDATA, map);
+}
+
 char* util_resource_name(char *url) {
     int si = 0;
     int osi = 0;
--- a/libidav/utils.h	Thu Oct 15 15:01:50 2015 +0200
+++ b/libidav/utils.h	Thu Oct 15 15:36:26 2015 +0200
@@ -65,6 +65,8 @@
 char* util_concat_path(char *url_base, char *path);
 void util_set_url(DavSession *sn, char *href);
 
+void util_capture_header(CURL *handle, UcxMap* map);
+
 char* util_path_to_url(DavSession *sn, char *path);
 char* util_parent_path(char *path);
 

mercurial