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