Mercurial > hg
comparison mercurial/hgweb/hgweb_mod.py @ 6926:57b954d8d003
hgweb: raise ErrorResponses to communicate protocol errors
author | Dirkjan Ochtman <dirkjan@ochtman.nl> |
---|---|
date | Tue, 22 Jul 2008 18:23:20 +0200 |
parents | 95f35b553ae6 |
children | 2cfdabe235fb |
comparison
equal
deleted
inserted
replaced
6925:87abfefafe02 | 6926:57b954d8d003 |
---|---|
11 from mercurial.repo import RepoError | 11 from mercurial.repo import RepoError |
12 from mercurial import mdiff, ui, hg, util, patch, hook | 12 from mercurial import mdiff, ui, hg, util, patch, hook |
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 |
19 perms = { | 20 perms = { |
20 'changegroup': 'pull', | 21 'changegroup': 'pull', |
86 # protocol bits don't need to create any URLs | 87 # protocol bits don't need to create any URLs |
87 # and the clients always use the old URL structure | 88 # and the clients always use the old URL structure |
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 return [] | 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 |
98 | 105 |
99 req.url = req.env['SCRIPT_NAME'] | 106 req.url = req.env['SCRIPT_NAME'] |
342 | 349 |
343 def check_perm(self, req, op): | 350 def check_perm(self, req, op): |
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 error('405 Method Not Allowed', 'push requires POST request') | 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('401 Unauthorized', 'push not authorized') | 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('401 Unauthorized', 'push not authorized') | 379 raise ErrorResponse(HTTP_UNAUTHORIZED, 'push not authorized') |
377 | |
378 return result |