##// END OF EJS Templates
merge with stable
Matt Mackall -
r15008:d0424f39 merge default
parent child Browse files
Show More
@@ -40,3 +40,4 b' b032bec2c0a651ca0ddecb65714bfe6770f67d70'
40 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 0 iD8DBQBNvTy4ywK+sNU5EO8RAmp8AJ9QnxK4jTJ7G722MyeBxf0UXEdGwACgtlM7BKtNQfbEH/fOW5y+45W88VI=
40 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 0 iD8DBQBNvTy4ywK+sNU5EO8RAmp8AJ9QnxK4jTJ7G722MyeBxf0UXEdGwACgtlM7BKtNQfbEH/fOW5y+45W88VI=
41 733af5d9f6b22387913e1d11350fb8cb7c1487dd 0 iD8DBQBN5q/8ywK+sNU5EO8RArRGAKCNGT94GKIYtSuwZ57z1sQbcw6uLACfffpbMV4NAPMl8womAwg+7ZPKnIU=
41 733af5d9f6b22387913e1d11350fb8cb7c1487dd 0 iD8DBQBN5q/8ywK+sNU5EO8RArRGAKCNGT94GKIYtSuwZ57z1sQbcw6uLACfffpbMV4NAPMl8womAwg+7ZPKnIU=
42 de9eb6b1da4fc522b1cab16d86ca166204c24f25 0 iD8DBQBODhfhywK+sNU5EO8RAr2+AJ4ugbAj8ae8/K0bYZzx3sascIAg1QCeK3b+zbbVVqd3b7CDpwFnaX8kTd4=
42 de9eb6b1da4fc522b1cab16d86ca166204c24f25 0 iD8DBQBODhfhywK+sNU5EO8RAr2+AJ4ugbAj8ae8/K0bYZzx3sascIAg1QCeK3b+zbbVVqd3b7CDpwFnaX8kTd4=
43 4a43e23b8c55b4566b8200bf69fe2158485a2634 0 iD8DBQBONzIMywK+sNU5EO8RAj5SAJ0aPS3+JHnyI6bHB2Fl0LImbDmagwCdGbDLp1S7TFobxXudOH49bX45Iik=
@@ -52,3 +52,4 b' b032bec2c0a651ca0ddecb65714bfe6770f67d70'
52 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 1.8.3
52 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 1.8.3
53 733af5d9f6b22387913e1d11350fb8cb7c1487dd 1.8.4
53 733af5d9f6b22387913e1d11350fb8cb7c1487dd 1.8.4
54 de9eb6b1da4fc522b1cab16d86ca166204c24f25 1.9
54 de9eb6b1da4fc522b1cab16d86ca166204c24f25 1.9
55 4a43e23b8c55b4566b8200bf69fe2158485a2634 1.9.1
@@ -266,7 +266,9 b' Supported arguments:'
266 Optional. Username to authenticate with. If not given, and the
266 Optional. Username to authenticate with. If not given, and the
267 remote site requires basic or digest authentication, the user will
267 remote site requires basic or digest authentication, the user will
268 be prompted for it. Environment variables are expanded in the
268 be prompted for it. Environment variables are expanded in the
269 username letting you do ``foo.username = $USER``.
269 username letting you do ``foo.username = $USER``. If the URI
270 includes a username, only ``[auth]`` entries with a matching
271 username or without a username will be considered.
270
272
271 ``password``
273 ``password``
272 Optional. Password to authenticate with. If not given, and the
274 Optional. Password to authenticate with. If not given, and the
@@ -1158,6 +1160,13 b' The full set of options is:'
1158 be present in this list. The contents of the allow_push list are
1160 be present in this list. The contents of the allow_push list are
1159 examined after the deny_push list.
1161 examined after the deny_push list.
1160
1162
1163 ``guessmime``
1164 Control MIME types for raw download of file content.
1165 Set to True to let hgweb guess the content type from the file
1166 extension. This will serve HTML files as ``text/html`` and might
1167 allow cross-site scripting attacks when serving untrusted
1168 repositories. Default is False.
1169
1161 ``allow_read``
1170 ``allow_read``
1162 If the user has not already been denied repository access due to
1171 If the user has not already been denied repository access due to
1163 the contents of deny_read, this list determines whether to grant
1172 the contents of deny_read, this list determines whether to grant
@@ -32,6 +32,8 b' def log(web, req, tmpl):'
32 return changelog(web, req, tmpl)
32 return changelog(web, req, tmpl)
33
33
34 def rawfile(web, req, tmpl):
34 def rawfile(web, req, tmpl):
35 guessmime = web.configbool('web', 'guessmime', False)
36
35 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
37 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
36 if not path:
38 if not path:
37 content = manifest(web, req, tmpl)
39 content = manifest(web, req, tmpl)
@@ -50,9 +52,11 b' def rawfile(web, req, tmpl):'
50
52
51 path = fctx.path()
53 path = fctx.path()
52 text = fctx.data()
54 text = fctx.data()
53 mt = mimetypes.guess_type(path)[0]
55 mt = 'application/binary'
54 if mt is None:
56 if guessmime:
55 mt = binary(text) and 'application/octet-stream' or 'text/plain'
57 mt = mimetypes.guess_type(path)[0]
58 if mt is None:
59 mt = binary(text) and 'application/binary' or 'text/plain'
56 if mt.startswith('text/'):
60 if mt.startswith('text/'):
57 mt += '; charset="%s"' % encoding.encoding
61 mt += '; charset="%s"' % encoding.encoding
58
62
@@ -72,10 +72,19 b' def readauthforuri(ui, uri):'
72 gdict[setting] = val
72 gdict[setting] = val
73
73
74 # Find the best match
74 # Find the best match
75 uri = util.url(uri)
76 user = uri.user
77 uri.user = uri.password = None
78 uri = str(uri)
75 scheme, hostpath = uri.split('://', 1)
79 scheme, hostpath = uri.split('://', 1)
80 bestuser = None
76 bestlen = 0
81 bestlen = 0
77 bestauth = None
82 bestauth = None
78 for group, auth in config.iteritems():
83 for group, auth in config.iteritems():
84 if user and user != auth.get('username', user):
85 # If a username was set in the URI, the entry username
86 # must either match it or be unset
87 continue
79 prefix = auth.get('prefix')
88 prefix = auth.get('prefix')
80 if not prefix:
89 if not prefix:
81 continue
90 continue
@@ -85,9 +94,14 b' def readauthforuri(ui, uri):'
85 else:
94 else:
86 schemes = (auth.get('schemes') or 'https').split()
95 schemes = (auth.get('schemes') or 'https').split()
87 if (prefix == '*' or hostpath.startswith(prefix)) and \
96 if (prefix == '*' or hostpath.startswith(prefix)) and \
88 len(prefix) > bestlen and scheme in schemes:
97 (len(prefix) > bestlen or (len(prefix) == bestlen and \
98 not bestuser and 'username' in auth)) \
99 and scheme in schemes:
89 bestlen = len(prefix)
100 bestlen = len(prefix)
90 bestauth = group, auth
101 bestauth = group, auth
102 bestuser = auth.get('username')
103 if user and not bestuser:
104 auth['username'] = user
91 return bestauth
105 return bestauth
92
106
93 # Mercurial (at least until we can remove the old codepath) requires
107 # Mercurial (at least until we can remove the old codepath) requires
@@ -25,7 +25,7 b' class passwordmgr(urllib2.HTTPPasswordMg'
25 self._writedebug(user, passwd)
25 self._writedebug(user, passwd)
26 return (user, passwd)
26 return (user, passwd)
27
27
28 if not user:
28 if not user or not passwd:
29 res = httpconnectionmod.readauthforuri(self.ui, authuri)
29 res = httpconnectionmod.readauthforuri(self.ui, authuri)
30 if res:
30 if res:
31 group, auth = res
31 group, auth = res
@@ -1,5 +1,5 b''
1 from mercurial import demandimport; demandimport.enable()
1 from mercurial import demandimport; demandimport.enable()
2 from mercurial import ui
2 from mercurial import ui, util
3 from mercurial import url
3 from mercurial import url
4 from mercurial.error import Abort
4 from mercurial.error import Abort
5
5
@@ -19,13 +19,16 b' def dumpdict(dict):'
19 return '{' + ', '.join(['%s: %s' % (k, dict[k])
19 return '{' + ', '.join(['%s: %s' % (k, dict[k])
20 for k in sorted(dict.iterkeys())]) + '}'
20 for k in sorted(dict.iterkeys())]) + '}'
21
21
22 def test(auth):
22 def test(auth, urls=None):
23 print 'CFG:', dumpdict(auth)
23 print 'CFG:', dumpdict(auth)
24 prefixes = set()
24 prefixes = set()
25 for k in auth:
25 for k in auth:
26 prefixes.add(k.split('.', 1)[0])
26 prefixes.add(k.split('.', 1)[0])
27 for p in prefixes:
27 for p in prefixes:
28 auth.update({p + '.username': p, p + '.password': p})
28 for name in ('.username', '.password'):
29 if (p + name) not in auth:
30 auth[p + name] = p
31 auth = dict((k, v) for k, v in auth.iteritems() if v is not None)
29
32
30 ui = writeauth(auth)
33 ui = writeauth(auth)
31
34
@@ -33,16 +36,26 b' def test(auth):'
33 print 'URI:', uri
36 print 'URI:', uri
34 try:
37 try:
35 pm = url.passwordmgr(ui)
38 pm = url.passwordmgr(ui)
39 authinfo = util.url(uri).authinfo()[1]
40 if authinfo is not None:
41 pm.add_password(*authinfo)
36 print ' ', pm.find_user_password('test', uri)
42 print ' ', pm.find_user_password('test', uri)
37 except Abort, e:
43 except Abort, e:
38 print 'abort'
44 print 'abort'
39
45
40 _test('http://example.org/foo')
46 if not urls:
41 _test('http://example.org/foo/bar')
47 urls = [
42 _test('http://example.org/bar')
48 'http://example.org/foo',
43 _test('https://example.org/foo')
49 'http://example.org/foo/bar',
44 _test('https://example.org/foo/bar')
50 'http://example.org/bar',
45 _test('https://example.org/bar')
51 'https://example.org/foo',
52 'https://example.org/foo/bar',
53 'https://example.org/bar',
54 'https://x@example.org/bar',
55 'https://y@example.org/bar',
56 ]
57 for u in urls:
58 _test(u)
46
59
47
60
48 print '\n*** Test in-uri schemes\n'
61 print '\n*** Test in-uri schemes\n'
@@ -62,3 +75,23 b" test({'x.prefix': 'http://example.org/fo"
62 test({'x.prefix': 'http://example.org/foo',
75 test({'x.prefix': 'http://example.org/foo',
63 'y.prefix': 'http://example.org/foo/bar'})
76 'y.prefix': 'http://example.org/foo/bar'})
64 test({'x.prefix': '*', 'y.prefix': 'https://example.org/bar'})
77 test({'x.prefix': '*', 'y.prefix': 'https://example.org/bar'})
78
79 print '\n*** Test user matching\n'
80 test({'x.prefix': 'http://example.org/foo',
81 'x.username': None,
82 'x.password': 'xpassword'},
83 urls=['http://y@example.org/foo'])
84 test({'x.prefix': 'http://example.org/foo',
85 'x.username': None,
86 'x.password': 'xpassword',
87 'y.prefix': 'http://example.org/foo',
88 'y.username': 'y',
89 'y.password': 'ypassword'},
90 urls=['http://y@example.org/foo'])
91 test({'x.prefix': 'http://example.org/foo/bar',
92 'x.username': None,
93 'x.password': 'xpassword',
94 'y.prefix': 'http://example.org/foo',
95 'y.username': 'y',
96 'y.password': 'ypassword'},
97 urls=['http://y@example.org/foo/bar'])
@@ -14,6 +14,10 b' URI: https://example.org/foo/bar'
14 abort
14 abort
15 URI: https://example.org/bar
15 URI: https://example.org/bar
16 abort
16 abort
17 URI: https://x@example.org/bar
18 abort
19 URI: https://y@example.org/bar
20 abort
17 CFG: {x.prefix: https://example.org}
21 CFG: {x.prefix: https://example.org}
18 URI: http://example.org/foo
22 URI: http://example.org/foo
19 abort
23 abort
@@ -27,6 +31,10 b' URI: https://example.org/foo/bar'
27 ('x', 'x')
31 ('x', 'x')
28 URI: https://example.org/bar
32 URI: https://example.org/bar
29 ('x', 'x')
33 ('x', 'x')
34 URI: https://x@example.org/bar
35 ('x', 'x')
36 URI: https://y@example.org/bar
37 abort
30 CFG: {x.prefix: http://example.org, x.schemes: https}
38 CFG: {x.prefix: http://example.org, x.schemes: https}
31 URI: http://example.org/foo
39 URI: http://example.org/foo
32 ('x', 'x')
40 ('x', 'x')
@@ -40,6 +48,10 b' URI: https://example.org/foo/bar'
40 abort
48 abort
41 URI: https://example.org/bar
49 URI: https://example.org/bar
42 abort
50 abort
51 URI: https://x@example.org/bar
52 abort
53 URI: https://y@example.org/bar
54 abort
43 CFG: {x.prefix: https://example.org, x.schemes: http}
55 CFG: {x.prefix: https://example.org, x.schemes: http}
44 URI: http://example.org/foo
56 URI: http://example.org/foo
45 abort
57 abort
@@ -53,6 +65,10 b' URI: https://example.org/foo/bar'
53 ('x', 'x')
65 ('x', 'x')
54 URI: https://example.org/bar
66 URI: https://example.org/bar
55 ('x', 'x')
67 ('x', 'x')
68 URI: https://x@example.org/bar
69 ('x', 'x')
70 URI: https://y@example.org/bar
71 abort
56
72
57 *** Test separately configured schemes
73 *** Test separately configured schemes
58
74
@@ -69,6 +85,10 b' URI: https://example.org/foo/bar'
69 abort
85 abort
70 URI: https://example.org/bar
86 URI: https://example.org/bar
71 abort
87 abort
88 URI: https://x@example.org/bar
89 abort
90 URI: https://y@example.org/bar
91 abort
72 CFG: {x.prefix: example.org, x.schemes: https}
92 CFG: {x.prefix: example.org, x.schemes: https}
73 URI: http://example.org/foo
93 URI: http://example.org/foo
74 abort
94 abort
@@ -82,6 +102,10 b' URI: https://example.org/foo/bar'
82 ('x', 'x')
102 ('x', 'x')
83 URI: https://example.org/bar
103 URI: https://example.org/bar
84 ('x', 'x')
104 ('x', 'x')
105 URI: https://x@example.org/bar
106 ('x', 'x')
107 URI: https://y@example.org/bar
108 abort
85 CFG: {x.prefix: example.org, x.schemes: http https}
109 CFG: {x.prefix: example.org, x.schemes: http https}
86 URI: http://example.org/foo
110 URI: http://example.org/foo
87 ('x', 'x')
111 ('x', 'x')
@@ -95,6 +119,10 b' URI: https://example.org/foo/bar'
95 ('x', 'x')
119 ('x', 'x')
96 URI: https://example.org/bar
120 URI: https://example.org/bar
97 ('x', 'x')
121 ('x', 'x')
122 URI: https://x@example.org/bar
123 ('x', 'x')
124 URI: https://y@example.org/bar
125 abort
98
126
99 *** Test prefix matching
127 *** Test prefix matching
100
128
@@ -111,6 +139,10 b' URI: https://example.org/foo/bar'
111 abort
139 abort
112 URI: https://example.org/bar
140 URI: https://example.org/bar
113 abort
141 abort
142 URI: https://x@example.org/bar
143 abort
144 URI: https://y@example.org/bar
145 abort
114 CFG: {x.prefix: http://example.org/foo, y.prefix: http://example.org/foo/bar}
146 CFG: {x.prefix: http://example.org/foo, y.prefix: http://example.org/foo/bar}
115 URI: http://example.org/foo
147 URI: http://example.org/foo
116 ('x', 'x')
148 ('x', 'x')
@@ -124,6 +156,10 b' URI: https://example.org/foo/bar'
124 abort
156 abort
125 URI: https://example.org/bar
157 URI: https://example.org/bar
126 abort
158 abort
159 URI: https://x@example.org/bar
160 abort
161 URI: https://y@example.org/bar
162 abort
127 CFG: {x.prefix: *, y.prefix: https://example.org/bar}
163 CFG: {x.prefix: *, y.prefix: https://example.org/bar}
128 URI: http://example.org/foo
164 URI: http://example.org/foo
129 abort
165 abort
@@ -137,3 +173,19 b' URI: https://example.org/foo/bar'
137 ('x', 'x')
173 ('x', 'x')
138 URI: https://example.org/bar
174 URI: https://example.org/bar
139 ('y', 'y')
175 ('y', 'y')
176 URI: https://x@example.org/bar
177 ('x', 'x')
178 URI: https://y@example.org/bar
179 ('y', 'y')
180
181 *** Test user matching
182
183 CFG: {x.password: xpassword, x.prefix: http://example.org/foo, x.username: None}
184 URI: http://y@example.org/foo
185 ('y', 'xpassword')
186 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}
187 URI: http://y@example.org/foo
188 ('y', 'ypassword')
189 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}
190 URI: http://y@example.org/foo/bar
191 ('y', 'xpassword')
@@ -22,6 +22,28 b' Test raw style of hgweb'
22 $ sleep 1 # wait for server to scream and die
22 $ sleep 1 # wait for server to scream and die
23 $ cat getoutput.txt
23 $ cat getoutput.txt
24 200 Script output follows
24 200 Script output follows
25 content-type: application/binary
26 content-length: 157
27 content-disposition: inline; filename="some \"text\".txt"
28
29 This is just some random text
30 that will go inside the file and take a few lines.
31 It is very boring to read, but computers don't
32 care about things like that.
33 $ cat access.log error.log
34 127.0.0.1 - - [*] "GET /?f=a23bf1310f6e;file=sub/some%20%22text%22.txt;style=raw HTTP/1.1" 200 - (glob)
35
36 $ rm access.log error.log
37 $ hg serve -p $HGPORT -A access.log -E error.log -d --pid-file=hg.pid \
38 > --config web.guessmime=True
39
40 $ cat hg.pid >> $DAEMON_PIDS
41 $ ("$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 &
42 $ sleep 5
43 $ kill `cat hg.pid`
44 $ sleep 1 # wait for server to scream and die
45 $ cat getoutput.txt
46 200 Script output follows
25 content-type: text/plain; charset="ascii"
47 content-type: text/plain; charset="ascii"
26 content-length: 157
48 content-length: 157
27 content-disposition: inline; filename="some \"text\".txt"
49 content-disposition: inline; filename="some \"text\".txt"
General Comments 0
You need to be logged in to leave comments. Login now