url: always use str for proxy configuration
authorGregory Szorc <gregory.szorc@gmail.com>
Fri, 15 Feb 2019 13:16:07 -0800
changeset 41710 4028897dfa05
parent 41709 97e2442a4595
child 41711 544035846830
url: always use str for proxy configuration Previously, proxies didn't work on Python 3 for various reasons. First, the keys to the "proxies" dict are fed into a `setattr(self, "%s_open", ...)` call and passing bytestrings results in setting an oddly named attribute due to the b'' in %s formatting. This resulted in "http_open" and "https_open" not being properly overridden and proxies not being used. Second, the standard library was expecting proxy URLs to be str. And various operations (including our custom code in url.py) would fail to account for the str/bytes mismatch. This commit normalizes everything to str and adjusts our proxy code in url.py to account for the presence of str on Python 3. Differential Revision: https://phab.mercurial-scm.org/D5952
mercurial/url.py
--- a/mercurial/url.py	Tue Feb 12 14:29:56 2019 -0800
+++ b/mercurial/url.py	Fri Feb 15 13:16:07 2019 -0800
@@ -131,9 +131,11 @@
             else:
                 self.no_list = no_list
 
-            proxyurl = bytes(proxy)
-            proxies = {'http': proxyurl, 'https': proxyurl}
-            ui.debug('proxying through %s\n' % util.hidepassword(proxyurl))
+            # Keys and values need to be str because the standard library
+            # expects them to be.
+            proxyurl = str(proxy)
+            proxies = {r'http': proxyurl, r'https': proxyurl}
+            ui.debug('proxying through %s\n' % util.hidepassword(bytes(proxy)))
         else:
             proxies = {}
 
@@ -141,7 +143,7 @@
         self.ui = ui
 
     def proxy_open(self, req, proxy, type_):
-        host = urllibcompat.gethost(req).split(':')[0]
+        host = pycompat.bytesurl(urllibcompat.gethost(req)).split(':')[0]
         for e in self.no_list:
             if host == e:
                 return None
@@ -184,15 +186,15 @@
 def _generic_start_transaction(handler, h, req):
     tunnel_host = req._tunnel_host
     if tunnel_host:
-        if tunnel_host[:7] not in ['http://', 'https:/']:
-            tunnel_host = 'https://' + tunnel_host
+        if tunnel_host[:7] not in [r'http://', r'https:/']:
+            tunnel_host = r'https://' + tunnel_host
         new_tunnel = True
     else:
         tunnel_host = urllibcompat.getselector(req)
         new_tunnel = False
 
     if new_tunnel or tunnel_host == urllibcompat.getfullurl(req): # has proxy
-        u = util.url(tunnel_host)
+        u = util.url(pycompat.bytesurl(tunnel_host))
         if new_tunnel or u.scheme == 'https': # only use CONNECT for HTTPS
             h.realhostport = ':'.join([u.host, (u.port or '443')])
             h.headers = req.headers.copy()
@@ -205,7 +207,7 @@
 def _generic_proxytunnel(self):
     proxyheaders = dict(
             [(x, self.headers[x]) for x in self.headers
-             if x.lower().startswith('proxy-')])
+             if x.lower().startswith(r'proxy-')])
     self.send('CONNECT %s HTTP/1.0\r\n' % self.realhostport)
     for header in proxyheaders.iteritems():
         self.send('%s: %s\r\n' % header)