Show More
@@ -10,7 +10,9 b' import errno, mimetypes, os' | |||||
10 |
|
10 | |||
11 | HTTP_OK = 200 |
|
11 | HTTP_OK = 200 | |
12 | HTTP_BAD_REQUEST = 400 |
|
12 | HTTP_BAD_REQUEST = 400 | |
|
13 | HTTP_UNAUTHORIZED = 401 | |||
13 | HTTP_NOT_FOUND = 404 |
|
14 | HTTP_NOT_FOUND = 404 | |
|
15 | HTTP_METHOD_NOT_ALLOWED = 405 | |||
14 | HTTP_SERVER_ERROR = 500 |
|
16 | HTTP_SERVER_ERROR = 500 | |
15 |
|
17 | |||
16 | class ErrorResponse(Exception): |
|
18 | class ErrorResponse(Exception): |
@@ -13,6 +13,7 b' from mercurial import mdiff, ui, hg, uti' | |||||
13 | from mercurial import revlog, templater, templatefilters |
|
13 | from mercurial import revlog, templater, templatefilters | |
14 | from common import get_mtime, style_map, paritygen, countgen, ErrorResponse |
|
14 | from common import get_mtime, style_map, paritygen, countgen, ErrorResponse | |
15 | from common import HTTP_OK, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR |
|
15 | from common import HTTP_OK, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR | |
|
16 | from common import HTTP_UNAUTHORIZED, HTTP_METHOD_NOT_ALLOWED | |||
16 | from request import wsgirequest |
|
17 | from request import wsgirequest | |
17 | import webcommands, protocol, webutil |
|
18 | import webcommands, protocol, webutil | |
18 |
|
19 | |||
@@ -88,10 +89,16 b' class hgweb(object):' | |||||
88 |
|
89 | |||
89 | cmd = req.form.get('cmd', [''])[0] |
|
90 | cmd = req.form.get('cmd', [''])[0] | |
90 | if cmd and cmd in protocol.__all__: |
|
91 | if cmd and cmd in protocol.__all__: | |
91 | if cmd in perms and not self.check_perm(req, perms[cmd]): |
|
92 | try: | |
92 |
|
|
93 | if cmd in perms: | |
93 | method = getattr(protocol, cmd) |
|
94 | self.check_perm(req, perms[cmd]) | |
94 | return method(self.repo, req) |
|
95 | method = getattr(protocol, cmd) | |
|
96 | return method(self.repo, req) | |||
|
97 | except ErrorResponse, inst: | |||
|
98 | req.respond(inst.code, protocol.HGTYPE) | |||
|
99 | if not inst.message: | |||
|
100 | return [] | |||
|
101 | return '0\n%s\n' % inst.message, | |||
95 |
|
102 | |||
96 | # work with CGI variables to create coherent structure |
|
103 | # work with CGI variables to create coherent structure | |
97 | # use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME |
|
104 | # use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME | |
@@ -344,35 +351,29 b' class hgweb(object):' | |||||
344 | '''Check permission for operation based on request data (including |
|
351 | '''Check permission for operation based on request data (including | |
345 | authentication info. Return true if op allowed, else false.''' |
|
352 | authentication info. Return true if op allowed, else false.''' | |
346 |
|
353 | |||
347 | def error(status, message): |
|
354 | if op == 'pull' and not self.allowpull: | |
348 | req.respond(status, protocol.HGTYPE) |
|
355 | raise ErrorResponse(HTTP_OK, '') | |
349 | req.write('0\n%s\n' % message) |
|
356 | elif op == 'pull': | |
350 |
|
357 | return | ||
351 | if op == 'pull': |
|
|||
352 | return self.allowpull |
|
|||
353 |
|
358 | |||
354 | # enforce that you can only push using POST requests |
|
359 | # enforce that you can only push using POST requests | |
355 | if req.env['REQUEST_METHOD'] != 'POST': |
|
360 | if req.env['REQUEST_METHOD'] != 'POST': | |
356 |
|
|
361 | msg = 'push requires POST request' | |
357 | return False |
|
362 | raise ErrorResponse(HTTP_METHOD_NOT_ALLOWED, msg) | |
358 |
|
363 | |||
359 | # require ssl by default for pushing, auth info cannot be sniffed |
|
364 | # require ssl by default for pushing, auth info cannot be sniffed | |
360 | # and replayed |
|
365 | # and replayed | |
361 | scheme = req.env.get('wsgi.url_scheme') |
|
366 | scheme = req.env.get('wsgi.url_scheme') | |
362 | if self.configbool('web', 'push_ssl', True) and scheme != 'https': |
|
367 | if self.configbool('web', 'push_ssl', True) and scheme != 'https': | |
363 | error(HTTP_OK, 'ssl required') |
|
368 | raise ErrorResponse(HTTP_OK, 'ssl required') | |
364 | return False |
|
|||
365 |
|
369 | |||
366 | user = req.env.get('REMOTE_USER') |
|
370 | user = req.env.get('REMOTE_USER') | |
367 |
|
371 | |||
368 | deny = self.configlist('web', 'deny_push') |
|
372 | deny = self.configlist('web', 'deny_push') | |
369 | if deny and (not user or deny == ['*'] or user in deny): |
|
373 | if deny and (not user or deny == ['*'] or user in deny): | |
370 |
error( |
|
374 | raise ErrorResponse(HTTP_UNAUTHORIZED, 'push not authorized') | |
371 | return False |
|
|||
372 |
|
375 | |||
373 | allow = self.configlist('web', 'allow_push') |
|
376 | allow = self.configlist('web', 'allow_push') | |
374 | result = allow and (allow == ['*'] or user in allow) |
|
377 | result = allow and (allow == ['*'] or user in allow) | |
375 | if not result: |
|
378 | if not result: | |
376 |
error( |
|
379 | raise ErrorResponse(HTTP_UNAUTHORIZED, 'push not authorized') | |
377 |
|
||||
378 | return result |
|
@@ -108,7 +108,6 b' def capabilities(repo, req):' | |||||
108 |
|
108 | |||
109 | def unbundle(repo, req): |
|
109 | def unbundle(repo, req): | |
110 |
|
110 | |||
111 | errorfmt = '0\n%s\n' |
|
|||
112 | proto = req.env.get('wsgi.url_scheme') or 'http' |
|
111 | proto = req.env.get('wsgi.url_scheme') or 'http' | |
113 | their_heads = req.form['heads'][0].split(' ') |
|
112 | their_heads = req.form['heads'][0].split(' ') | |
114 |
|
113 | |||
@@ -123,10 +122,7 b' def unbundle(repo, req):' | |||||
123 | # drain incoming bundle, else client will not see |
|
122 | # drain incoming bundle, else client will not see | |
124 | # response when run outside cgi script |
|
123 | # response when run outside cgi script | |
125 | pass |
|
124 | pass | |
126 | req.respond(HTTP_OK, HGTYPE) |
|
125 | raise ErrorResponse(HTTP_OK, 'unsynced changes') | |
127 | return errorfmt % 'unsynced changes', |
|
|||
128 |
|
||||
129 | req.respond(HTTP_OK, HGTYPE) |
|
|||
130 |
|
126 | |||
131 | # do not lock repo until all changegroup data is |
|
127 | # do not lock repo until all changegroup data is | |
132 | # streamed. save to temporary file. |
|
128 | # streamed. save to temporary file. | |
@@ -142,7 +138,7 b' def unbundle(repo, req):' | |||||
142 | lock = repo.lock() |
|
138 | lock = repo.lock() | |
143 | try: |
|
139 | try: | |
144 | if not check_heads(): |
|
140 | if not check_heads(): | |
145 |
re |
|
141 | raise ErrorResponse(HTTP_OK, 'unsynced changes') | |
146 |
|
142 | |||
147 | fp.seek(0) |
|
143 | fp.seek(0) | |
148 | header = fp.read(6) |
|
144 | header = fp.read(6) | |
@@ -168,11 +164,12 b' def unbundle(repo, req):' | |||||
168 | finally: |
|
164 | finally: | |
169 | val = sys.stdout.getvalue() |
|
165 | val = sys.stdout.getvalue() | |
170 | sys.stdout, sys.stderr = oldio |
|
166 | sys.stdout, sys.stderr = oldio | |
|
167 | req.respond(HTTP_OK, HGTYPE) | |||
171 | return '%d\n%s' % (ret, val), |
|
168 | return '%d\n%s' % (ret, val), | |
172 | finally: |
|
169 | finally: | |
173 | del lock |
|
170 | del lock | |
174 | except ValueError, inst: |
|
171 | except ValueError, inst: | |
175 | return errorfmt % inst, |
|
172 | raise ErrorResponse(HTTP_OK, inst) | |
176 | except (OSError, IOError), inst: |
|
173 | except (OSError, IOError), inst: | |
177 | filename = getattr(inst, 'filename', '') |
|
174 | filename = getattr(inst, 'filename', '') | |
178 | # Don't send our filesystem layout to the client |
|
175 | # Don't send our filesystem layout to the client | |
@@ -185,8 +182,7 b' def unbundle(repo, req):' | |||||
185 | code = HTTP_NOT_FOUND |
|
182 | code = HTTP_NOT_FOUND | |
186 | else: |
|
183 | else: | |
187 | code = HTTP_SERVER_ERROR |
|
184 | code = HTTP_SERVER_ERROR | |
188 | req.respond(code) |
|
185 | raise ErrorResponse(code, '%s: %s' % (error, filename)) | |
189 | return '0\n%s: %s\n' % (error, filename), |
|
|||
190 | finally: |
|
186 | finally: | |
191 | fp.close() |
|
187 | fp.close() | |
192 | os.unlink(tempname) |
|
188 | os.unlink(tempname) |
General Comments 0
You need to be logged in to leave comments.
Login now