--- a/mercurial/dispatch.py Thu Aug 04 16:12:58 2011 -0500
+++ b/mercurial/dispatch.py Fri Aug 05 16:07:51 2011 -0500
@@ -357,6 +357,15 @@
# but only if they have been defined prior to the current definition.
for alias, definition in ui.configitems('alias'):
aliasdef = cmdalias(alias, definition, cmdtable)
+
+ try:
+ olddef = cmdtable[aliasdef.cmd][0]
+ if olddef.definition == aliasdef.definition:
+ continue
+ except (KeyError, AttributeError):
+ # definition might not exist or it might not be a cmdalias
+ pass
+
cmdtable[aliasdef.cmd] = (aliasdef, aliasdef.opts, aliasdef.help)
if aliasdef.norepo:
commands.norepo += ' %s' % alias
--- a/mercurial/httpconnection.py Thu Aug 04 16:12:58 2011 -0500
+++ b/mercurial/httpconnection.py Fri Aug 05 16:07:51 2011 -0500
@@ -58,7 +58,7 @@
return self._len
# moved here from url.py to avoid a cycle
-def readauthforuri(ui, uri):
+def readauthforuri(ui, uri, user):
# Read configuration
config = dict()
for key, val in ui.configitems('auth'):
@@ -72,10 +72,6 @@
gdict[setting] = val
# Find the best match
- uri = util.url(uri)
- user = uri.user
- uri.user = uri.password = None
- uri = str(uri)
scheme, hostpath = uri.split('://', 1)
bestuser = None
bestlen = 0
@@ -238,7 +234,11 @@
return self.do_open(HTTPConnection, req, False)
def https_open(self, req):
- res = readauthforuri(self.ui, req.get_full_url())
+ # req.get_full_url() does not contain credentials and we may
+ # need them to match the certificates.
+ url = req.get_full_url()
+ user, password = self.pwmgr.find_stored_password(url)
+ res = readauthforuri(self.ui, url, user)
if res:
group, auth = res
self.auth = auth
--- a/mercurial/url.py Thu Aug 04 16:12:58 2011 -0500
+++ b/mercurial/url.py Fri Aug 05 16:07:51 2011 -0500
@@ -26,7 +26,7 @@
return (user, passwd)
if not user or not passwd:
- res = httpconnectionmod.readauthforuri(self.ui, authuri)
+ res = httpconnectionmod.readauthforuri(self.ui, authuri, user)
if res:
group, auth = res
user, passwd = auth.get('username'), auth.get('password')
@@ -53,6 +53,10 @@
msg = _('http auth: user %s, password %s\n')
self.ui.debug(msg % (user, passwd and '*' * len(passwd) or 'not set'))
+ def find_stored_password(self, authuri):
+ return urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(
+ self, None, authuri)
+
class proxyhandler(urllib2.ProxyHandler):
def __init__(self, ui):
proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
@@ -342,7 +346,11 @@
return keepalive.KeepAliveHandler._start_transaction(self, h, req)
def https_open(self, req):
- res = httpconnectionmod.readauthforuri(self.ui, req.get_full_url())
+ # req.get_full_url() does not contain credentials and we may
+ # need them to match the certificates.
+ url = req.get_full_url()
+ user, password = self.pwmgr.find_stored_password(url)
+ res = httpconnectionmod.readauthforuri(self.ui, url, user)
if res:
group, auth = res
self.auth = auth
--- a/mercurial/util.py Thu Aug 04 16:12:58 2011 -0500
+++ b/mercurial/util.py Fri Aug 05 16:07:51 2011 -0500
@@ -1468,6 +1468,8 @@
path = None
if not self.host:
self.host = None
+ # path of file:///d is /d
+ # path of file:///d:/ is d:/, not /d:/
if path and not hasdriveletter(path):
path = '/' + path
@@ -1587,7 +1589,9 @@
self.user, self.passwd = user, passwd
if not self.user:
return (s, None)
- return (s, (None, (str(self), self.host),
+ # authinfo[1] is passed to urllib2 password manager, and its URIs
+ # must not contain credentials.
+ return (s, (None, (s, self.host),
self.user, self.passwd or ''))
def isabs(self):
@@ -1610,11 +1614,6 @@
path = self._hostport + '/' + self.path
elif self.host is not None and self.path:
path = '/' + path
- # We also need to handle the case of file:///C:/, which
- # should return C:/, not /C:/.
- elif hasdriveletter(path):
- # Strip leading slash from paths with drive names
- return path[1:]
return path
return self._origpath
--- a/tests/test-hgweb-auth.py Thu Aug 04 16:12:58 2011 -0500
+++ b/tests/test-hgweb-auth.py Fri Aug 05 16:07:51 2011 -0500
@@ -1,4 +1,5 @@
from mercurial import demandimport; demandimport.enable()
+import urllib2
from mercurial import ui, util
from mercurial import url
from mercurial.error import Abort
@@ -36,10 +37,10 @@
print 'URI:', uri
try:
pm = url.passwordmgr(ui)
- authinfo = util.url(uri).authinfo()[1]
+ u, authinfo = util.url(uri).authinfo()
if authinfo is not None:
pm.add_password(*authinfo)
- print ' ', pm.find_user_password('test', uri)
+ print ' ', pm.find_user_password('test', u)
except Abort, e:
print 'abort'
@@ -95,3 +96,12 @@
'y.username': 'y',
'y.password': 'ypassword'},
urls=['http://y@example.org/foo/bar'])
+
+def testauthinfo(fullurl, authurl):
+ print 'URIs:', fullurl, authurl
+ pm = urllib2.HTTPPasswordMgrWithDefaultRealm()
+ pm.add_password(*util.url(fullurl).authinfo()[1])
+ print pm.find_user_password('test', authurl)
+
+print '\n*** Test urllib2 and util.url\n'
+testauthinfo('http://user@example.com:8080/foo', 'http://example.com:8080/foo')
--- a/tests/test-hgweb-auth.py.out Thu Aug 04 16:12:58 2011 -0500
+++ b/tests/test-hgweb-auth.py.out Fri Aug 05 16:07:51 2011 -0500
@@ -189,3 +189,8 @@
CFG: {x.password: xpassword, x.prefix: http://example.org/foo/bar, x.username: None, y.password: ypassword, y.prefix: http://example.org/foo, y.username: y}
URI: http://y@example.org/foo/bar
('y', 'xpassword')
+
+*** Test urllib2 and util.url
+
+URIs: http://user@example.com:8080/foo http://example.com:8080/foo
+('user', '')
--- a/tests/test-http.t Thu Aug 04 16:12:58 2011 -0500
+++ b/tests/test-http.t Fri Aug 05 16:07:51 2011 -0500
@@ -110,6 +110,55 @@
abort: HTTP Error 404: Not Found
[255]
+test http authentication
+
+ $ cd test
+ $ cat << EOT > userpass.py
+ > import base64
+ > from mercurial.hgweb import common
+ > def perform_authentication(hgweb, req, op):
+ > auth = req.env.get('HTTP_AUTHORIZATION')
+ > if not auth:
+ > raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, 'who',
+ > [('WWW-Authenticate', 'Basic Realm="mercurial"')])
+ > if base64.b64decode(auth.split()[1]).split(':', 1) != ['user', 'pass']:
+ > raise common.ErrorResponse(common.HTTP_FORBIDDEN, 'no')
+ > def extsetup():
+ > common.permhooks.insert(0, perform_authentication)
+ > EOT
+ $ hg --config extensions.x=userpass.py serve -p $HGPORT2 -d --pid-file=pid
+ $ cat pid >> $DAEMON_PIDS
+
+ $ hg id http://localhost:$HGPORT2/
+ abort: http authorization required
+ [255]
+ $ hg id http://user@localhost:$HGPORT2/
+ abort: http authorization required
+ [255]
+ $ hg id http://user:pass@localhost:$HGPORT2/
+ 5fed3813f7f5
+ $ echo '[auth]' >> .hg/hgrc
+ $ echo 'l.schemes=http' >> .hg/hgrc
+ $ echo 'l.prefix=lo' >> .hg/hgrc
+ $ echo 'l.username=user' >> .hg/hgrc
+ $ echo 'l.password=pass' >> .hg/hgrc
+ $ hg id http://localhost:$HGPORT2/
+ 5fed3813f7f5
+ $ hg id http://localhost:$HGPORT2/
+ 5fed3813f7f5
+ $ hg id http://user@localhost:$HGPORT2/
+ 5fed3813f7f5
+ $ hg id http://user:pass@localhost:$HGPORT2/
+ 5fed3813f7f5
+ $ hg id http://user2@localhost:$HGPORT2/
+ abort: http authorization required
+ [255]
+ $ hg id http://user:pass2@localhost:$HGPORT2/
+ abort: HTTP Error 403: no
+ [255]
+
+ $ cd ..
+
check error log
$ cat error.log
--- a/tests/test-url.py Thu Aug 04 16:12:58 2011 -0500
+++ b/tests/test-url.py Fri Aug 05 16:07:51 2011 -0500
@@ -204,18 +204,32 @@
<url scheme: 'file', path: '/foo/bar/baz'>
>>> str(u)
'file:///foo/bar/baz'
+ >>> u.localpath()
+ '/foo/bar/baz'
>>> u = url('file:///foo/bar/baz')
>>> u
<url scheme: 'file', path: '/foo/bar/baz'>
>>> str(u)
'file:///foo/bar/baz'
+ >>> u.localpath()
+ '/foo/bar/baz'
+
+ >>> u = url('file:///f:oo/bar/baz')
+ >>> u
+ <url scheme: 'file', path: 'f:oo/bar/baz'>
+ >>> str(u)
+ 'file:f%3Aoo/bar/baz'
+ >>> u.localpath()
+ 'f:oo/bar/baz'
>>> u = url('file:foo/bar/baz')
>>> u
<url scheme: 'file', path: 'foo/bar/baz'>
>>> str(u)
'file:foo/bar/baz'
+ >>> u.localpath()
+ 'foo/bar/baz'
"""
doctest.testmod(optionflags=doctest.NORMALIZE_WHITESPACE)