Thu, 15 Oct 2015 15:36:26 +0200
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);