diff mercurial/url.py @ 14244:e7525a555a64

url: use new http support if requested by the user The new http library is wired in via an extra module (httpconnection.py), as it requires similar but different plumbing to connect the library to Mercurial's internals and urllib2. Eventualy we should be able to remove all of keepalive.py and its associated tangle in url.py and replace it all with the code in httpconnection.py. To use the new library, set 'ui.usehttp2' to true. The underlying http library uses the logging module liberally, so if things break you can use 'ui.http2debuglevel' to set the log level to INFO or DEBUG to get that logging information (for example, ui.http2debuglevel=info.)
author Augie Fackler <durin42@gmail.com>
date Fri, 06 May 2011 10:22:08 -0500
parents 5fa21960b2f4
children 376c32a5ccdc 4a43e23b8c55
line wrap: on
line diff
--- a/mercurial/url.py	Fri May 06 09:57:55 2011 -0500
+++ b/mercurial/url.py	Fri May 06 10:22:08 2011 -0500
@@ -8,41 +8,9 @@
 # GNU General Public License version 2 or any later version.
 
 import urllib, urllib2, httplib, os, socket, cStringIO
-import __builtin__
 from i18n import _
 import keepalive, util, sslutil
-
-def readauthforuri(ui, uri):
-    # Read configuration
-    config = dict()
-    for key, val in ui.configitems('auth'):
-        if '.' not in key:
-            ui.warn(_("ignoring invalid [auth] key '%s'\n") % key)
-            continue
-        group, setting = key.rsplit('.', 1)
-        gdict = config.setdefault(group, dict())
-        if setting in ('username', 'cert', 'key'):
-            val = util.expandpath(val)
-        gdict[setting] = val
-
-    # Find the best match
-    scheme, hostpath = uri.split('://', 1)
-    bestlen = 0
-    bestauth = None
-    for group, auth in config.iteritems():
-        prefix = auth.get('prefix')
-        if not prefix:
-            continue
-        p = prefix.split('://', 1)
-        if len(p) > 1:
-            schemes, prefix = [p[0]], p[1]
-        else:
-            schemes = (auth.get('schemes') or 'https').split()
-        if (prefix == '*' or hostpath.startswith(prefix)) and \
-            len(prefix) > bestlen and scheme in schemes:
-            bestlen = len(prefix)
-            bestauth = group, auth
-    return bestauth
+import httpconnection as httpconnectionmod
 
 class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm):
     def __init__(self, ui):
@@ -58,7 +26,7 @@
             return (user, passwd)
 
         if not user:
-            res = readauthforuri(self.ui, authuri)
+            res = httpconnectionmod.readauthforuri(self.ui, authuri)
             if res:
                 group, auth = res
                 user, passwd = auth.get('username'), auth.get('password')
@@ -149,48 +117,10 @@
 
         return urllib2.ProxyHandler.proxy_open(self, req, proxy, type_)
 
-class httpsendfile(object):
-    """This is a wrapper around the objects returned by python's "open".
-
-    Its purpose is to send file-like objects via HTTP and, to do so, it
-    defines a __len__ attribute to feed the Content-Length header.
-    """
-
-    def __init__(self, ui, *args, **kwargs):
-        # We can't just "self._data = open(*args, **kwargs)" here because there
-        # is an "open" function defined in this module that shadows the global
-        # one
-        self.ui = ui
-        self._data = __builtin__.open(*args, **kwargs)
-        self.seek = self._data.seek
-        self.close = self._data.close
-        self.write = self._data.write
-        self._len = os.fstat(self._data.fileno()).st_size
-        self._pos = 0
-        self._total = len(self) / 1024 * 2
-
-    def read(self, *args, **kwargs):
-        try:
-            ret = self._data.read(*args, **kwargs)
-        except EOFError:
-            self.ui.progress(_('sending'), None)
-        self._pos += len(ret)
-        # We pass double the max for total because we currently have
-        # to send the bundle twice in the case of a server that
-        # requires authentication. Since we can't know until we try
-        # once whether authentication will be required, just lie to
-        # the user and maybe the push succeeds suddenly at 50%.
-        self.ui.progress(_('sending'), self._pos / 1024,
-                         unit=_('kb'), total=self._total)
-        return ret
-
-    def __len__(self):
-        return self._len
-
 def _gen_sendfile(orgsend):
     def _sendfile(self, data):
         # send a file
-        if isinstance(data, httpsendfile):
+        if isinstance(data, httpconnectionmod.httpsendfile):
             # if auth required, some data sent twice, so rewind here
             data.seek(0)
             for chunk in util.filechunkiter(data):
@@ -412,7 +342,7 @@
             return keepalive.KeepAliveHandler._start_transaction(self, h, req)
 
         def https_open(self, req):
-            res = readauthforuri(self.ui, req.get_full_url())
+            res = httpconnectionmod.readauthforuri(self.ui, req.get_full_url())
             if res:
                 group, auth = res
                 self.auth = auth
@@ -495,9 +425,12 @@
     construct an opener suitable for urllib2
     authinfo will be added to the password manager
     '''
-    handlers = [httphandler()]
-    if has_https:
-        handlers.append(httpshandler(ui))
+    if ui.configbool('ui', 'usehttp2', False):
+        handlers = [httpconnectionmod.http2handler(ui, passwordmgr(ui))]
+    else:
+        handlers = [httphandler()]
+        if has_https:
+            handlers.append(httpshandler(ui))
 
     handlers.append(proxyhandler(ui))