--- 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""")
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