##// END OF EJS Templates
merge with stable
merge with stable

File last commit:

r45306:a50f33f1 stable
r45643:3a6ec080 merge default
Show More
url.py
728 lines | 24.2 KiB | text/x-python | PythonLexer
Benoit Boissinot
factor out the url handling from httprepo...
r7270 # url.py - HTTP handling for mercurial
#
# Copyright 2005, 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
# Copyright 2006, 2007 Alexis S. L. Carvalho <alexis@cecm.usp.br>
# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
#
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Benoit Boissinot
factor out the url handling from httprepo...
r7270
Gregory Szorc
url: use absolute_import
r25990 from __future__ import absolute_import
import base64
import os
import socket
Yuya Nishihara
url: make logginghttphandler compatible with Python 2.7.6...
r37118 import sys
Gregory Szorc
url: use absolute_import
r25990
from .i18n import _
Gregory Szorc
py3: manually import getattr where it is needed...
r43359 from .pycompat import getattr
Gregory Szorc
url: use absolute_import
r25990 from . import (
Pulkit Goyal
py3: replace pycompat.getenv with encoding.environ.get...
r30820 encoding,
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 error,
Gregory Szorc
url: use absolute_import
r25990 httpconnection as httpconnectionmod,
keepalive,
Augie Fackler
url: use native strings for header values...
r34429 pycompat,
Gregory Szorc
url: use absolute_import
r25990 sslutil,
Augie Fackler
cleanup: use urllibcompat for renamed methods on urllib request objects...
r34467 urllibcompat,
Gregory Szorc
url: use absolute_import
r25990 util,
)
Augie Fackler
formatting: blacken the codebase...
r43346 from .utils import stringutil
Pulkit Goyal
py3: conditionalize httplib import...
r29455
httplib = util.httplib
timeless
pycompat: switch to util.stringio for py3 compat
r28861 stringio = util.stringio
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 urlerr = util.urlerr
urlreq = util.urlreq
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
url: add cgi.escape equivalent for bytestrings...
r34695 def escape(s, quote=None):
'''Replace special characters "&", "<" and ">" to HTML-safe sequences.
If the optional flag quote is true, the quotation mark character (")
is also translated.
This is the same as cgi.escape in Python, but always operates on
bytes, whereas cgi.escape in Python 3 only works on unicodes.
'''
s = s.replace(b"&", b"&amp;")
s = s.replace(b"<", b"&lt;")
s = s.replace(b">", b"&gt;")
if quote:
s = s.replace(b'"', b"&quot;")
return s
Augie Fackler
formatting: blacken the codebase...
r43346
liscju
url: extract password database from password manager...
r29377 class passwordmgr(object):
def __init__(self, ui, passwddb):
Benoit Boissinot
factor out the url handling from httprepo...
r7270 self.ui = ui
liscju
url: extract password database from password manager...
r29377 self.passwddb = passwddb
def add_password(self, realm, uri, user, passwd):
return self.passwddb.add_password(realm, uri, user, passwd)
Benoit Boissinot
factor out the url handling from httprepo...
r7270
def find_user_password(self, realm, authuri):
Augie Fackler
url: add some defensive asserts on expected incoming types...
r41492 assert isinstance(realm, (type(None), str))
assert isinstance(authuri, str)
liscju
url: extract password database from password manager...
r29377 authinfo = self.passwddb.find_user_password(realm, authuri)
Benoit Boissinot
factor out the url handling from httprepo...
r7270 user, passwd = authinfo
Augie Fackler
url: convert some variables back to bytes...
r41493 user, passwd = pycompat.bytesurl(user), pycompat.bytesurl(passwd)
Benoit Boissinot
factor out the url handling from httprepo...
r7270 if user and passwd:
Sune Foldager
allow http authentication information to be specified in the configuration
r8333 self._writedebug(user, passwd)
Matt Harbison
py3: ensure the HTTP password manager returns strings, not bytes...
r41730 return (pycompat.strurl(user), pycompat.strurl(passwd))
Benoit Boissinot
factor out the url handling from httprepo...
r7270
Patrick Mezard
hgweb: do not ignore [auth] if url has a username (issue2822)...
r15005 if not user or not passwd:
Patrick Mezard
http: pass user to readauthforuri() (fix 4a43e23b8c55)...
r15025 res = httpconnectionmod.readauthforuri(self.ui, authuri, user)
Steve Borho
url: return the matched authentication group name from readauthforuri()...
r13372 if res:
group, auth = res
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 user, passwd = auth.get(b'username'), auth.get(b'password')
self.ui.debug(b"using auth.%s.* for authentication\n" % group)
Sune Foldager
allow http authentication information to be specified in the configuration
r8333 if not user or not passwd:
Augie Fackler
url: more bytes/unicodes fussing in url.py around auth handling...
r36670 u = util.url(pycompat.bytesurl(authuri))
Lucas Moscovicz
url: added authuri when login information is requested (issue3209)...
r20291 u.query = None
Sune Foldager
allow http authentication information to be specified in the configuration
r8333 if not self.ui.interactive():
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'http authorization required for %s')
Augie Fackler
formatting: blacken the codebase...
r43346 % util.hidepassword(bytes(u))
)
Benoit Boissinot
factor out the url handling from httprepo...
r7270
Augie Fackler
formatting: blacken the codebase...
r43346 self.ui.write(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"http authorization required for %s\n")
Augie Fackler
formatting: blacken the codebase...
r43346 % util.hidepassword(bytes(u))
)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.ui.write(_(b"realm: %s\n") % pycompat.bytesurl(realm))
Sune Foldager
allow http authentication information to be specified in the configuration
r8333 if user:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.ui.write(_(b"user: %s\n") % user)
Sune Foldager
allow http authentication information to be specified in the configuration
r8333 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 user = self.ui.prompt(_(b"user:"), default=None)
Benoit Boissinot
factor out the url handling from httprepo...
r7270
Sune Foldager
allow http authentication information to be specified in the configuration
r8333 if not passwd:
passwd = self.ui.getpass()
Benoit Boissinot
factor out the url handling from httprepo...
r7270
liscju
url: extract password database from password manager...
r29377 self.passwddb.add_password(realm, authuri, user, passwd)
Sune Foldager
allow http authentication information to be specified in the configuration
r8333 self._writedebug(user, passwd)
Matt Harbison
py3: ensure the HTTP password manager returns strings, not bytes...
r41730 return (pycompat.strurl(user), pycompat.strurl(passwd))
Benoit Boissinot
factor out the url handling from httprepo...
r7270
Sune Foldager
allow http authentication information to be specified in the configuration
r8333 def _writedebug(self, user, passwd):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = _(b'http auth: user %s, password %s\n')
self.ui.debug(msg % (user, passwd and b'*' * len(passwd) or b'not set'))
Sune Foldager
allow http authentication information to be specified in the configuration
r8333
Patrick Mezard
http: pass user to readauthforuri() (fix 4a43e23b8c55)...
r15025 def find_stored_password(self, authuri):
liscju
url: extract password database from password manager...
r29377 return self.passwddb.find_user_password(None, authuri)
Patrick Mezard
http: pass user to readauthforuri() (fix 4a43e23b8c55)...
r15025
Augie Fackler
formatting: blacken the codebase...
r43346
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 class proxyhandler(urlreq.proxyhandler):
Benoit Boissinot
factor out the url handling from httprepo...
r7270 def __init__(self, ui):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 proxyurl = ui.config(b"http_proxy", b"host") or encoding.environ.get(
b'http_proxy'
Augie Fackler
formatting: blacken the codebase...
r43346 )
Benoit Boissinot
factor out the url handling from httprepo...
r7270 # XXX proxyauthinfo = None
if proxyurl:
# proxy can be proper url or host[:port]
Augie Fackler
formatting: blacken the codebase...
r43346 if not (
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 proxyurl.startswith(b'http:') or proxyurl.startswith(b'https:')
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 proxyurl = b'http://' + proxyurl + b'/'
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 proxy = util.url(proxyurl)
Brodie Rao
url: use url.url in proxyhandler
r13820 if not proxy.user:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 proxy.user = ui.config(b"http_proxy", b"user")
proxy.passwd = ui.config(b"http_proxy", b"passwd")
Benoit Boissinot
factor out the url handling from httprepo...
r7270
# see if we should use a proxy for this url
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 no_list = [b"localhost", b"127.0.0.1"]
Augie Fackler
formatting: blacken the codebase...
r43346 no_list.extend(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 [p.lower() for p in ui.configlist(b"http_proxy", b"no")]
Augie Fackler
formatting: blacken the codebase...
r43346 )
no_list.extend(
[
p.strip().lower()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for p in encoding.environ.get(b"no_proxy", b'').split(b',')
Augie Fackler
formatting: blacken the codebase...
r43346 if p.strip()
]
)
Benoit Boissinot
factor out the url handling from httprepo...
r7270 # "http_proxy.always" config is for running tests on localhost
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if ui.configbool(b"http_proxy", b"always"):
Benoit Boissinot
factor out the url handling from httprepo...
r7270 self.no_list = []
else:
self.no_list = no_list
Gregory Szorc
url: always use str for proxy configuration...
r41859 # Keys and values need to be str because the standard library
# expects them to be.
proxyurl = str(proxy)
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 proxies = {'http': proxyurl, 'https': proxyurl}
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.debug(b'proxying through %s\n' % util.hidepassword(bytes(proxy)))
Benoit Boissinot
factor out the url handling from httprepo...
r7270 else:
proxies = {}
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 urlreq.proxyhandler.__init__(self, proxies)
Benoit Boissinot
factor out the url handling from httprepo...
r7270 self.ui = ui
def proxy_open(self, req, proxy, type_):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 host = pycompat.bytesurl(urllibcompat.gethost(req)).split(b':')[0]
Matt Mackall
proxy: allow wildcards in the no proxy list (issue1821)
r19535 for e in self.no_list:
if host == e:
return None
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if e.startswith(b'*.') and host.endswith(e[2:]):
Matt Mackall
proxy: allow wildcards in the no proxy list (issue1821)
r19535 return None
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if e.startswith(b'.') and host.endswith(e[1:]):
Matt Mackall
proxy: allow wildcards in the no proxy list (issue1821)
r19535 return None
Benoit Boissinot
factor out the url handling from httprepo...
r7270
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 return urlreq.proxyhandler.proxy_open(self, req, proxy, type_)
Benoit Boissinot
factor out the url handling from httprepo...
r7270
Augie Fackler
formatting: blacken the codebase...
r43346
Mads Kiilerich
url: refactor _gen_sendfile
r13420 def _gen_sendfile(orgsend):
Benoit Boissinot
factor out the url handling from httprepo...
r7270 def _sendfile(self, data):
# send a file
Augie Fackler
url: use new http support if requested by the user...
r14244 if isinstance(data, httpconnectionmod.httpsendfile):
Benoit Boissinot
factor out the url handling from httprepo...
r7270 # if auth required, some data sent twice, so rewind here
data.seek(0)
for chunk in util.filechunkiter(data):
Mads Kiilerich
url: refactor _gen_sendfile
r13420 orgsend(self, chunk)
Benoit Boissinot
factor out the url handling from httprepo...
r7270 else:
Mads Kiilerich
url: refactor _gen_sendfile
r13420 orgsend(self, data)
Augie Fackler
formatting: blacken the codebase...
r43346
Benoit Boissinot
factor out the url handling from httprepo...
r7270 return _sendfile
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 has_https = util.safehasattr(urlreq, b'httpshandler')
Henrik Stuart
url: SSL server certificate verification using web.cacerts file (issue1174)
r10409
Augie Fackler
formatting: blacken the codebase...
r43346
Benoit Boissinot
factor out the url handling from httprepo...
r7270 class httpconnection(keepalive.HTTPConnection):
# must be able to send big bundle as stream.
Mads Kiilerich
url: refactor _gen_sendfile
r13420 send = _gen_sendfile(keepalive.HTTPConnection.send)
Benoit Boissinot
factor out the url handling from httprepo...
r7270
Henrik Stuart
url: use CONNECT for HTTPS connections through HTTP proxy (issue967)...
r8590 def getresponse(self):
proxyres = getattr(self, 'proxyres', None)
if proxyres:
if proxyres.will_close:
self.close()
self.proxyres = None
return proxyres
return keepalive.HTTPConnection.getresponse(self)
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
url: always access req._tunnel_host...
r41857 # Large parts of this function have their origin from before Python 2.6
# and could potentially be removed.
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852 def _generic_start_transaction(handler, h, req):
Gregory Szorc
url: always access req._tunnel_host...
r41857 tunnel_host = req._tunnel_host
Augie Fackler
url: replace uses of hasattr with safehasattr or getattr
r14964 if tunnel_host:
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 if tunnel_host[:7] not in ['http://', 'https:/']:
tunnel_host = 'https://' + tunnel_host
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852 new_tunnel = True
else:
Augie Fackler
cleanup: use urllibcompat for renamed methods on urllib request objects...
r34467 tunnel_host = urllibcompat.getselector(req)
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852 new_tunnel = False
Augie Fackler
formatting: blacken the codebase...
r43346 if new_tunnel or tunnel_host == urllibcompat.getfullurl(req): # has proxy
Gregory Szorc
url: always use str for proxy configuration...
r41859 u = util.url(pycompat.bytesurl(tunnel_host))
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if new_tunnel or u.scheme == b'https': # only use CONNECT for HTTPS
h.realhostport = b':'.join([u.host, (u.port or b'443')])
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852 h.headers = req.headers.copy()
h.headers.update(handler.parent.addheaders)
return
Benoit Boissinot
url: proxy handling, simplify and correctly deal with IPv6...
r10415 h.realhostport = None
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852 h.headers = None
Augie Fackler
formatting: blacken the codebase...
r43346
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852 def _generic_proxytunnel(self):
Augie Fackler
cleanup: run pyupgrade on our source tree to clean up varying things...
r44937 proxyheaders = {
Matt Harbison
url: fix a bytes vs str crash in processing proxy headers (issue6249)...
r45306 pycompat.bytestr(x): pycompat.bytestr(self.headers[x])
Augie Fackler
cleanup: run pyupgrade on our source tree to clean up varying things...
r44937 for x in self.headers
if x.lower().startswith('proxy-')
}
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.send(b'CONNECT %s HTTP/1.0\r\n' % self.realhostport)
Gregory Szorc
py3: finish porting iteritems() to pycompat and remove source transformer...
r43376 for header in pycompat.iteritems(proxyheaders):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.send(b'%s: %s\r\n' % header)
self.send(b'\r\n')
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852
# majority of the following code is duplicated from
# httplib.HTTPConnection as there are no adequate places to
# override functions to provide the needed functionality
Gregory Szorc
url: don't pass strict argument on Python 3...
r41860 # strict was removed in Python 3.4.
kwargs = {}
if not pycompat.ispy3:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 kwargs[b'strict'] = self.strict
Gregory Szorc
url: don't pass strict argument on Python 3...
r41860
Augie Fackler
formatting: blacken the codebase...
r43346 res = self.response_class(self.sock, method=self._method, **kwargs)
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852
while True:
version, status, reason = res._read_status()
if status != httplib.CONTINUE:
break
Augie Fackler
url: use `iter(callable, sentinel)` instead of while True...
r29729 # skip lines that are all whitespace
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 list(iter(lambda: res.fp.readline().strip(), b''))
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852 res.status = status
res.reason = reason.strip()
if res.status == 200:
Augie Fackler
url: use `iter(callable, sentinel)` instead of while True...
r29729 # skip lines until we find a blank line
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 list(iter(res.fp.readline, b'\r\n'))
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852 return True
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if version == b'HTTP/1.0':
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852 res.version = 10
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif version.startswith(b'HTTP/1.'):
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852 res.version = 11
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif version == b'HTTP/0.9':
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852 res.version = 9
else:
raise httplib.UnknownProtocol(version)
if res.version == 9:
res.length = None
res.chunked = 0
res.will_close = 1
timeless
pycompat: switch to util.stringio for py3 compat
r28861 res.msg = httplib.HTTPMessage(stringio())
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852 return False
res.msg = httplib.HTTPMessage(res.fp)
res.msg.fp = None
# are we using the chunked-style of transfer encoding?
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 trenc = res.msg.getheader(b'transfer-encoding')
if trenc and trenc.lower() == b"chunked":
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852 res.chunked = 1
res.chunk_left = None
else:
res.chunked = 0
# will the connection close at the end of the response?
res.will_close = res._check_close()
# do we have a Content-Length?
Mads Kiilerich
avoid using abbreviations that look like spelling errors
r17428 # NOTE: RFC 2616, section 4.4, #3 says we ignore this if
# transfer-encoding is "chunked"
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 length = res.msg.getheader(b'content-length')
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852 if length and not res.chunked:
try:
res.length = int(length)
except ValueError:
res.length = None
else:
if res.length < 0: # ignore nonsensical negative lengths
res.length = None
else:
res.length = None
# does the body have a fixed length? (of zero)
Augie Fackler
formatting: blacken the codebase...
r43346 if (
status == httplib.NO_CONTENT
or status == httplib.NOT_MODIFIED
or 100 <= status < 200
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 or res._method == b'HEAD' # 1xx codes
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852 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.
Augie Fackler
formatting: blacken the codebase...
r43346 if not res.will_close and not res.chunked and res.length is None:
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852 res.will_close = 1
self.proxyres = res
return False
Augie Fackler
formatting: blacken the codebase...
r43346
Benoit Boissinot
factor out the url handling from httprepo...
r7270 class httphandler(keepalive.HTTPHandler):
def http_open(self, req):
return self.do_open(httpconnection, req)
Henrik Stuart
url: use CONNECT for HTTPS connections through HTTP proxy (issue967)...
r8590 def _start_transaction(self, h, req):
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852 _generic_start_transaction(self, h, req)
Henrik Stuart
url: use CONNECT for HTTPS connections through HTTP proxy (issue967)...
r8590 return keepalive.HTTPHandler._start_transaction(self, h, req)
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
url: add HTTP handler that uses a proxied socket...
r37029 class logginghttpconnection(keepalive.HTTPConnection):
def __init__(self, createconn, *args, **kwargs):
keepalive.HTTPConnection.__init__(self, *args, **kwargs)
self._create_connection = createconn
Yuya Nishihara
url: make logginghttphandler compatible with Python 2.7.6...
r37118 if sys.version_info < (2, 7, 7):
# copied from 2.7.14, since old implementations directly call
# socket.create_connection()
def connect(self):
Augie Fackler
formatting: blacken the codebase...
r43346 self.sock = self._create_connection(
(self.host, self.port), self.timeout, self.source_address
)
Yuya Nishihara
url: make logginghttphandler compatible with Python 2.7.6...
r37118 if self._tunnel_host:
self._tunnel()
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
url: add HTTP handler that uses a proxied socket...
r37029 class logginghttphandler(httphandler):
"""HTTP handler that logs socket I/O."""
Augie Fackler
formatting: blacken the codebase...
r43346
Cédric Krier
url: allow to configure timeout on http connection...
r40079 def __init__(self, logfh, name, observeropts, timeout=None):
super(logginghttphandler, self).__init__(timeout=timeout)
Gregory Szorc
url: add HTTP handler that uses a proxied socket...
r37029
self._logfh = logfh
self._logname = name
self._observeropts = observeropts
# do_open() calls the passed class to instantiate an HTTPConnection. We
# pass in a callable method that creates a custom HTTPConnection instance
# whose callback to create the socket knows how to proxy the socket.
def http_open(self, req):
return self.do_open(self._makeconnection, req)
def _makeconnection(self, *args, **kwargs):
def createconnection(*args, **kwargs):
sock = socket.create_connection(*args, **kwargs)
Augie Fackler
formatting: blacken the codebase...
r43346 return util.makeloggingsocket(
self._logfh, sock, self._logname, **self._observeropts
)
Gregory Szorc
url: add HTTP handler that uses a proxied socket...
r37029
return logginghttpconnection(createconnection, *args, **kwargs)
Augie Fackler
formatting: blacken the codebase...
r43346
Benoit Boissinot
factor out the url handling from httprepo...
r7270 if has_https:
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
url: have httpsconnection inherit from our custom HTTPConnection...
r40067 class httpsconnection(keepalive.HTTPConnection):
Mads Kiilerich
url: merge BetterHTTPS with httpsconnection to get some proxy https validation
r13424 response_class = keepalive.HTTPResponse
Yuya Nishihara
https: do not inherit httplib.HTTPSConnection that creates unused SSLContext...
r25414 default_port = httplib.HTTPS_PORT
Mads Kiilerich
url: merge BetterHTTPS with httpsconnection to get some proxy https validation
r13424 # must be able to send big bundle as stream.
send = _gen_sendfile(keepalive.safesend)
Yuya Nishihara
https: do not inherit httplib.HTTPSConnection that creates unused SSLContext...
r25414 getresponse = keepalive.wrapgetresponse(httplib.HTTPConnection)
Augie Fackler
formatting: blacken the codebase...
r43346 def __init__(
self,
host,
port=None,
key_file=None,
cert_file=None,
*args,
**kwargs
):
Gregory Szorc
url: have httpsconnection inherit from our custom HTTPConnection...
r40067 keepalive.HTTPConnection.__init__(self, host, port, *args, **kwargs)
Yuya Nishihara
https: do not inherit httplib.HTTPSConnection that creates unused SSLContext...
r25414 self.key_file = key_file
self.cert_file = cert_file
Augie Fackler
keepalive: handle broken pipes gracefully during large POSTs
r9726
Henrik Stuart
url: SSL server certificate verification using web.cacerts file (issue1174)
r10409 def connect(self):
Yuya Nishihara
url: drop compatibility wrapper of socket.create_connection()...
r29662 self.sock = socket.create_connection((self.host, self.port))
Mads Kiilerich
url: always create BetterHTTPS connections the same way
r13422
Mads Kiilerich
url: refactor BetterHTTPS.connect
r13421 host = self.host
Augie Fackler
formatting: blacken the codebase...
r43346 if self.realhostport: # use CONNECT proxy
Alexander Solovyov
remove unused imports and variables
r14064 _generic_proxytunnel(self)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 host = self.realhostport.rsplit(b':', 1)[0]
Yuya Nishihara
ssl: rename ssl_wrap_socket() to conform to our naming convention...
r25429 self.sock = sslutil.wrapsocket(
Augie Fackler
formatting: blacken the codebase...
r43346 self.sock,
self.key_file,
self.cert_file,
ui=self.ui,
serverhostname=host,
)
Gregory Szorc
sslutil: convert socket validation from a class to a function (API)...
r29227 sslutil.validatesocket(self.sock)
Henrik Stuart
url: SSL server certificate verification using web.cacerts file (issue1174)
r10409
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 class httpshandler(keepalive.KeepAliveHandler, urlreq.httpshandler):
Cédric Krier
url: allow to configure timeout on http connection...
r40079 def __init__(self, ui, timeout=None):
keepalive.KeepAliveHandler.__init__(self, timeout=timeout)
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 urlreq.httpshandler.__init__(self)
Henrik Stuart
url: support client certificate files over HTTPS (issue643)...
r8847 self.ui = ui
Augie Fackler
formatting: blacken the codebase...
r43346 self.pwmgr = passwordmgr(self.ui, self.ui.httppasswordmgrdb)
Henrik Stuart
url: support client certificate files over HTTPS (issue643)...
r8847
Henrik Stuart
url: generalise HTTPS proxy handling to accomodate Python changes...
r9852 def _start_transaction(self, h, req):
_generic_start_transaction(self, h, req)
return keepalive.KeepAliveHandler._start_transaction(self, h, req)
Benoit Boissinot
factor out the url handling from httprepo...
r7270 def https_open(self, req):
Augie Fackler
cleanup: use urllibcompat for renamed methods on urllib request objects...
r34467 # urllibcompat.getfullurl() does not contain credentials
# and we may need them to match the certificates.
url = urllibcompat.getfullurl(req)
Patrick Mezard
http: pass user to readauthforuri() (fix 4a43e23b8c55)...
r15025 user, password = self.pwmgr.find_stored_password(url)
res = httpconnectionmod.readauthforuri(self.ui, url, user)
Steve Borho
url: return the matched authentication group name from readauthforuri()...
r13372 if res:
group, auth = res
self.auth = auth
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.ui.debug(b"using auth.%s.* for authentication\n" % group)
Steve Borho
url: return the matched authentication group name from readauthforuri()...
r13372 else:
self.auth = None
Henrik Stuart
url: support client certificate files over HTTPS (issue643)...
r8847 return self.do_open(self._makeconnection, req)
Benoit Boissinot
url: httplib.HTTPSConnection already handles IPv6 and port parsing fine
r10408 def _makeconnection(self, host, port=None, *args, **kwargs):
Henrik Stuart
url: support client certificate files over HTTPS (issue643)...
r8847 keyfile = None
certfile = None
Augie Fackler
formatting: blacken the codebase...
r43346 if len(args) >= 1: # key_file
Benoit Boissinot
url: *args argument is a tuple, not a list (found by pylint)...
r10511 keyfile = args[0]
Augie Fackler
formatting: blacken the codebase...
r43346 if len(args) >= 2: # cert_file
Benoit Boissinot
url: *args argument is a tuple, not a list (found by pylint)...
r10511 certfile = args[1]
args = args[2:]
Henrik Stuart
url: support client certificate files over HTTPS (issue643)...
r8847
# if the user has specified different key/cert files in
# hgrc, we prefer these
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if self.auth and b'key' in self.auth and b'cert' in self.auth:
keyfile = self.auth[b'key']
certfile = self.auth[b'cert']
Henrik Stuart
url: support client certificate files over HTTPS (issue643)...
r8847
Augie Fackler
formatting: blacken the codebase...
r43346 conn = httpsconnection(
host, port, keyfile, certfile, *args, **kwargs
)
Henrik Stuart
url: SSL server certificate verification using web.cacerts file (issue1174)
r10409 conn.ui = self.ui
return conn
Benoit Boissinot
factor out the url handling from httprepo...
r7270
Augie Fackler
formatting: blacken the codebase...
r43346
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 class httpdigestauthhandler(urlreq.httpdigestauthhandler):
Mads Kiilerich
http digest auth: reset redirect counter on new requests (issue2255)...
r11457 def __init__(self, *args, **kwargs):
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 urlreq.httpdigestauthhandler.__init__(self, *args, **kwargs)
Mads Kiilerich
http digest auth: reset redirect counter on new requests (issue2255)...
r11457 self.retried_req = None
def reset_retry_count(self):
# Python 2.6.5 will call this on 401 or 407 errors and thus loop
# forever. We disable reset_retry_count completely and reset in
# http_error_auth_reqed instead.
pass
Benoit Boissinot
factor out the url handling from httprepo...
r7270 def http_error_auth_reqed(self, auth_header, host, req, headers):
Mads Kiilerich
http digest auth: reset redirect counter on new requests (issue2255)...
r11457 # Reset the retry counter once for each request.
if req is not self.retried_req:
self.retried_req = req
self.retried = 0
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 return urlreq.httpdigestauthhandler.http_error_auth_reqed(
Augie Fackler
formatting: blacken the codebase...
r43346 self, auth_header, host, req, headers
)
Benoit Boissinot
factor out the url handling from httprepo...
r7270
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 class httpbasicauthhandler(urlreq.httpbasicauthhandler):
Wagner Bruna
http basic auth: reset redirect counter on new requests (issue2255)...
r11844 def __init__(self, *args, **kwargs):
Stéphane Klein
http: reuse authentication info after the first failed request (issue3567)...
r20964 self.auth = None
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 urlreq.httpbasicauthhandler.__init__(self, *args, **kwargs)
Wagner Bruna
http basic auth: reset redirect counter on new requests (issue2255)...
r11844 self.retried_req = None
Stéphane Klein
http: reuse authentication info after the first failed request (issue3567)...
r20964 def http_request(self, request):
if self.auth:
request.add_unredirected_header(self.auth_header, self.auth)
return request
def https_request(self, request):
if self.auth:
request.add_unredirected_header(self.auth_header, self.auth)
return request
Wagner Bruna
http basic auth: reset redirect counter on new requests (issue2255)...
r11844 def reset_retry_count(self):
# Python 2.6.5 will call this on 401 or 407 errors and thus loop
# forever. We disable reset_retry_count completely and reset in
# http_error_auth_reqed instead.
pass
def http_error_auth_reqed(self, auth_header, host, req, headers):
# Reset the retry counter once for each request.
if req is not self.retried_req:
self.retried_req = req
self.retried = 0
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 return urlreq.httpbasicauthhandler.http_error_auth_reqed(
Augie Fackler
formatting: blacken the codebase...
r43346 self, auth_header, host, req, headers
)
Wagner Bruna
http basic auth: reset redirect counter on new requests (issue2255)...
r11844
Stéphane Klein
http: reuse authentication info after the first failed request (issue3567)...
r20964 def retry_http_basic_auth(self, host, req, realm):
Augie Fackler
cleanup: use urllibcompat for renamed methods on urllib request objects...
r34467 user, pw = self.passwd.find_user_password(
Augie Fackler
formatting: blacken the codebase...
r43346 realm, urllibcompat.getfullurl(req)
)
Stéphane Klein
http: reuse authentication info after the first failed request (issue3567)...
r20964 if pw is not None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raw = b"%s:%s" % (pycompat.bytesurl(user), pycompat.bytesurl(pw))
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 auth = 'Basic %s' % pycompat.strurl(base64.b64encode(raw).strip())
Kim Randell
url: avoid re-issuing incorrect password (issue3210)...
r29639 if req.get_header(self.auth_header, None) == auth:
Stéphane Klein
http: reuse authentication info after the first failed request (issue3567)...
r20964 return None
self.auth = auth
req.add_unredirected_header(self.auth_header, auth)
return self.parent.open(req)
else:
return None
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
url: support auth.cookiesfile for adding cookies to HTTP requests...
r31936 class cookiehandler(urlreq.basehandler):
def __init__(self, ui):
self.cookiejar = None
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cookiefile = ui.config(b'auth', b'cookiefile')
Gregory Szorc
url: support auth.cookiesfile for adding cookies to HTTP requests...
r31936 if not cookiefile:
return
cookiefile = util.expandpath(cookiefile)
try:
Augie Fackler
url: some bytes/str cleanup where we interface with stdlib funcs...
r37753 cookiejar = util.cookielib.MozillaCookieJar(
Augie Fackler
formatting: blacken the codebase...
r43346 pycompat.fsdecode(cookiefile)
)
Gregory Szorc
url: support auth.cookiesfile for adding cookies to HTTP requests...
r31936 cookiejar.load()
self.cookiejar = cookiejar
except util.cookielib.LoadError as e:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.warn(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'(error loading cookie file %s: %s; continuing without '
b'cookies)\n'
Augie Fackler
formatting: blacken the codebase...
r43346 )
% (cookiefile, stringutil.forcebytestr(e))
)
Gregory Szorc
url: support auth.cookiesfile for adding cookies to HTTP requests...
r31936
def http_request(self, request):
if self.cookiejar:
self.cookiejar.add_cookie_header(request)
return request
def https_request(self, request):
if self.cookiejar:
self.cookiejar.add_cookie_header(request)
return request
Augie Fackler
formatting: blacken the codebase...
r43346
Henrik Stuart
url: add support for custom handlers in extensions
r9347 handlerfuncs = []
Augie Fackler
formatting: blacken the codebase...
r43346
def opener(
ui,
authinfo=None,
useragent=None,
loggingfh=None,
loggingname=b's',
loggingopts=None,
sendaccept=True,
):
Benoit Boissinot
factor out the url handling from httprepo...
r7270 '''
construct an opener suitable for urllib2
authinfo will be added to the password manager
Gregory Szorc
url: add HTTP handler that uses a proxied socket...
r37029
The opener can be configured to log socket events if the various
``logging*`` arguments are specified.
``loggingfh`` denotes a file object to log events to.
``loggingname`` denotes the name of the to print when logging.
``loggingopts`` is a dict of keyword arguments to pass to the constructed
``util.socketobserver`` instance.
Gregory Szorc
url: support suppressing Accept header...
r37063
``sendaccept`` allows controlling whether the ``Accept`` request header
is sent. The header is sent by default.
Benoit Boissinot
factor out the url handling from httprepo...
r7270 '''
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 timeout = ui.configwith(float, b'http', b'timeout')
Gregory Szorc
url: add HTTP handler that uses a proxied socket...
r37029 handlers = []
if loggingfh:
Augie Fackler
formatting: blacken the codebase...
r43346 handlers.append(
logginghttphandler(
loggingfh, loggingname, loggingopts or {}, timeout=timeout
)
)
Gregory Szorc
url: add HTTP handler that uses a proxied socket...
r37029 # 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.
else:
Cédric Krier
url: allow to configure timeout on http connection...
r40079 handlers.append(httphandler(timeout=timeout))
Gregory Szorc
url: add HTTP handler that uses a proxied socket...
r37029 if has_https:
Cédric Krier
url: allow to configure timeout on http connection...
r40079 handlers.append(httpshandler(ui, timeout=timeout))
Benoit Boissinot
factor out the url handling from httprepo...
r7270
handlers.append(proxyhandler(ui))
liscju
url: remember http password database in ui object...
r29378 passmgr = passwordmgr(ui, ui.httppasswordmgrdb)
Benoit Boissinot
factor out the url handling from httprepo...
r7270 if authinfo is not None:
liscju
largefiles: make cloning not ask two times about password (issue4883)...
r29379 realm, uris, user, passwd = authinfo
saveduser, savedpass = passmgr.find_stored_password(uris[0])
if user != saveduser or passwd:
passmgr.add_password(realm, uris, user, passwd)
Augie Fackler
formatting: blacken the codebase...
r43346 ui.debug(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'http auth: user %s, password %s\n'
% (user, passwd and b'*' * len(passwd) or b'not set')
Augie Fackler
formatting: blacken the codebase...
r43346 )
Benoit Boissinot
factor out the url handling from httprepo...
r7270
Augie Fackler
formatting: blacken the codebase...
r43346 handlers.extend(
(httpbasicauthhandler(passmgr), httpdigestauthhandler(passmgr))
)
Henrik Stuart
url: add support for custom handlers in extensions
r9347 handlers.extend([h(ui, passmgr) for h in handlerfuncs])
Gregory Szorc
url: support auth.cookiesfile for adding cookies to HTTP requests...
r31936 handlers.append(cookiehandler(ui))
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 opener = urlreq.buildopener(*handlers)
Benoit Boissinot
factor out the url handling from httprepo...
r7270
Gregory Szorc
httppeer: report http statistics...
r40070 # keepalive.py's handlers will populate these attributes if they exist.
opener.requestscount = 0
opener.sentbytescount = 0
opener.receivedbytescount = 0
Gregory Szorc
url: add distribution and version to user-agent request header (BC)...
r29589 # The user agent should should *NOT* be used by servers for e.g.
# protocol detection or feature negotiation: there are other
# facilities for that.
#
# "mercurial/proto-1.0" was the original user agent string and
# exists for backwards compatibility reasons.
#
# The "(Mercurial %s)" string contains the distribution
# name and version. Other client implementations should choose their
# own distribution name. Since servers should not be using the user
# agent string for anything, clients should be able to define whatever
# user agent they deem appropriate.
Matt Harbison
lfs: add git to the User-Agent header for blob transfers...
r35455 #
# The custom user agent is for lfs, because unfortunately some servers
# do look at this value.
if not useragent:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 agent = b'mercurial/proto-1.0 (Mercurial %s)' % util.version()
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 opener.addheaders = [('User-agent', pycompat.sysstr(agent))]
Matt Harbison
lfs: add git to the User-Agent header for blob transfers...
r35455 else:
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 opener.addheaders = [('User-agent', pycompat.sysstr(useragent))]
Gregory Szorc
httppeer: advertise and support application/mercurial-0.2...
r30763
# This header should only be needed by wire protocol requests. But it has
# been sent on all requests since forever. We keep sending it for backwards
# compatibility reasons. Modern versions of the wire protocol use
# X-HgProto-<N> for advertising client support.
Gregory Szorc
url: support suppressing Accept header...
r37063 if sendaccept:
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 opener.addheaders.append(('Accept', 'application/mercurial-0.1'))
Gregory Szorc
url: support suppressing Accept header...
r37063
Benoit Boissinot
factor out the url handling from httprepo...
r7270 return opener
Augie Fackler
formatting: blacken the codebase...
r43346
timeless
import: suppress accept: header...
r42278 def open(ui, url_, data=None, sendaccept=True):
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 u = util.url(url_)
Brodie Rao
url: use url.url in url.open()
r13818 if u.scheme:
u.scheme = u.scheme.lower()
url_, authinfo = u.authinfo()
else:
path = util.normpath(os.path.abspath(url_))
Gregory Szorc
url: pass str to pathname2url...
r45131 url_ = b'file://' + pycompat.bytesurl(
urlreq.pathname2url(pycompat.fsdecode(path))
)
Patrick Mezard
url: fix file:// URL handling
r7284 authinfo = None
Augie Fackler
formatting: blacken the codebase...
r43346 return opener(ui, authinfo, sendaccept=sendaccept).open(
pycompat.strurl(url_), data
)
Gregory Szorc
url: move _wraphttpresponse() from httpeer...
r40054
def wrapresponse(resp):
"""Wrap a response object with common error handlers.
This ensures that any I/O from any consumer raises the appropriate
error and messaging.
"""
origread = resp.read
class readerproxy(resp.__class__):
def read(self, size=None):
try:
return origread(size)
except httplib.IncompleteRead as e:
# e.expected is an integer if length known or None otherwise.
if e.expected:
got = len(e.partial)
total = e.expected + got
Augie Fackler
formatting: blacken the codebase...
r43346 msg = _(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'HTTP request error (incomplete response; '
b'expected %d bytes got %d)'
Augie Fackler
formatting: blacken the codebase...
r43346 ) % (total, got)
Gregory Szorc
url: move _wraphttpresponse() from httpeer...
r40054 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = _(b'HTTP request error (incomplete response)')
Gregory Szorc
url: move _wraphttpresponse() from httpeer...
r40054
raise error.PeerTransportError(
msg,
Augie Fackler
formatting: blacken the codebase...
r43346 hint=_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'this may be an intermittent network failure; '
b'if the error persists, consider contacting the '
b'network or server operator'
Augie Fackler
formatting: blacken the codebase...
r43346 ),
)
Gregory Szorc
url: move _wraphttpresponse() from httpeer...
r40054 except httplib.HTTPException as e:
raise error.PeerTransportError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'HTTP request error (%s)') % e,
Augie Fackler
formatting: blacken the codebase...
r43346 hint=_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'this may be an intermittent network failure; '
b'if the error persists, consider contacting the '
b'network or server operator'
Augie Fackler
formatting: blacken the codebase...
r43346 ),
)
Gregory Szorc
url: move _wraphttpresponse() from httpeer...
r40054
resp.__class__ = readerproxy