--- a/mercurial/httpconnection.py Sun Feb 25 23:34:58 2018 -0500
+++ b/mercurial/httpconnection.py Sun Feb 25 23:51:32 2018 -0500
@@ -10,15 +10,10 @@
from __future__ import absolute_import
-import logging
import os
-import socket
from .i18n import _
from . import (
- httpclient,
- sslutil,
- urllibcompat,
util,
)
@@ -110,190 +105,3 @@
if user and not bestuser:
auth['username'] = user
return bestauth
-
-# Mercurial (at least until we can remove the old codepath) requires
-# that the http response object be sufficiently file-like, so we
-# provide a close() method here.
-class HTTPResponse(httpclient.HTTPResponse):
- def close(self):
- pass
-
-class HTTPConnection(httpclient.HTTPConnection):
- response_class = HTTPResponse
- def request(self, method, uri, body=None, headers=None):
- if headers is None:
- headers = {}
- if isinstance(body, httpsendfile):
- body.seek(0)
- httpclient.HTTPConnection.request(self, method, uri, body=body,
- headers=headers)
-
-
-_configuredlogging = False
-LOGFMT = '%(levelname)s:%(name)s:%(lineno)d:%(message)s'
-# Subclass BOTH of these because otherwise urllib2 "helpfully"
-# reinserts them since it notices we don't include any subclasses of
-# them.
-class http2handler(urlreq.httphandler, urlreq.httpshandler):
- def __init__(self, ui, pwmgr):
- global _configuredlogging
- urlreq.abstracthttphandler.__init__(self)
- self.ui = ui
- self.pwmgr = pwmgr
- self._connections = {}
- # developer config: ui.http2debuglevel
- loglevel = ui.config('ui', 'http2debuglevel')
- if loglevel and not _configuredlogging:
- _configuredlogging = True
- logger = logging.getLogger('mercurial.httpclient')
- logger.setLevel(getattr(logging, loglevel.upper()))
- handler = logging.StreamHandler()
- handler.setFormatter(logging.Formatter(LOGFMT))
- logger.addHandler(handler)
-
- def close_all(self):
- """Close and remove all connection objects being kept for reuse."""
- for openconns in self._connections.values():
- for conn in openconns:
- conn.close()
- self._connections = {}
-
- # shamelessly borrowed from urllib2.AbstractHTTPHandler
- def do_open(self, http_class, req, use_ssl):
- """Return an addinfourl object for the request, using http_class.
-
- http_class must implement the HTTPConnection API from httplib.
- The addinfourl return value is a file-like object. It also
- has methods and attributes including:
- - info(): return a mimetools.Message object for the headers
- - geturl(): return the original request URL
- - code: HTTP status code
- """
- # If using a proxy, the host returned by get_host() is
- # actually the proxy. On Python 2.6.1, the real destination
- # hostname is encoded in the URI in the urllib2 request
- # object. On Python 2.6.5, it's stored in the _tunnel_host
- # attribute which has no accessor.
- tunhost = getattr(req, '_tunnel_host', None)
- host = urllibcompat.gethost(req)
- if tunhost:
- proxyhost = host
- host = tunhost
- elif req.has_proxy():
- proxyhost = urllibcompat.gethost(req)
- host = urllibcompat.getselector(
- req).split('://', 1)[1].split('/', 1)[0]
- else:
- proxyhost = None
-
- if proxyhost:
- if ':' in proxyhost:
- # Note: this means we'll explode if we try and use an
- # IPv6 http proxy. This isn't a regression, so we
- # won't worry about it for now.
- proxyhost, proxyport = proxyhost.rsplit(':', 1)
- else:
- proxyport = 3128 # squid default
- proxy = (proxyhost, proxyport)
- else:
- proxy = None
-
- if not host:
- raise urlerr.urlerror('no host given')
-
- connkey = use_ssl, host, proxy
- allconns = self._connections.get(connkey, [])
- conns = [c for c in allconns if not c.busy()]
- if conns:
- h = conns[0]
- else:
- if allconns:
- self.ui.debug('all connections for %s busy, making a new '
- 'one\n' % host)
- timeout = None
- if req.timeout is not socket._GLOBAL_DEFAULT_TIMEOUT:
- timeout = req.timeout
- h = http_class(host, timeout=timeout, proxy_hostport=proxy)
- self._connections.setdefault(connkey, []).append(h)
-
- headers = dict(req.headers)
- headers.update(req.unredirected_hdrs)
- headers = dict(
- (name.title(), val) for name, val in headers.items())
- try:
- path = urllibcompat.getselector(req)
- if '://' in path:
- path = path.split('://', 1)[1].split('/', 1)[1]
- if path[0] != '/':
- path = '/' + path
- h.request(req.get_method(), path, req.data, headers)
- r = h.getresponse()
- except socket.error as err: # XXX what error?
- raise urlerr.urlerror(err)
-
- # Pick apart the HTTPResponse object to get the addinfourl
- # object initialized properly.
- r.recv = r.read
-
- resp = urlreq.addinfourl(r, r.headers, urllibcompat.getfullurl(req))
- resp.code = r.status
- resp.msg = r.reason
- return resp
-
- # httplib always uses the given host/port as the socket connect
- # target, and then allows full URIs in the request path, which it
- # then observes and treats as a signal to do proxying instead.
- def http_open(self, req):
- if urllibcompat.getfullurl(req).startswith('https'):
- return self.https_open(req)
- def makehttpcon(*args, **kwargs):
- k2 = dict(kwargs)
- k2[r'use_ssl'] = False
- return HTTPConnection(*args, **k2)
- return self.do_open(makehttpcon, req, False)
-
- def https_open(self, req):
- # urllibcompat.getfullurl(req) does not contain credentials and we may
- # need them to match the certificates.
- url = urllibcompat.getfullurl(req)
- user, password = self.pwmgr.find_stored_password(url)
- res = readauthforuri(self.ui, url, user)
- if res:
- group, auth = res
- self.auth = auth
- self.ui.debug("using auth.%s.* for authentication\n" % group)
- else:
- self.auth = None
- return self.do_open(self._makesslconnection, req, True)
-
- def _makesslconnection(self, host, port=443, *args, **kwargs):
- keyfile = None
- certfile = None
-
- if args: # key_file
- keyfile = args.pop(0)
- if args: # cert_file
- certfile = args.pop(0)
-
- # if the user has specified different key/cert files in
- # hgrc, we prefer these
- if self.auth and 'key' in self.auth and 'cert' in self.auth:
- keyfile = self.auth['key']
- certfile = self.auth['cert']
-
- # let host port take precedence
- if ':' in host and '[' not in host or ']:' in host:
- host, port = host.rsplit(':', 1)
- port = int(port)
- if '[' in host:
- host = host[1:-1]
-
- kwargs[r'keyfile'] = keyfile
- kwargs[r'certfile'] = certfile
-
- con = HTTPConnection(host, port, use_ssl=True,
- ssl_wrap_socket=sslutil.wrapsocket,
- ssl_validator=sslutil.validatesocket,
- ui=self.ui,
- **kwargs)
- return con