mercurial/url.py
changeset 43076 2372284d9457
parent 42109 2a3c0106ded9
child 43077 687b865b95ad
--- a/mercurial/url.py	Sat Oct 05 10:29:34 2019 -0400
+++ b/mercurial/url.py	Sun Oct 06 09:45:02 2019 -0400
@@ -25,15 +25,14 @@
     urllibcompat,
     util,
 )
-from .utils import (
-    stringutil,
-)
+from .utils import stringutil
 
 httplib = util.httplib
 stringio = util.stringio
 urlerr = util.urlerr
 urlreq = util.urlreq
 
+
 def escape(s, quote=None):
     '''Replace special characters "&", "<" and ">" to HTML-safe sequences.
     If the optional flag quote is true, the quotation mark character (")
@@ -49,6 +48,7 @@
         s = s.replace(b'"', b"&quot;")
     return s
 
+
 class passwordmgr(object):
     def __init__(self, ui, passwddb):
         self.ui = ui
@@ -77,11 +77,15 @@
             u = util.url(pycompat.bytesurl(authuri))
             u.query = None
             if not self.ui.interactive():
-                raise error.Abort(_('http authorization required for %s') %
-                                  util.hidepassword(bytes(u)))
+                raise error.Abort(
+                    _('http authorization required for %s')
+                    % util.hidepassword(bytes(u))
+                )
 
-            self.ui.write(_("http authorization required for %s\n") %
-                          util.hidepassword(bytes(u)))
+            self.ui.write(
+                _("http authorization required for %s\n")
+                % util.hidepassword(bytes(u))
+            )
             self.ui.write(_("realm: %s\n") % pycompat.bytesurl(realm))
             if user:
                 self.ui.write(_("user: %s\n") % user)
@@ -102,16 +106,19 @@
     def find_stored_password(self, authuri):
         return self.passwddb.find_user_password(None, authuri)
 
+
 class proxyhandler(urlreq.proxyhandler):
     def __init__(self, ui):
-        proxyurl = (ui.config("http_proxy", "host") or
-                        encoding.environ.get('http_proxy'))
+        proxyurl = ui.config("http_proxy", "host") or encoding.environ.get(
+            'http_proxy'
+        )
         # XXX proxyauthinfo = None
 
         if proxyurl:
             # proxy can be proper url or host[:port]
-            if not (proxyurl.startswith('http:') or
-                    proxyurl.startswith('https:')):
+            if not (
+                proxyurl.startswith('http:') or proxyurl.startswith('https:')
+            ):
                 proxyurl = 'http://' + proxyurl + '/'
             proxy = util.url(proxyurl)
             if not proxy.user:
@@ -120,11 +127,16 @@
 
             # see if we should use a proxy for this url
             no_list = ["localhost", "127.0.0.1"]
-            no_list.extend([p.lower() for
-                            p in ui.configlist("http_proxy", "no")])
-            no_list.extend([p.strip().lower() for
-                            p in encoding.environ.get("no_proxy", '').split(',')
-                            if p.strip()])
+            no_list.extend(
+                [p.lower() for p in ui.configlist("http_proxy", "no")]
+            )
+            no_list.extend(
+                [
+                    p.strip().lower()
+                    for p in encoding.environ.get("no_proxy", '').split(',')
+                    if p.strip()
+                ]
+            )
             # "http_proxy.always" config is for running tests on localhost
             if ui.configbool("http_proxy", "always"):
                 self.no_list = []
@@ -154,6 +166,7 @@
 
         return urlreq.proxyhandler.proxy_open(self, req, proxy, type_)
 
+
 def _gen_sendfile(orgsend):
     def _sendfile(self, data):
         # send a file
@@ -164,10 +177,13 @@
                 orgsend(self, chunk)
         else:
             orgsend(self, data)
+
     return _sendfile
 
+
 has_https = util.safehasattr(urlreq, 'httpshandler')
 
+
 class httpconnection(keepalive.HTTPConnection):
     # must be able to send big bundle as stream.
     send = _gen_sendfile(keepalive.HTTPConnection.send)
@@ -181,6 +197,7 @@
             return proxyres
         return keepalive.HTTPConnection.getresponse(self)
 
+
 # Large parts of this function have their origin from before Python 2.6
 # and could potentially be removed.
 def _generic_start_transaction(handler, h, req):
@@ -193,9 +210,9 @@
         tunnel_host = urllibcompat.getselector(req)
         new_tunnel = False
 
-    if new_tunnel or tunnel_host == urllibcompat.getfullurl(req): # has proxy
+    if new_tunnel or tunnel_host == urllibcompat.getfullurl(req):  # has proxy
         u = util.url(pycompat.bytesurl(tunnel_host))
-        if new_tunnel or u.scheme == 'https': # only use CONNECT for HTTPS
+        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()
             h.headers.update(handler.parent.addheaders)
@@ -204,10 +221,15 @@
     h.realhostport = None
     h.headers = None
 
+
 def _generic_proxytunnel(self):
     proxyheaders = dict(
-            [(x, self.headers[x]) for x in self.headers
-             if x.lower().startswith(r'proxy-')])
+        [
+            (x, self.headers[x])
+            for x in self.headers
+            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)
@@ -221,9 +243,7 @@
     if not pycompat.ispy3:
         kwargs['strict'] = self.strict
 
-    res = self.response_class(self.sock,
-                              method=self._method,
-                              **kwargs)
+    res = self.response_class(self.sock, method=self._method, **kwargs)
 
     while True:
         version, status, reason = res._read_status()
@@ -285,23 +305,25 @@
         res.length = None
 
     # does the body have a fixed length? (of zero)
-    if (status == httplib.NO_CONTENT or status == httplib.NOT_MODIFIED or
-        100 <= status < 200 or # 1xx codes
-        res._method == 'HEAD'):
+    if (
+        status == httplib.NO_CONTENT
+        or status == httplib.NOT_MODIFIED
+        or 100 <= status < 200
+        or res._method == 'HEAD'  # 1xx codes
+    ):
         res.length = 0
 
     # if the connection remains open, and we aren't using chunked, and
     # a content-length was not provided, then assume that the connection
     # WILL close.
-    if (not res.will_close and
-       not res.chunked and
-       res.length is None):
+    if not res.will_close and not res.chunked and res.length is None:
         res.will_close = 1
 
     self.proxyres = res
 
     return False
 
+
 class httphandler(keepalive.HTTPHandler):
     def http_open(self, req):
         return self.do_open(httpconnection, req)
@@ -310,6 +332,7 @@
         _generic_start_transaction(self, h, req)
         return keepalive.HTTPHandler._start_transaction(self, h, req)
 
+
 class logginghttpconnection(keepalive.HTTPConnection):
     def __init__(self, createconn, *args, **kwargs):
         keepalive.HTTPConnection.__init__(self, *args, **kwargs)
@@ -319,14 +342,16 @@
         # copied from 2.7.14, since old implementations directly call
         # socket.create_connection()
         def connect(self):
-            self.sock = self._create_connection((self.host, self.port),
-                                                self.timeout,
-                                                self.source_address)
+            self.sock = self._create_connection(
+                (self.host, self.port), self.timeout, self.source_address
+            )
             if self._tunnel_host:
                 self._tunnel()
 
+
 class logginghttphandler(httphandler):
     """HTTP handler that logs socket I/O."""
+
     def __init__(self, logfh, name, observeropts, timeout=None):
         super(logginghttphandler, self).__init__(timeout=timeout)
 
@@ -343,12 +368,15 @@
     def _makeconnection(self, *args, **kwargs):
         def createconnection(*args, **kwargs):
             sock = socket.create_connection(*args, **kwargs)
-            return util.makeloggingsocket(self._logfh, sock, self._logname,
-                                          **self._observeropts)
+            return util.makeloggingsocket(
+                self._logfh, sock, self._logname, **self._observeropts
+            )
 
         return logginghttpconnection(createconnection, *args, **kwargs)
 
+
 if has_https:
+
     class httpsconnection(keepalive.HTTPConnection):
         response_class = keepalive.HTTPResponse
         default_port = httplib.HTTPS_PORT
@@ -356,8 +384,15 @@
         send = _gen_sendfile(keepalive.safesend)
         getresponse = keepalive.wrapgetresponse(httplib.HTTPConnection)
 
-        def __init__(self, host, port=None, key_file=None, cert_file=None,
-                     *args, **kwargs):
+        def __init__(
+            self,
+            host,
+            port=None,
+            key_file=None,
+            cert_file=None,
+            *args,
+            **kwargs
+        ):
             keepalive.HTTPConnection.__init__(self, host, port, *args, **kwargs)
             self.key_file = key_file
             self.cert_file = cert_file
@@ -366,12 +401,16 @@
             self.sock = socket.create_connection((self.host, self.port))
 
             host = self.host
-            if self.realhostport: # use CONNECT proxy
+            if self.realhostport:  # use CONNECT proxy
                 _generic_proxytunnel(self)
                 host = self.realhostport.rsplit(':', 1)[0]
             self.sock = sslutil.wrapsocket(
-                self.sock, self.key_file, self.cert_file, ui=self.ui,
-                serverhostname=host)
+                self.sock,
+                self.key_file,
+                self.cert_file,
+                ui=self.ui,
+                serverhostname=host,
+            )
             sslutil.validatesocket(self.sock)
 
     class httpshandler(keepalive.KeepAliveHandler, urlreq.httpshandler):
@@ -379,8 +418,7 @@
             keepalive.KeepAliveHandler.__init__(self, timeout=timeout)
             urlreq.httpshandler.__init__(self)
             self.ui = ui
-            self.pwmgr = passwordmgr(self.ui,
-                                     self.ui.httppasswordmgrdb)
+            self.pwmgr = passwordmgr(self.ui, self.ui.httppasswordmgrdb)
 
         def _start_transaction(self, h, req):
             _generic_start_transaction(self, h, req)
@@ -404,9 +442,9 @@
             keyfile = None
             certfile = None
 
-            if len(args) >= 1: # key_file
+            if len(args) >= 1:  # key_file
                 keyfile = args[0]
-            if len(args) >= 2: # cert_file
+            if len(args) >= 2:  # cert_file
                 certfile = args[1]
             args = args[2:]
 
@@ -416,11 +454,13 @@
                 keyfile = self.auth['key']
                 certfile = self.auth['cert']
 
-            conn = httpsconnection(host, port, keyfile, certfile, *args,
-                                   **kwargs)
+            conn = httpsconnection(
+                host, port, keyfile, certfile, *args, **kwargs
+            )
             conn.ui = self.ui
             return conn
 
+
 class httpdigestauthhandler(urlreq.httpdigestauthhandler):
     def __init__(self, *args, **kwargs):
         urlreq.httpdigestauthhandler.__init__(self, *args, **kwargs)
@@ -438,7 +478,9 @@
             self.retried_req = req
             self.retried = 0
         return urlreq.httpdigestauthhandler.http_error_auth_reqed(
-                    self, auth_header, host, req, headers)
+            self, auth_header, host, req, headers
+        )
+
 
 class httpbasicauthhandler(urlreq.httpbasicauthhandler):
     def __init__(self, *args, **kwargs):
@@ -470,11 +512,13 @@
             self.retried_req = req
             self.retried = 0
         return urlreq.httpbasicauthhandler.http_error_auth_reqed(
-                        self, auth_header, host, req, headers)
+            self, auth_header, host, req, headers
+        )
 
     def retry_http_basic_auth(self, host, req, realm):
         user, pw = self.passwd.find_user_password(
-            realm, urllibcompat.getfullurl(req))
+            realm, urllibcompat.getfullurl(req)
+        )
         if pw is not None:
             raw = "%s:%s" % (pycompat.bytesurl(user), pycompat.bytesurl(pw))
             auth = r'Basic %s' % pycompat.strurl(base64.b64encode(raw).strip())
@@ -486,6 +530,7 @@
         else:
             return None
 
+
 class cookiehandler(urlreq.basehandler):
     def __init__(self, ui):
         self.cookiejar = None
@@ -497,12 +542,18 @@
         cookiefile = util.expandpath(cookiefile)
         try:
             cookiejar = util.cookielib.MozillaCookieJar(
-                pycompat.fsdecode(cookiefile))
+                pycompat.fsdecode(cookiefile)
+            )
             cookiejar.load()
             self.cookiejar = cookiejar
         except util.cookielib.LoadError as e:
-            ui.warn(_('(error loading cookie file %s: %s; continuing without '
-                      'cookies)\n') % (cookiefile, stringutil.forcebytestr(e)))
+            ui.warn(
+                _(
+                    '(error loading cookie file %s: %s; continuing without '
+                    'cookies)\n'
+                )
+                % (cookiefile, stringutil.forcebytestr(e))
+            )
 
     def http_request(self, request):
         if self.cookiejar:
@@ -516,10 +567,19 @@
 
         return request
 
+
 handlerfuncs = []
 
-def opener(ui, authinfo=None, useragent=None, loggingfh=None,
-           loggingname=b's', loggingopts=None, sendaccept=True):
+
+def opener(
+    ui,
+    authinfo=None,
+    useragent=None,
+    loggingfh=None,
+    loggingname=b's',
+    loggingopts=None,
+    sendaccept=True,
+):
     '''
     construct an opener suitable for urllib2
     authinfo will be added to the password manager
@@ -539,8 +599,11 @@
     handlers = []
 
     if loggingfh:
-        handlers.append(logginghttphandler(loggingfh, loggingname,
-                                           loggingopts or {}, timeout=timeout))
+        handlers.append(
+            logginghttphandler(
+                loggingfh, loggingname, loggingopts or {}, timeout=timeout
+            )
+        )
         # We don't yet support HTTPS when logging I/O. If we attempt to open
         # an HTTPS URL, we'll likely fail due to unknown protocol.
 
@@ -557,11 +620,14 @@
         saveduser, savedpass = passmgr.find_stored_password(uris[0])
         if user != saveduser or passwd:
             passmgr.add_password(realm, uris, user, passwd)
-        ui.debug('http auth: user %s, password %s\n' %
-                 (user, passwd and '*' * len(passwd) or 'not set'))
+        ui.debug(
+            'http auth: user %s, password %s\n'
+            % (user, passwd and '*' * len(passwd) or 'not set')
+        )
 
-    handlers.extend((httpbasicauthhandler(passmgr),
-                     httpdigestauthhandler(passmgr)))
+    handlers.extend(
+        (httpbasicauthhandler(passmgr), httpdigestauthhandler(passmgr))
+    )
     handlers.extend([h(ui, passmgr) for h in handlerfuncs])
     handlers.append(cookiehandler(ui))
     opener = urlreq.buildopener(*handlers)
@@ -601,6 +667,7 @@
 
     return opener
 
+
 def open(ui, url_, data=None, sendaccept=True):
     u = util.url(url_)
     if u.scheme:
@@ -610,9 +677,10 @@
         path = util.normpath(os.path.abspath(url_))
         url_ = 'file://' + pycompat.bytesurl(urlreq.pathname2url(path))
         authinfo = None
-    return opener(ui, authinfo,
-                  sendaccept=sendaccept).open(pycompat.strurl(url_),
-                                              data)
+    return opener(ui, authinfo, sendaccept=sendaccept).open(
+        pycompat.strurl(url_), data
+    )
+
 
 def wrapresponse(resp):
     """Wrap a response object with common error handlers.
@@ -631,21 +699,29 @@
                 if e.expected:
                     got = len(e.partial)
                     total = e.expected + got
-                    msg = _('HTTP request error (incomplete response; '
-                            'expected %d bytes got %d)') % (total, got)
+                    msg = _(
+                        'HTTP request error (incomplete response; '
+                        'expected %d bytes got %d)'
+                    ) % (total, got)
                 else:
                     msg = _('HTTP request error (incomplete response)')
 
                 raise error.PeerTransportError(
                     msg,
-                    hint=_('this may be an intermittent network failure; '
-                           'if the error persists, consider contacting the '
-                           'network or server operator'))
+                    hint=_(
+                        'this may be an intermittent network failure; '
+                        'if the error persists, consider contacting the '
+                        'network or server operator'
+                    ),
+                )
             except httplib.HTTPException as e:
                 raise error.PeerTransportError(
                     _('HTTP request error (%s)') % e,
-                    hint=_('this may be an intermittent network failure; '
-                           'if the error persists, consider contacting the '
-                           'network or server operator'))
+                    hint=_(
+                        'this may be an intermittent network failure; '
+                        'if the error persists, consider contacting the '
+                        'network or server operator'
+                    ),
+                )
 
     resp.__class__ = readerproxy