--- a/mercurial/hgweb/common.py Fri Feb 01 10:31:09 2008 +0100
+++ b/mercurial/hgweb/common.py Fri Feb 01 10:31:13 2008 +0100
@@ -8,6 +8,11 @@
import errno, mimetypes, os
+HTTP_OK = 200
+HTTP_BAD_REQUEST = 400
+HTTP_NOT_FOUND = 404
+HTTP_SERVER_ERROR = 500
+
class ErrorResponse(Exception):
def __init__(self, code, message=None):
Exception.__init__(self)
@@ -54,18 +59,15 @@
try:
os.stat(path)
ct = mimetypes.guess_type(path)[0] or "text/plain"
- req.header([
- ('Content-Type', ct),
- ('Content-Length', str(os.path.getsize(path)))
- ])
+ req.respond(HTTP_OK, ct, length = os.path.getsize(path))
return file(path, 'rb').read()
except TypeError:
- raise ErrorResponse(500, 'illegal file name')
+ raise ErrorResponse(HTTP_SERVER_ERROR, 'illegal file name')
except OSError, err:
if err.errno == errno.ENOENT:
- raise ErrorResponse(404)
+ raise ErrorResponse(HTTP_NOT_FOUND)
else:
- raise ErrorResponse(500, err.strerror)
+ raise ErrorResponse(HTTP_SERVER_ERROR, err.strerror)
def style_map(templatepath, style):
"""Return path to mapfile for a given style.
--- a/mercurial/hgweb/hgweb_mod.py Fri Feb 01 10:31:09 2008 +0100
+++ b/mercurial/hgweb/hgweb_mod.py Fri Feb 01 10:31:13 2008 +0100
@@ -11,6 +11,7 @@
from mercurial import mdiff, ui, hg, util, archival, patch, hook
from mercurial import revlog, templater, templatefilters
from common import ErrorResponse, get_mtime, style_map, paritygen, get_contact
+from common import HTTP_OK, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
from request import wsgirequest
import webcommands, protocol
@@ -207,27 +208,35 @@
method(self, req)
else:
tmpl = self.templater(req)
+ ctype = tmpl('mimetype', encoding=self.encoding)
+ ctype = templater.stringify(ctype)
+
if cmd == '':
req.form['cmd'] = [tmpl.cache['default']]
cmd = req.form['cmd'][0]
if cmd not in webcommands.__all__:
- raise ErrorResponse(400, 'No such method: ' + cmd)
+ msg = 'No such method: %s' % cmd
+ raise ErrorResponse(HTTP_BAD_REQUEST, msg)
elif cmd == 'file' and 'raw' in req.form.get('style', []):
+ self.ctype = ctype
content = webcommands.rawfile(self, req, tmpl)
else:
content = getattr(webcommands, cmd)(self, req, tmpl)
+ req.respond(HTTP_OK, ctype)
req.write(content)
del tmpl
except revlog.LookupError, err:
- req.respond(404, tmpl(
- 'error', error='revision not found: %s' % err.name))
+ req.respond(HTTP_NOT_FOUND, ctype)
+ req.write(tmpl('error', error='revision not found: %s' % err.name))
except (hg.RepoError, revlog.RevlogError), inst:
- req.respond(500, tmpl('error', error=str(inst)))
+ req.respond(HTTP_SERVER_ERROR, ctype)
+ req.write(tmpl('error', error=str(inst)))
except ErrorResponse, inst:
- req.respond(inst.code, tmpl('error', error=inst.message))
+ req.respond(inst.code, ctype)
+ req.write(tmpl('error', error=inst.message))
def templater(self, req):
@@ -252,8 +261,6 @@
# some functions for the templater
def header(**map):
- ctype = tmpl('mimetype', encoding=self.encoding)
- req.httphdr(templater.stringify(ctype))
yield tmpl('header', encoding=self.encoding, **map)
def footer(**map):
@@ -668,7 +675,7 @@
files[short] = (f, n)
if not files:
- raise ErrorResponse(404, 'Path not found: ' + path)
+ raise ErrorResponse(HTTP_NOT_FOUND, 'Path not found: ' + path)
def filelist(**map):
fl = files.keys()
@@ -846,6 +853,7 @@
if encoding:
headers.append(('Content-Encoding', encoding))
req.header(headers)
+ req.respond(HTTP_OK)
archival.archive(self.repo, req, cnode, artype, prefix=name)
# add tags to things
--- a/mercurial/hgweb/hgwebdir_mod.py Fri Feb 01 10:31:09 2008 +0100
+++ b/mercurial/hgweb/hgwebdir_mod.py Fri Feb 01 10:31:13 2008 +0100
@@ -10,7 +10,7 @@
from mercurial.i18n import gettext as _
from mercurial import ui, hg, util, templater, templatefilters
from common import ErrorResponse, get_mtime, staticfile, style_map, paritygen,\
- get_contact
+ get_contact, HTTP_OK, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
from hgweb_mod import hgweb
from request import wsgirequest
@@ -76,6 +76,9 @@
try:
virtual = req.env.get("PATH_INFO", "").strip('/')
+ tmpl = self.templater(req)
+ ctype = tmpl('mimetype', encoding=util._encoding)
+ ctype = templater.stringify(ctype)
# a static file
if virtual.startswith('static/') or 'static' in req.form:
@@ -89,11 +92,12 @@
# top-level index
elif not virtual:
- tmpl = self.templater(req)
+ req.respond(HTTP_OK, ctype)
req.write(self.makeindex(req, tmpl))
return
# nested indexes and hgwebs
+
repos = dict(self.repos)
while virtual:
real = repos.get(virtual)
@@ -104,14 +108,15 @@
hgweb(repo).run_wsgi(req)
return
except IOError, inst:
- raise ErrorResponse(500, inst.strerror)
+ msg = inst.strerror
+ raise ErrorResponse(HTTP_SERVER_ERROR, msg)
except hg.RepoError, inst:
- raise ErrorResponse(500, str(inst))
+ raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
# browse subdirectories
subdir = virtual + '/'
if [r for r in repos if r.startswith(subdir)]:
- tmpl = self.templater(req)
+ req.respond(HTTP_OK, ctype)
req.write(self.makeindex(req, tmpl, subdir))
return
@@ -121,12 +126,12 @@
virtual = virtual[:up]
# prefixes not found
- tmpl = self.templater(req)
- req.respond(404, tmpl("notfound", repo=virtual))
+ req.respond(HTTP_NOT_FOUND, ctype)
+ req.write(tmpl("notfound", repo=virtual))
except ErrorResponse, err:
- tmpl = self.templater(req)
- req.respond(err.code, tmpl('error', error=err.message or ''))
+ req.respond(err.code, ctype)
+ req.write(tmpl('error', error=err.message or ''))
finally:
tmpl = None
@@ -234,8 +239,6 @@
def templater(self, req):
def header(**map):
- ctype = tmpl('mimetype', encoding=util._encoding)
- req.httphdr(templater.stringify(ctype))
yield tmpl('header', encoding=util._encoding, **map)
def footer(**map):
--- a/mercurial/hgweb/protocol.py Fri Feb 01 10:31:09 2008 +0100
+++ b/mercurial/hgweb/protocol.py Fri Feb 01 10:31:13 2008 +0100
@@ -9,6 +9,7 @@
from mercurial import util, streamclone
from mercurial.i18n import gettext as _
from mercurial.node import *
+from common import HTTP_OK, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
# __all__ is populated with the allowed commands. Be sure to add to it if
# you're adding a new command, or the new command won't work.
@@ -18,6 +19,8 @@
'changegroupsubset', 'capabilities', 'unbundle', 'stream_out',
]
+HGTYPE = 'application/mercurial-0.1'
+
def lookup(web, req):
try:
r = hex(web.repo.lookup(req.form['key'][0]))
@@ -26,12 +29,12 @@
r = str(inst)
success = 0
resp = "%s %s\n" % (success, r)
- req.httphdr("application/mercurial-0.1", length=len(resp))
+ req.respond(HTTP_OK, HGTYPE, length=len(resp))
req.write(resp)
def heads(web, req):
resp = " ".join(map(hex, web.repo.heads())) + "\n"
- req.httphdr("application/mercurial-0.1", length=len(resp))
+ req.respond(HTTP_OK, HGTYPE, length=len(resp))
req.write(resp)
def branches(web, req):
@@ -42,7 +45,7 @@
for b in web.repo.branches(nodes):
resp.write(" ".join(map(hex, b)) + "\n")
resp = resp.getvalue()
- req.httphdr("application/mercurial-0.1", length=len(resp))
+ req.respond(HTTP_OK, HGTYPE, length=len(resp))
req.write(resp)
def between(web, req):
@@ -53,11 +56,11 @@
for b in web.repo.between(pairs):
resp.write(" ".join(map(hex, b)) + "\n")
resp = resp.getvalue()
- req.httphdr("application/mercurial-0.1", length=len(resp))
+ req.respond(HTTP_OK, HGTYPE, length=len(resp))
req.write(resp)
def changegroup(web, req):
- req.httphdr("application/mercurial-0.1")
+ req.respond(HTTP_OK, HGTYPE)
nodes = []
if not web.allowpull:
return
@@ -76,7 +79,7 @@
req.write(z.flush())
def changegroupsubset(web, req):
- req.httphdr("application/mercurial-0.1")
+ req.respond(HTTP_OK, HGTYPE)
bases = []
heads = []
if not web.allowpull:
@@ -106,7 +109,7 @@
if unbundleversions:
caps.append('unbundle=%s' % ','.join(unbundleversions))
resp = ' '.join(caps)
- req.httphdr("application/mercurial-0.1", length=len(resp))
+ req.respond(HTTP_OK, HGTYPE, length=len(resp))
req.write(resp)
def unbundle(web, req):
@@ -116,7 +119,8 @@
# drain incoming bundle, else client will not see
# response when run outside cgi script
pass
- req.httphdr("application/mercurial-0.1", headers=headers)
+ req.header(headers.items())
+ req.respond(HTTP_OK, HGTYPE)
req.write('0\n')
req.write(response)
@@ -148,7 +152,7 @@
bail(_('unsynced changes\n'))
return
- req.httphdr("application/mercurial-0.1")
+ req.respond(HTTP_OK, HGTYPE)
# do not lock repo until all changegroup data is
# streamed. save to temporary file.
@@ -232,14 +236,15 @@
filename = ''
error = getattr(inst, 'strerror', 'Unknown error')
if inst.errno == errno.ENOENT:
- code = 404
+ code = HTTP_NOT_FOUND
else:
- code = 500
- req.respond(code, '%s: %s\n' % (error, filename))
+ code = HTTP_SERVER_ERROR
+ req.respond(code)
+ req.write('%s: %s\n' % (error, filename))
finally:
fp.close()
os.unlink(tempname)
def stream_out(web, req):
- req.httphdr("application/mercurial-0.1")
+ req.respond(HTTP_OK, HGTYPE)
streamclone.stream_out(web.repo, req, untrusted=True)
--- a/mercurial/hgweb/request.py Fri Feb 01 10:31:09 2008 +0100
+++ b/mercurial/hgweb/request.py Fri Feb 01 10:31:13 2008 +0100
@@ -17,7 +17,6 @@
raise RuntimeError("Unknown and unsupported WSGI version %d.%d"
% version)
self.inp = wsgienv['wsgi.input']
- self.server_write = None
self.err = wsgienv['wsgi.errors']
self.threaded = wsgienv['wsgi.multithread']
self.multiprocess = wsgienv['wsgi.multiprocess']
@@ -25,6 +24,7 @@
self.env = wsgienv
self.form = cgi.parse(self.inp, self.env, keep_blank_values=1)
self._start_response = start_response
+ self.server_write = None
self.headers = []
def __iter__(self):
@@ -33,8 +33,10 @@
def read(self, count=-1):
return self.inp.read(count)
- def start_response(self, status):
+ def respond(self, status, type=None, filename=None, length=0):
if self._start_response is not None:
+
+ self.httphdr(type, filename, length)
if not self.headers:
raise RuntimeError("request.write called before headers sent")
@@ -44,6 +46,8 @@
if isinstance(status, ErrorResponse):
status = statusmessage(status.code)
+ elif status == 200:
+ status = '200 Script output follows'
elif isinstance(status, int):
status = statusmessage(status)
@@ -51,24 +55,17 @@
self._start_response = None
self.headers = []
- def respond(self, status, *things):
- if not things:
- self.start_response(status)
- for thing in things:
- if hasattr(thing, "__iter__"):
- for part in thing:
- self.respond(status, part)
- else:
- thing = str(thing)
- self.start_response(status)
- try:
- self.server_write(thing)
- except socket.error, inst:
- if inst[0] != errno.ECONNRESET:
- raise
-
- def write(self, *things):
- self.respond('200 Script output follows', *things)
+ def write(self, thing):
+ if hasattr(thing, "__iter__"):
+ for part in thing:
+ self.write(part)
+ else:
+ thing = str(thing)
+ try:
+ self.server_write(thing)
+ except socket.error, inst:
+ if inst[0] != errno.ECONNRESET:
+ raise
def writelines(self, lines):
for line in lines:
@@ -83,9 +80,10 @@
def header(self, headers=[('Content-Type','text/html')]):
self.headers.extend(headers)
- def httphdr(self, type, filename=None, length=0, headers={}):
+ def httphdr(self, type=None, filename=None, length=0, headers={}):
headers = headers.items()
- headers.append(('Content-Type', type))
+ if type is not None:
+ headers.append(('Content-Type', type))
if filename:
headers.append(('Content-Disposition', 'inline; filename=%s' %
filename))
--- a/mercurial/hgweb/webcommands.py Fri Feb 01 10:31:09 2008 +0100
+++ b/mercurial/hgweb/webcommands.py Fri Feb 01 10:31:13 2008 +0100
@@ -7,7 +7,7 @@
import os, mimetypes
from mercurial import revlog, util, hg
-from common import staticfile, ErrorResponse
+from common import staticfile, ErrorResponse, HTTP_OK, HTTP_NOT_FOUND
# __all__ is populated with the allowed commands. Be sure to add to it if
# you're adding a new command, or the new command won't work.
@@ -27,12 +27,16 @@
def rawfile(web, req, tmpl):
path = web.cleanpath(req.form.get('file', [''])[0])
if not path:
- return web.manifest(tmpl, web.changectx(req), path)
+ content = web.manifest(tmpl, web.changectx(req), path)
+ req.respond(HTTP_OK, web.ctype)
+ return content
try:
fctx = web.filectx(req)
except revlog.LookupError:
- return web.manifest(tmpl, web.changectx(req), path)
+ content = web.manifest(tmpl, web.changectx(req), path)
+ req.respond(HTTP_OK, web.ctype)
+ return content
path = fctx.path()
text = fctx.data()
@@ -40,7 +44,7 @@
if mt is None or util.binary(text):
mt = mt or 'application/octet-stream'
- req.httphdr(mt, path, len(text))
+ req.respond(HTTP_OK, mt, path, len(text))
return [text]
def file(web, req, tmpl):
@@ -104,8 +108,7 @@
web.configbool("web", "allow" + type_, False))):
web.archive(tmpl, req, req.form['node'][0], type_)
return []
-
- raise ErrorResponse(400, 'Unsupported archive type: %s' % type_)
+ raise ErrorResponse(HTTP_NOT_FOUND, 'Unsupported archive type: %s' % type_)
def static(web, req, tmpl):
fname = req.form['file'][0]