From 257454b5bd7b7d6b7aa224ad43fe398b38a9651a Mon Sep 17 00:00:00 2001
From: Vijay Panghal <vijay.panghal@gmail.com>
Date: Mon, 25 Aug 2014 10:30:01 -0700
Subject: [PATCH] [https proxy]: Add support for https proxy.

This commit add https proxy support in curl. Right now curl support
http proxy. With this change, https proxy will be able to fetch either
http/https resource from remote server.
TODO: Add these unit tests
- Https proxy fetching https url
- Https proxy fetching http url
- Authenticated https proxy fetching https url
- Authenticated https proxy fetching http url
---
 include/curl/curl.h |  3 ++-
 lib/http.c          | 15 +++++++++------
 lib/url.c           | 11 ++++++++++-
 lib/urldata.h       |  1 +
 4 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/include/curl/curl.h b/include/curl/curl.h
index d40b2db..1bf6ae1 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -613,9 +613,10 @@ typedef enum {
                            in 7.10 */
   CURLPROXY_SOCKS5 = 5, /* added in 7.10 */
   CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */
-  CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the
+  CURLPROXY_SOCKS5_HOSTNAME = 7, /* Use the SOCKS5 protocol but pass along the
                                    host name rather than the IP address. added
                                    in 7.18.0 */
+  CURLPROXY_HTTPS = 8, /* added in 7.38.0 */
 } curl_proxytype;  /* this enum was added in 7.10 */
 
 /*
diff --git a/lib/http.c b/lib/http.c
index 3fdab27..69a53e0 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -670,7 +670,8 @@ Curl_http_output_auth(struct connectdata *conn,
   authhost = &data->state.authhost;
   authproxy = &data->state.authproxy;
 
-  if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
+  if(((conn->bits.httpproxy || conn->bits.httpsproxy) &&
+      conn->bits.proxy_user_passwd) ||
      conn->bits.user_passwd)
     /* continue please */ ;
   else {
@@ -1558,7 +1559,8 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
   if(is_connect)
     proxy = HEADER_CONNECT;
   else
-    proxy = conn->bits.httpproxy && !conn->bits.tunnel_proxy?
+    proxy = (conn->bits.httpproxy || conn->bits.httpsproxy) &&
+    !conn->bits.tunnel_proxy?
       HEADER_PROXY:HEADER_SERVER;
 
   switch(proxy) {
@@ -1987,7 +1989,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
   }
 
 #ifndef CURL_DISABLE_PROXY
-  if(conn->bits.httpproxy && !conn->bits.tunnel_proxy)  {
+  if((conn->bits.httpproxy || conn->bits.httpsproxy)
+     && !conn->bits.tunnel_proxy)  {
     /* Using a proxy but does not tunnel through it */
 
     /* The path sent to the proxy is in fact the entire URL. But if the remote
@@ -2259,7 +2262,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
                      conn->allocptr.accept_encoding:"",
                      (data->change.referer && conn->allocptr.ref)?
                      conn->allocptr.ref:"" /* Referer: <data> */,
-                     (conn->bits.httpproxy &&
+                     ((conn->bits.httpproxy || conn->bits.httpsproxy) &&
                       !conn->bits.tunnel_proxy &&
                       !Curl_checkProxyheaders(conn, "Proxy-Connection:"))?
                      "Proxy-Connection: Keep-Alive\r\n":"",
@@ -3389,7 +3392,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
       Curl_safefree(server_name);
     }
     else if((conn->httpversion == 10) &&
-            conn->bits.httpproxy &&
+            (conn->bits.httpproxy || conn->bits.httpsproxy) &&
             Curl_compareheader(k->p,
                                "Proxy-Connection:", "keep-alive")) {
       /*
@@ -3402,7 +3405,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
       infof(data, "HTTP/1.0 proxy connection set to keep alive!\n");
     }
     else if((conn->httpversion == 11) &&
-            conn->bits.httpproxy &&
+            (conn->bits.httpproxy || conn->bits.httpsproxy) &&
             Curl_compareheader(k->p,
                                "Proxy-Connection:", "close")) {
       /*
diff --git a/lib/url.c b/lib/url.c
index f2ce4ff..fca88fd 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -4397,6 +4397,8 @@ static CURLcode parse_proxy(struct SessionHandle *data,
       conn->proxytype = CURLPROXY_SOCKS4A;
     else if(checkprefix("socks4", proxy) || checkprefix("socks", proxy))
       conn->proxytype = CURLPROXY_SOCKS4;
+    if(checkprefix("https", proxy))
+      conn->proxytype = CURLPROXY_HTTPS;
     /* Any other xxx:// : change to http proxy */
   }
   else
@@ -4850,7 +4852,7 @@ static CURLcode parse_remote_port(struct SessionHandle *data,
     if(portptr)
       *portptr = '\0'; /* cut off the name there anyway - if there was a port
                       number - since the port number is to be ignored! */
-    if(conn->bits.httpproxy) {
+    if(conn->bits.httpproxy || conn->bits.httpsproxy) {
       /* we need to create new URL with the new port number */
       char *url;
       char type[12]="";
@@ -5386,6 +5388,12 @@ static CURLcode create_conn(struct SessionHandle *data,
         conn->handler = &Curl_handler_http;
 
       conn->bits.httpproxy = TRUE;
+    }
+    else if(conn->proxytype == CURLPROXY_HTTPS) {
+      conn->bits.httpproxy = FALSE;
+      conn->bits.httpsproxy = TRUE;
+      conn->given = &Curl_handler_https;
+      conn->handler = &Curl_handler_https;
 #endif
     }
     else
@@ -5396,6 +5404,7 @@ static CURLcode create_conn(struct SessionHandle *data,
     /* we aren't using the proxy after all... */
     conn->bits.proxy = FALSE;
     conn->bits.httpproxy = FALSE;
+    conn->bits.httpsproxy = FALSE;
     conn->bits.proxy_user_passwd = FALSE;
     conn->bits.tunnel_proxy = FALSE;
   }
diff --git a/lib/urldata.h b/lib/urldata.h
index 8594c2f..cba27da 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -495,6 +495,7 @@ struct ConnectBits {
   bool reuse; /* if set, this is a re-used connection */
   bool proxy; /* if set, this transfer is done through a proxy - any type */
   bool httpproxy;    /* if set, this transfer is done through a http proxy */
+  bool httpsproxy;   /* if set, this transfer is done through a https proxy */
   bool user_passwd;    /* do we use user+password for this connection? */
   bool proxy_user_passwd; /* user+password for the proxy? */
   bool ipv6_ip; /* we communicate with a remote site specified with pure IPv6
-- 
1.8.5.2 (Apple Git-48)

