##// 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 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 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
@@ -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 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
@@ -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 return errorfmt % 'unsynced changes',
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