25a903639645b7bd2d783858023555c375dbc112
galt
  Tue May 17 18:08:51 2011 -0700
adding support for redirects to byterange urls
diff --git src/lib/net.c src/lib/net.c
index bf99f67..0d36230 100644
--- src/lib/net.c
+++ src/lib/net.c
@@ -472,30 +472,69 @@
     if (sameWord(parsed->protocol,"ftp"))
 	strcpy(parsed->port, "21");
     }
 else
     {
     *t++ = 0;
     if (!isdigit(t[0]))
 	errAbort("Non-numeric port name %s", t);
     safecpy(parsed->port, sizeof(parsed->port), t);
     }
 
 /* What's left is the host. */
 safecpy(parsed->host, sizeof(parsed->host), s);
 }
 
+char *urlFromNetParsedUrl(struct netParsedUrl *npu)
+/* Build URL from netParsedUrl structure */
+{
+struct dyString *dy = newDyString(512);
+
+dyStringAppend(dy, npu->protocol);
+dyStringAppend(dy, "://");
+if (npu->user[0] != 0)
+    {
+    dyStringAppend(dy, npu->user);
+    if (npu->password[0] != 0)
+	{
+	dyStringAppend(dy, ":");
+	dyStringAppend(dy, npu->password);
+	}
+    dyStringAppend(dy, "@");
+    }
+dyStringAppend(dy, npu->host);
+/* do not include port if it is the default */
+if (!(
+ (sameString(npu->protocol, "ftp"  ) && sameString("21", npu->port)) ||
+ (sameString(npu->protocol, "http" ) && sameString("80", npu->port)) ||
+ (sameString(npu->protocol, "https") && sameString("443",npu->port))
+    ))
+    {
+    dyStringAppend(dy, ":");
+    dyStringAppend(dy, npu->port);
+    }
+dyStringAppend(dy, npu->file);
+if (npu->byteRangeStart != -1)
+    {
+    dyStringPrintf(dy, ";byterange=%lld-", (long long)npu->byteRangeStart);
+    if (npu->byteRangeEnd != -1)
+	dyStringPrintf(dy, "%lld", (long long)npu->byteRangeEnd);
+    }
+
+/* Clean up and return handle. */
+return dyStringCannibalize(&dy);
+}
 
 /* this was cloned from rudp.c - move it later for sharing */
 static boolean readReadyWait(int sd, int microseconds)
 /* Wait for descriptor to have some data to read, up to
  * given number of microseconds. */
 {
 struct timeval tv;
 fd_set set;
 int readyCount;
 
 for (;;)
     {
     if (microseconds >= 1000000)
 	{
 	tv.tv_sec = microseconds/1000000;
@@ -993,31 +1032,32 @@
 
 /* Ask remote server for a file. */
 char *urlForProxy = NULL;
 if (proxyUrl)
     {
     /* trim off the byterange part at the end of url because proxy does not understand it. */
     urlForProxy = cloneString(url);
     char *x = strrchr(urlForProxy, ';');
     if (x && startsWith(";byterange=", x))
 	*x = 0;
     }
 dyStringPrintf(dy, "%s %s %s\r\n", method, proxyUrl ? urlForProxy : npu.file, protocol);
 freeMem(urlForProxy);
 dyStringPrintf(dy, "User-Agent: %s\r\n", agent);
 /* do not need the 80 since it is the default */
-if (sameString("80",npu.port))
+if ((sameString(npu.protocol, "http" ) && sameString("80", npu.port)) ||
+    (sameString(npu.protocol, "https") && sameString("443",npu.port)))
     dyStringPrintf(dy, "Host: %s\r\n", npu.host);
 else
     dyStringPrintf(dy, "Host: %s:%s\r\n", npu.host, npu.port);
 setAuthorization(npu, "Authorization", dy);
 if (proxyUrl)
     setAuthorization(pxy, "Proxy-Authorization", dy);
 dyStringAppend(dy, "Accept: */*\r\n");
 if (npu.byteRangeStart != -1)
     {
     if (npu.byteRangeEnd != -1)
 	dyStringPrintf(dy, "Range: bytes=%lld-%lld\r\n"
 		       , (long long)npu.byteRangeStart
 		       , (long long)npu.byteRangeEnd);
     else
 	dyStringPrintf(dy, "Range: bytes=%lld-\r\n"
@@ -1423,30 +1463,44 @@
 	/* we have a new url to try */
 	++redirectCount;
 	if (redirectCount > 5)
 	    {
 	    warn("code 30x redirects: exceeded limit of 5 redirects, %s", newUrl);
 	    success = FALSE;
 	    }
 	else if (!startsWith("http://",newUrl) 
               && !startsWith("https://",newUrl))
 	    {
 	    warn("redirected to non-http(s): %s", newUrl);
 	    success = FALSE;
 	    }
 	else 
 	    {
+	    struct netParsedUrl npu;
+	    /* Parse the old URL to make parts available for graft onto the redirected url. */
+	    /* This makes redirection work with byterange urls */
+	    /* If needed we can preserve the user and password from the old url in a similar way. */
+	    netParseUrl(url, &npu);
+	    if (npu.byteRangeStart != -1)
+		{
+		struct netParsedUrl newNpu;
+		netParseUrl(newUrl, &newNpu);
+		newNpu.byteRangeStart = npu.byteRangeStart;
+		newNpu.byteRangeEnd = npu.byteRangeEnd;
+		freeMem(newUrl);
+		newUrl = urlFromNetParsedUrl(&newNpu);
+		}
 	    sd = netUrlOpen(newUrl);
 	    if (sd < 0)
 		{
 		warn("Couldn't open %s", newUrl);
 		success = FALSE;
 		}
 	    }
 	}
     if (!success)
 	{  /* failure after 0 to 5 redirects */
 	if (redirectCount > 0)
 	    freeMem(newUrl);
 	return FALSE;
 	}
     url = newUrl;
@@ -1939,33 +1993,30 @@
 	    else
 		{
 		char *newUrl = NULL;
 		int newSd = 0;
 		if (startsWith("http://",url) || startsWith("https://",url))
 		    {
 		    if (!netSkipHttpHeaderLinesHandlingRedirect(pc->sd, urlExt, &newSd, &newUrl))
 			{
 			warn("Error processing http response for %s", url);
 			return FALSE;
 			}
 		    if (newUrl) 
 			{
 			/*  Update sd with newSd, replace it with newUrl, etc. */
 			pc->sd = newSd;
-			warn("Redirects not supported at this time: %s re-directed to: %s", url, newUrl);
-			freeMem(newUrl);  /* redirects with byterange do not work anyway */
-			return FALSE;
 			}
 		    }
 		++connOpen;
 		}
 	    }
 	}
 
 
     if (connOpen == 0)
 	{
 	warn("Unable to open any connections to download %s, can't proceed, sorry", url);
 	return FALSE;
 	}