comparison mercurial/hgweb/hgweb_mod.py @ 5561:22713dce19f6

hgweb: return meaningful HTTP status codes instead of nonsense
author Bryan O'Sullivan <bos@serpentine.com>
date Wed, 28 Nov 2007 08:38:42 -0800
parents 48c22c719f8c
children d61fea133f2d
comparison
equal deleted inserted replaced
5560:e78c24011001 5561:22713dce19f6
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com> 4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 # 5 #
6 # This software may be used and distributed according to the terms 6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference. 7 # of the GNU General Public License, incorporated herein by reference.
8 8
9 import os, mimetypes, re, zlib, mimetools, cStringIO, sys 9 import errno, os, mimetypes, re, zlib, mimetools, cStringIO, sys
10 import tempfile, urllib, bz2 10 import tempfile, urllib, bz2
11 from mercurial.node import * 11 from mercurial.node import *
12 from mercurial.i18n import gettext as _ 12 from mercurial.i18n import gettext as _
13 from mercurial import mdiff, ui, hg, util, archival, streamclone, patch 13 from mercurial import mdiff, ui, hg, util, archival, streamclone, patch
14 from mercurial import revlog, templater 14 from mercurial import revlog, templater
15 from common import get_mtime, staticfile, style_map, paritygen 15 from common import ErrorResponse, get_mtime, staticfile, style_map, paritygen
16 16
17 def _up(p): 17 def _up(p):
18 if p[0] != "/": 18 if p[0] != "/":
19 p = "/" + p 19 p = "/" + p
20 if p[-1] == "/": 20 if p[-1] == "/":
476 files[short] = (f, None) 476 files[short] = (f, None)
477 else: 477 else:
478 short = os.path.basename(remain) 478 short = os.path.basename(remain)
479 files[short] = (f, n) 479 files[short] = (f, n)
480 480
481 if not files:
482 raise ErrorResponse(404, 'Path not found: ' + path)
483
481 def filelist(**map): 484 def filelist(**map):
482 fl = files.keys() 485 fl = files.keys()
483 fl.sort() 486 fl.sort()
484 for f in fl: 487 for f in fl:
485 full, fnode = files[f] 488 full, fnode = files[f]
843 if not req.form.has_key('cmd'): 846 if not req.form.has_key('cmd'):
844 req.form['cmd'] = [self.t.cache['default']] 847 req.form['cmd'] = [self.t.cache['default']]
845 848
846 cmd = req.form['cmd'][0] 849 cmd = req.form['cmd'][0]
847 850
848 method = getattr(self, 'do_' + cmd, None) 851 try:
849 if method: 852 method = getattr(self, 'do_' + cmd)
850 try: 853 method(req)
851 method(req) 854 except revlog.LookupError, err:
852 except (hg.RepoError, revlog.RevlogError), inst: 855 req.respond(404, self.t(
853 req.write(self.t("error", error=str(inst))) 856 'error', error='revision not found: %s' % err.name))
854 else: 857 except (hg.RepoError, revlog.RevlogError), inst:
855 req.write(self.t("error", error='No such method: ' + cmd)) 858 req.respond('500 Internal Server Error',
859 self.t('error', error=str(inst)))
860 except ErrorResponse, inst:
861 req.respond(inst.code, self.t('error', error=inst.message))
862 except AttributeError:
863 req.respond(400,
864 self.t('error', error='No such method: ' + cmd))
856 finally: 865 finally:
857 self.t = None 866 self.t = None
858 867
859 def changectx(self, req): 868 def changectx(self, req):
860 if req.form.has_key('node'): 869 if req.form.has_key('node'):
1036 if (type_ in self.archives and (type_ in allowed or 1045 if (type_ in self.archives and (type_ in allowed or
1037 self.configbool("web", "allow" + type_, False))): 1046 self.configbool("web", "allow" + type_, False))):
1038 self.archive(req, req.form['node'][0], type_) 1047 self.archive(req, req.form['node'][0], type_)
1039 return 1048 return
1040 1049
1041 req.write(self.t("error")) 1050 req.respond(400, self.t('error',
1051 error='Unsupported archive type: %s' % type_))
1042 1052
1043 def do_static(self, req): 1053 def do_static(self, req):
1044 fname = req.form['file'][0] 1054 fname = req.form['file'][0]
1045 # a repo owner may set web.static in .hg/hgrc to get any file 1055 # a repo owner may set web.static in .hg/hgrc to get any file
1046 # readable by the user running the CGI script 1056 # readable by the user running the CGI script
1047 static = self.config("web", "static", 1057 static = self.config("web", "static",
1048 os.path.join(self.templatepath, "static"), 1058 os.path.join(self.templatepath, "static"),
1049 untrusted=False) 1059 untrusted=False)
1050 req.write(staticfile(static, fname, req) 1060 req.write(staticfile(static, fname, req))
1051 or self.t("error", error="%r not found" % fname))
1052 1061
1053 def do_capabilities(self, req): 1062 def do_capabilities(self, req):
1054 caps = ['lookup', 'changegroupsubset'] 1063 caps = ['lookup', 'changegroupsubset']
1055 if self.configbool('server', 'uncompressed'): 1064 if self.configbool('server', 'uncompressed'):
1056 caps.append('stream=%d' % self.repo.changelog.version) 1065 caps.append('stream=%d' % self.repo.changelog.version)
1196 if filename.startswith(self.repo.root): 1205 if filename.startswith(self.repo.root):
1197 filename = filename[len(self.repo.root)+1:] 1206 filename = filename[len(self.repo.root)+1:]
1198 else: 1207 else:
1199 filename = '' 1208 filename = ''
1200 error = getattr(inst, 'strerror', 'Unknown error') 1209 error = getattr(inst, 'strerror', 'Unknown error')
1201 req.write('%s: %s\n' % (error, filename)) 1210 if inst.errno == errno.ENOENT:
1211 code = 404
1212 else:
1213 code = 500
1214 req.respond(code, '%s: %s\n' % (error, filename))
1202 finally: 1215 finally:
1203 fp.close() 1216 fp.close()
1204 os.unlink(tempname) 1217 os.unlink(tempname)
1205 1218
1206 def do_stream_out(self, req): 1219 def do_stream_out(self, req):