THRIFT-3798 THttpClient does not use proxy from http_proxy, https_proxy environment variables
Client: Python
Patch: Martin Wilck <mwilck@arcor.de>
diff --git a/lib/py/src/transport/THttpClient.py b/lib/py/src/transport/THttpClient.py
index 95f118c..a492789 100644
--- a/lib/py/src/transport/THttpClient.py
+++ b/lib/py/src/transport/THttpClient.py
@@ -22,6 +22,7 @@
 import socket
 import sys
 import warnings
+import base64
 
 from six.moves import urllib
 from six.moves import http_client
@@ -63,17 +64,48 @@
             self.path = parsed.path
             if parsed.query:
                 self.path += '?%s' % parsed.query
+        try:
+            proxy = urllib.request.getproxies()[self.scheme]
+        except KeyError:
+            proxy = None
+        else:
+            if urllib.request.proxy_bypass(self.host):
+                proxy = None
+        if proxy:
+            parsed = urllib.parse.urlparse(proxy)
+            self.realhost = self.host
+            self.realport = self.port
+            self.host = parsed.hostname
+            self.port = parsed.port
+            self.proxy_auth = self.basic_proxy_auth_header(parsed)
+        else:
+            self.realhost = self.realport = self.proxy_auth = None
         self.__wbuf = BytesIO()
         self.__http = None
         self.__http_response = None
         self.__timeout = None
         self.__custom_headers = None
 
+    @staticmethod
+    def basic_proxy_auth_header(proxy):
+        if proxy is None or not proxy.username:
+            return None
+        ap = "%s:%s" % (urllib.parse.unquote(proxy.username),
+                        urllib.parse.unquote(proxy.password))
+        cr = base64.b64encode(ap).strip()
+        return "Basic " + cr
+
+    def using_proxy(self):
+        return self.realhost is not None
+
     def open(self):
         if self.scheme == 'http':
             self.__http = http_client.HTTPConnection(self.host, self.port)
-        else:
+        elif self.scheme == 'https':
             self.__http = http_client.HTTPSConnection(self.host, self.port)
+            if self.using_proxy():
+                self.__http.set_tunnel(self.realhost, self.realport,
+                                       { "Proxy-Authorization": self.proxy_auth })
 
     def close(self):
         self.__http.close()
@@ -122,11 +154,18 @@
         self.__wbuf = BytesIO()
 
         # HTTP request
-        self.__http.putrequest('POST', self.path)
+        if self.using_proxy() and self.scheme == "http":
+            # need full URL of real host for HTTP proxy here (HTTPS uses CONNECT tunnel)
+            self.__http.putrequest('POST', "http://%s:%s%s" %
+                                   (self.realhost, self.realport, self.path))
+        else:
+            self.__http.putrequest('POST', self.path)
 
         # Write headers
         self.__http.putheader('Content-Type', 'application/x-thrift')
         self.__http.putheader('Content-Length', str(len(data)))
+        if self.using_proxy() and self.scheme == "http" and self.proxy_auth is not None:
+            self.__http.putheader("Proxy-Authorization", self.proxy_auth)
 
         if not self.__custom_headers or 'User-Agent' not in self.__custom_headers:
             user_agent = 'Python/THttpClient'