src/lib/net.c 1.80

1.80 2010/04/14 07:42:06 galt
Adding support for http(s) proxy
Index: src/lib/net.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/lib/net.c,v
retrieving revision 1.79
retrieving revision 1.80
diff -b -B -U 4 -r1.79 -r1.80
--- src/lib/net.c	10 Mar 2010 23:41:17 -0000	1.79
+++ src/lib/net.c	14 Apr 2010 07:42:06 -0000	1.80
@@ -803,56 +803,95 @@
     return pipefd[0];
     }
 }
 
+
+int connectNpu(struct netParsedUrl npu, char *url)
+/* Connect using NetParsedUrl. */
+{
+int sd = -1;
+if (sameString(npu.protocol, "http"))
+    {
+    sd = netConnect(npu.host, atoi(npu.port));
+    }
+else if (sameString(npu.protocol, "https"))
+    {
+    sd = netConnectHttps(npu.host, atoi(npu.port));
+    }
+else
+    {
+    errAbort("netHttpConnect: url (%s) is not for http.", url);
+    return -1;  /* never gets here, fixes compiler complaint */
+    }
+return sd;
+}
+
+void setAuthorization(struct netParsedUrl npu, char *authHeader, struct dyString *dy)
+/* Set the specified authorization header with BASIC auth base64-encoded user and password */
+{
+if (!sameString(npu.user,""))
+    {
+    char up[256];
+    char *b64up = NULL;
+    safef(up, sizeof(up), "%s:%s", npu.user, npu.password);
+    b64up = base64Encode(up, strlen(up));
+    dyStringPrintf(dy, "%s: Basic %s\r\n", authHeader, b64up);
+    freez(&b64up);
+    }
+}
+
 int netHttpConnect(char *url, char *method, char *protocol, char *agent, char *optionalHeader)
 /* Parse URL, connect to associated server on port, and send most of
  * the request to the server.  If specified in the url send user name
  * and password too.  Typically the "method" will be "GET" or "POST"
  * and the agent will be the name of your program or
  * library. optionalHeader may be NULL or contain additional header
  * lines such as cookie info. 
+ * Proxy support via hg.conf httpProxy or env var http_proxy
  * Return data socket, or -1 if error.*/
 {
 struct netParsedUrl npu;
+struct netParsedUrl pxy;
 struct dyString *dy = newDyString(512);
 int sd = -1;
-
 /* Parse the URL and connect. */
 netParseUrl(url, &npu);
-if (sameString(npu.protocol, "http"))
-    {
-    sd = netConnect(npu.host, atoi(npu.port));
-    }
-else if (sameString(npu.protocol, "https"))
+
+char *proxyUrl = getenv("http_proxy");
+
+if (proxyUrl)
     {
-    sd = netConnectHttps(npu.host, atoi(npu.port));
+    netParseUrl(proxyUrl, &pxy);
+    sd = connectNpu(pxy, url);
     }
 else
     {
-    errAbort("netHttpConnect: url (%s) is not for http.", url);
-    return -1;  /* never gets here, fixes compiler complaint */
+    sd = connectNpu(npu, url);
     }
 if (sd < 0)
     return -1;
 
 /* Ask remote server for a file. */
-dyStringPrintf(dy, "%s %s %s\r\n", method, npu.file, protocol);
+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))
     dyStringPrintf(dy, "Host: %s\r\n", npu.host);
 else
     dyStringPrintf(dy, "Host: %s:%s\r\n", npu.host, npu.port);
-if (!sameString(npu.user,""))
-    {
-    char up[256];
-    char *b64up = NULL;
-    safef(up, sizeof(up), "%s:%s", npu.user, npu.password);
-    b64up = base64Encode(up, strlen(up));
-    dyStringPrintf(dy, "Authorization: Basic %s\r\n", b64up);
-    freez(&b64up);
-    }
+setAuthorization(npu, "Authorization", dy);
+if (proxyUrl)
+    setAuthorization(pxy, "Proxy-Authorization", dy);
 dyStringAppend(dy, "Accept: */*\r\n");
 if (npu.byteRangeStart != -1)
     {
     if (npu.byteRangeEnd != -1)
@@ -999,8 +1038,13 @@
 char *sep = NULL;
 char *headerName = NULL;
 char *headerVal = NULL;
 boolean redirect = FALSE;
+
+boolean mustUseProxy = FALSE;  /* User must use proxy 305 error*/
+char *proxyLocation = NULL;
+boolean mustUseProxyAuth = FALSE;  /* User must use proxy authentication 407 error*/
+
 while(TRUE)
     {
     i = 0;
     while (TRUE)
@@ -1046,8 +1090,16 @@
 	    && ((code[2] >= '0' && code[2] <= '3') || code[2] == '7') && code[3] == 0)
 	    {
 	    redirect = TRUE;
 	    }
+	else if (sameString(code, "305"))
+	    {
+	    mustUseProxy = TRUE;
+	    }
+	else if (sameString(code, "407"))
+	    {
+	    mustUseProxyAuth = TRUE;
+	    }
 	else if (!(sameString(code, "200") || sameString(code, "206")))
 	    {
 	    warn("%s: %s %s\n", url, code, line);
 	    return FALSE;
@@ -1068,10 +1120,20 @@
     if (sameWord(headerName,"Location"))
 	{
 	if (redirect)
 	    *redirectedUrl = cloneString(headerVal);
+	if (mustUseProxy)
+	    proxyLocation = cloneString(headerVal);
 	}
     }
+if (mustUseProxy ||  mustUseProxyAuth)
+    {
+    warn("%s: %s error. Use Proxy%s. Location = %s\n", url, 
+	mustUseProxy ? "" : " Authentication", 
+	mustUseProxy ? "305" : "407", 
+	proxyLocation ? proxyLocation : "not given");
+    return FALSE;
+    }
 return TRUE;
 }