merge with stable
authorMatt Mackall <mpm@selenic.com>
Mon, 01 Aug 2011 18:10:05 -0500
changeset 15008 d0424f39984c
parent 15003 a31b8e03af28 (current diff)
parent 15007 9991f8b19ff3 (diff)
child 15009 caa5283390f8
merge with stable
mercurial/help/config.txt
mercurial/url.py
--- a/.hgsigs	Mon Aug 01 14:53:10 2011 -0500
+++ b/.hgsigs	Mon Aug 01 18:10:05 2011 -0500
@@ -40,3 +40,4 @@
 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 0 iD8DBQBNvTy4ywK+sNU5EO8RAmp8AJ9QnxK4jTJ7G722MyeBxf0UXEdGwACgtlM7BKtNQfbEH/fOW5y+45W88VI=
 733af5d9f6b22387913e1d11350fb8cb7c1487dd 0 iD8DBQBN5q/8ywK+sNU5EO8RArRGAKCNGT94GKIYtSuwZ57z1sQbcw6uLACfffpbMV4NAPMl8womAwg+7ZPKnIU=
 de9eb6b1da4fc522b1cab16d86ca166204c24f25 0 iD8DBQBODhfhywK+sNU5EO8RAr2+AJ4ugbAj8ae8/K0bYZzx3sascIAg1QCeK3b+zbbVVqd3b7CDpwFnaX8kTd4=
+4a43e23b8c55b4566b8200bf69fe2158485a2634 0 iD8DBQBONzIMywK+sNU5EO8RAj5SAJ0aPS3+JHnyI6bHB2Fl0LImbDmagwCdGbDLp1S7TFobxXudOH49bX45Iik=
--- a/.hgtags	Mon Aug 01 14:53:10 2011 -0500
+++ b/.hgtags	Mon Aug 01 18:10:05 2011 -0500
@@ -52,3 +52,4 @@
 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 1.8.3
 733af5d9f6b22387913e1d11350fb8cb7c1487dd 1.8.4
 de9eb6b1da4fc522b1cab16d86ca166204c24f25 1.9
+4a43e23b8c55b4566b8200bf69fe2158485a2634 1.9.1
--- a/mercurial/help/config.txt	Mon Aug 01 14:53:10 2011 -0500
+++ b/mercurial/help/config.txt	Mon Aug 01 18:10:05 2011 -0500
@@ -266,7 +266,9 @@
     Optional. Username to authenticate with. If not given, and the
     remote site requires basic or digest authentication, the user will
     be prompted for it. Environment variables are expanded in the
-    username letting you do ``foo.username = $USER``.
+    username letting you do ``foo.username = $USER``. If the URI
+    includes a username, only ``[auth]`` entries with a matching
+    username or without a username will be considered.
 
 ``password``
     Optional. Password to authenticate with. If not given, and the
@@ -1158,6 +1160,13 @@
     be present in this list. The contents of the allow_push list are
     examined after the deny_push list.
 
+``guessmime``
+    Control MIME types for raw download of file content.
+    Set to True to let hgweb guess the content type from the file
+    extension. This will serve HTML files as ``text/html`` and might
+    allow cross-site scripting attacks when serving untrusted
+    repositories. Default is False.
+   
 ``allow_read``
     If the user has not already been denied repository access due to
     the contents of deny_read, this list determines whether to grant
--- a/mercurial/hgweb/webcommands.py	Mon Aug 01 14:53:10 2011 -0500
+++ b/mercurial/hgweb/webcommands.py	Mon Aug 01 18:10:05 2011 -0500
@@ -32,6 +32,8 @@
         return changelog(web, req, tmpl)
 
 def rawfile(web, req, tmpl):
+    guessmime = web.configbool('web', 'guessmime', False)
+
     path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
     if not path:
         content = manifest(web, req, tmpl)
@@ -50,9 +52,11 @@
 
     path = fctx.path()
     text = fctx.data()
-    mt = mimetypes.guess_type(path)[0]
-    if mt is None:
-        mt = binary(text) and 'application/octet-stream' or 'text/plain'
+    mt = 'application/binary'
+    if guessmime:
+        mt = mimetypes.guess_type(path)[0]
+        if mt is None:
+            mt = binary(text) and 'application/binary' or 'text/plain'
     if mt.startswith('text/'):
         mt += '; charset="%s"' % encoding.encoding
 
--- a/mercurial/httpconnection.py	Mon Aug 01 14:53:10 2011 -0500
+++ b/mercurial/httpconnection.py	Mon Aug 01 18:10:05 2011 -0500
@@ -72,10 +72,19 @@
         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
     bestauth = None
     for group, auth in config.iteritems():
+        if user and user != auth.get('username', user):
+            # If a username was set in the URI, the entry username
+            # must either match it or be unset
+            continue
         prefix = auth.get('prefix')
         if not prefix:
             continue
@@ -85,9 +94,14 @@
         else:
             schemes = (auth.get('schemes') or 'https').split()
         if (prefix == '*' or hostpath.startswith(prefix)) and \
-            len(prefix) > bestlen and scheme in schemes:
+            (len(prefix) > bestlen or (len(prefix) == bestlen and \
+                not bestuser and 'username' in auth)) \
+             and scheme in schemes:
             bestlen = len(prefix)
             bestauth = group, auth
+            bestuser = auth.get('username')
+            if user and not bestuser:
+                auth['username'] = user
     return bestauth
 
 # Mercurial (at least until we can remove the old codepath) requires
--- a/mercurial/url.py	Mon Aug 01 14:53:10 2011 -0500
+++ b/mercurial/url.py	Mon Aug 01 18:10:05 2011 -0500
@@ -25,7 +25,7 @@
             self._writedebug(user, passwd)
             return (user, passwd)
 
-        if not user:
+        if not user or not passwd:
             res = httpconnectionmod.readauthforuri(self.ui, authuri)
             if res:
                 group, auth = res
--- a/tests/test-hgweb-auth.py	Mon Aug 01 14:53:10 2011 -0500
+++ b/tests/test-hgweb-auth.py	Mon Aug 01 18:10:05 2011 -0500
@@ -1,5 +1,5 @@
 from mercurial import demandimport; demandimport.enable()
-from mercurial import ui
+from mercurial import ui, util
 from mercurial import url
 from mercurial.error import Abort
 
@@ -19,13 +19,16 @@
     return '{' + ', '.join(['%s: %s' % (k, dict[k])
                             for k in sorted(dict.iterkeys())]) + '}'
 
-def test(auth):
+def test(auth, urls=None):
     print 'CFG:', dumpdict(auth)
     prefixes = set()
     for k in auth:
         prefixes.add(k.split('.', 1)[0])
     for p in prefixes:
-        auth.update({p + '.username': p, p + '.password': p})
+        for name in ('.username', '.password'):
+            if (p + name) not in auth:
+                auth[p + name] = p
+    auth = dict((k, v) for k, v in auth.iteritems() if v is not None)
 
     ui = writeauth(auth)
 
@@ -33,16 +36,26 @@
         print 'URI:', uri
         try:
             pm = url.passwordmgr(ui)
+            authinfo = util.url(uri).authinfo()[1]
+            if authinfo is not None:
+                pm.add_password(*authinfo)
             print '    ', pm.find_user_password('test', uri)
         except Abort, e:
             print 'abort'
 
-    _test('http://example.org/foo')
-    _test('http://example.org/foo/bar')
-    _test('http://example.org/bar')
-    _test('https://example.org/foo')
-    _test('https://example.org/foo/bar')
-    _test('https://example.org/bar')
+    if not urls:
+        urls = [
+            'http://example.org/foo',
+            'http://example.org/foo/bar',
+            'http://example.org/bar',
+            'https://example.org/foo',
+            'https://example.org/foo/bar',
+            'https://example.org/bar',
+            'https://x@example.org/bar',
+            'https://y@example.org/bar',
+            ]
+    for u in urls:
+        _test(u)
 
 
 print '\n*** Test in-uri schemes\n'
@@ -62,3 +75,23 @@
 test({'x.prefix': 'http://example.org/foo',
       'y.prefix': 'http://example.org/foo/bar'})
 test({'x.prefix': '*', 'y.prefix': 'https://example.org/bar'})
+
+print '\n*** Test user matching\n'
+test({'x.prefix': 'http://example.org/foo',
+      'x.username': None,
+      'x.password': 'xpassword'},
+     urls=['http://y@example.org/foo'])
+test({'x.prefix': 'http://example.org/foo',
+      'x.username': None,
+      'x.password': 'xpassword',
+      'y.prefix': 'http://example.org/foo',
+      'y.username': 'y',
+      'y.password': 'ypassword'},
+     urls=['http://y@example.org/foo'])
+test({'x.prefix': 'http://example.org/foo/bar',
+      'x.username': None,
+      'x.password': 'xpassword',
+      'y.prefix': 'http://example.org/foo',
+      'y.username': 'y',
+      'y.password': 'ypassword'},
+     urls=['http://y@example.org/foo/bar'])
--- a/tests/test-hgweb-auth.py.out	Mon Aug 01 14:53:10 2011 -0500
+++ b/tests/test-hgweb-auth.py.out	Mon Aug 01 18:10:05 2011 -0500
@@ -14,6 +14,10 @@
      abort
 URI: https://example.org/bar
      abort
+URI: https://x@example.org/bar
+     abort
+URI: https://y@example.org/bar
+     abort
 CFG: {x.prefix: https://example.org}
 URI: http://example.org/foo
      abort
@@ -27,6 +31,10 @@
      ('x', 'x')
 URI: https://example.org/bar
      ('x', 'x')
+URI: https://x@example.org/bar
+     ('x', 'x')
+URI: https://y@example.org/bar
+     abort
 CFG: {x.prefix: http://example.org, x.schemes: https}
 URI: http://example.org/foo
      ('x', 'x')
@@ -40,6 +48,10 @@
      abort
 URI: https://example.org/bar
      abort
+URI: https://x@example.org/bar
+     abort
+URI: https://y@example.org/bar
+     abort
 CFG: {x.prefix: https://example.org, x.schemes: http}
 URI: http://example.org/foo
      abort
@@ -53,6 +65,10 @@
      ('x', 'x')
 URI: https://example.org/bar
      ('x', 'x')
+URI: https://x@example.org/bar
+     ('x', 'x')
+URI: https://y@example.org/bar
+     abort
 
 *** Test separately configured schemes
 
@@ -69,6 +85,10 @@
      abort
 URI: https://example.org/bar
      abort
+URI: https://x@example.org/bar
+     abort
+URI: https://y@example.org/bar
+     abort
 CFG: {x.prefix: example.org, x.schemes: https}
 URI: http://example.org/foo
      abort
@@ -82,6 +102,10 @@
      ('x', 'x')
 URI: https://example.org/bar
      ('x', 'x')
+URI: https://x@example.org/bar
+     ('x', 'x')
+URI: https://y@example.org/bar
+     abort
 CFG: {x.prefix: example.org, x.schemes: http https}
 URI: http://example.org/foo
      ('x', 'x')
@@ -95,6 +119,10 @@
      ('x', 'x')
 URI: https://example.org/bar
      ('x', 'x')
+URI: https://x@example.org/bar
+     ('x', 'x')
+URI: https://y@example.org/bar
+     abort
 
 *** Test prefix matching
 
@@ -111,6 +139,10 @@
      abort
 URI: https://example.org/bar
      abort
+URI: https://x@example.org/bar
+     abort
+URI: https://y@example.org/bar
+     abort
 CFG: {x.prefix: http://example.org/foo, y.prefix: http://example.org/foo/bar}
 URI: http://example.org/foo
      ('x', 'x')
@@ -124,6 +156,10 @@
      abort
 URI: https://example.org/bar
      abort
+URI: https://x@example.org/bar
+     abort
+URI: https://y@example.org/bar
+     abort
 CFG: {x.prefix: *, y.prefix: https://example.org/bar}
 URI: http://example.org/foo
      abort
@@ -137,3 +173,19 @@
      ('x', 'x')
 URI: https://example.org/bar
      ('y', 'y')
+URI: https://x@example.org/bar
+     ('x', 'x')
+URI: https://y@example.org/bar
+     ('y', 'y')
+
+*** Test user matching
+
+CFG: {x.password: xpassword, x.prefix: http://example.org/foo, x.username: None}
+URI: http://y@example.org/foo
+     ('y', 'xpassword')
+CFG: {x.password: xpassword, x.prefix: http://example.org/foo, x.username: None, y.password: ypassword, y.prefix: http://example.org/foo, y.username: y}
+URI: http://y@example.org/foo
+     ('y', 'ypassword')
+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')
--- a/tests/test-hgweb-raw.t	Mon Aug 01 14:53:10 2011 -0500
+++ b/tests/test-hgweb-raw.t	Mon Aug 01 18:10:05 2011 -0500
@@ -22,6 +22,28 @@
   $ sleep 1 # wait for server to scream and die
   $ cat getoutput.txt
   200 Script output follows
+  content-type: application/binary
+  content-length: 157
+  content-disposition: inline; filename="some \"text\".txt"
+  
+  This is just some random text
+  that will go inside the file and take a few lines.
+  It is very boring to read, but computers don't
+  care about things like that.
+  $ cat access.log error.log
+  127.0.0.1 - - [*] "GET /?f=a23bf1310f6e;file=sub/some%20%22text%22.txt;style=raw HTTP/1.1" 200 - (glob)
+
+  $ rm access.log error.log
+  $ hg serve -p $HGPORT -A access.log -E error.log -d --pid-file=hg.pid \
+  > --config web.guessmime=True
+
+  $ cat hg.pid >> $DAEMON_PIDS
+  $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?f=a23bf1310f6e;file=sub/some%20%22text%22.txt;style=raw' content-type content-length content-disposition) >getoutput.txt &
+  $ sleep 5
+  $ kill `cat hg.pid`
+  $ sleep 1 # wait for server to scream and die
+  $ cat getoutput.txt
+  200 Script output follows
   content-type: text/plain; charset="ascii"
   content-length: 157
   content-disposition: inline; filename="some \"text\".txt"