c6961a123a07b21da18ad03045e4733b8f3496ac max Tue Nov 8 14:42:07 2016 -0800 adding goOnline to -f gbic mode, email from chmalee, no redmine diff --git src/lib/udc.c src/lib/udc.c index 095ac97..332bcde 100644 --- src/lib/udc.c +++ src/lib/udc.c @@ -78,30 +78,31 @@ }; #define udcBlockSize (8*1024) /* All fetch requests are rounded up to block size. */ #define udcMaxBytesPerRemoteFetch (udcBlockSize * 32) /* Very large remote reads are broken down into chunks this size. */ struct connInfo /* Socket descriptor and associated info, for keeping net connections open. */ { int socket; /* Socket descriptor for data connection (or 0). */ bits64 offset; /* Current file offset of socket. */ int ctrlSocket; /* (FTP only) Control socket descriptor or 0. */ char *redirUrl; /* (HTTP(S) only) use redirected url */ + char *tmpRedirUrl; }; typedef int (*UdcDataCallback)(char *url, bits64 offset, int size, void *buffer, struct udcFile *file); /* Type for callback function that fetches file data. */ struct udcRemoteFileInfo /* Information about a remote file. */ { bits64 updateTime; /* Last update in seconds since 1970 */ bits64 size; /* Remote file size */ struct connInfo ci; /* Connection info for open net connection */ }; typedef boolean (*UdcInfoCallback)(char *url, struct udcRemoteFileInfo *retInfo); @@ -434,72 +435,98 @@ defaultDir = NULL; } static bool udcCacheEnabled() /* TRUE if caching is activated */ { return (defaultDir != NULL); } int udcDataViaHttpOrFtp( char *url, bits64 offset, int size, void *buffer, struct udcFile *file) /* Fetch a block of data of given size into buffer using url's protocol, * which must be http, https or ftp. Returns number of bytes actually read. * Does an errAbort on error. * Typically will be called with size in the 8k-64k range. */ { +if (file->connInfo.tmpRedirUrl) + url = file->connInfo.tmpRedirUrl; + if (startsWith("http://",url) || startsWith("https://",url) || startsWith("ftp://",url)) verbose(4, "reading http/https/ftp data - %d bytes at %lld - on %s\n", size, offset, url); else errAbort("Invalid protocol in url [%s] in udcDataViaFtp, only http, https, or ftp supported", url); int sd = connInfoGetSocket(file, url, offset, size); if (sd < 0) errAbort("Can't get data socket for %s", url); int rd = 0, total = 0, remaining = size; char *buf = (char *)buffer; while ((remaining > 0) && ((rd = ourRead(&file->ios.net, sd, buf, remaining)) > 0)) { total += rd; buf += rd; remaining -= rd; } if (rd == -1) errnoAbort("udcDataViaHttpOrFtp: error reading socket"); struct connInfo *ci = &file->connInfo; if (ci == NULL) mustCloseFd(&sd); else ci->offset += total; return total; } +static int followOneRedirect(int status, struct hash **hashPtr, struct udcRemoteFileInfo *retInfo) +// if needed, follow a single redirect and add new URL to retInfo->ci.tmpRedirUrl +{ +struct hash *hash = *hashPtr; +if (status != 302 || !hashFindValUpperCase(hash, "Location:")) + return status; + +char *newUrl = cloneString((char *)hashFindValUpperCase(hash, "Location:")); +retInfo->ci.tmpRedirUrl = cloneString(newUrl); +freeHashAndVals(&hash); +hash = newHash(0); +status = netUrlHead(newUrl, hash); +return status; +} + boolean udcInfoViaHttp(char *url, struct udcRemoteFileInfo *retInfo) /* Gets size and last modified time of URL * and returns status of HEAD GET. */ { verbose(4, "checking http remote info on %s\n", url); int redirectCount = 0; struct hash *hash; int status; while (TRUE) { hash = newHash(0); status = netUrlHead(url, hash); + + // dropbox/box.com/onedrive redirect up to twice, + // the redirect has to be re-done every time + status = followOneRedirect(status, &hash, retInfo); + status = followOneRedirect(status, &hash, retInfo); + if (status == 200) break; + if (status != 301 && status != 302) return FALSE; + ++redirectCount; if (redirectCount > 5) { warn("code %d redirects: exceeded limit of 5 redirects, %s", status, url); return FALSE; } char *newUrl = hashFindValUpperCase(hash, "Location:"); retInfo->ci.redirUrl = cloneString(newUrl); url = transferParamsToRedirectedUrl(url, newUrl); hashFree(&hash); } char *sizeString = hashFindValUpperCase(hash, "Content-Length:"); if (sizeString == NULL) {