--- a/mercurial/hgweb.py Fri Feb 10 11:25:07 2006 -0800
+++ b/mercurial/hgweb.py Fri Mar 03 09:39:37 2006 -0800
@@ -7,6 +7,7 @@
# of the GNU General Public License, incorporated herein by reference.
import os, cgi, sys, urllib
+import mimetypes
from demandload import demandload
demandload(globals(), "mdiff time re socket zlib errno ui hg ConfigParser")
demandload(globals(), "zipfile tempfile StringIO tarfile BaseHTTPServer util")
@@ -18,7 +19,7 @@
for f in "templates", "../templates":
p = os.path.join(os.path.dirname(__file__), f)
if os.path.isdir(p):
- return p
+ return os.path.normpath(p)
def age(x):
def plural(t, c):
@@ -71,6 +72,30 @@
else:
return os.stat(hg_path).st_mtime
+def staticfile(directory, fname):
+ """return a file inside directory with guessed content-type header
+
+ fname always uses '/' as directory separator and isn't allowed to
+ contain unusual path components.
+ Content-type is guessed using the mimetypes module.
+ Return an empty string if fname is illegal or file not found.
+
+ """
+ parts = fname.split('/')
+ path = directory
+ for part in parts:
+ if (part in ('', os.curdir, os.pardir) or
+ os.sep in part or os.altsep is not None and os.altsep in part):
+ return ""
+ path = os.path.join(path, part)
+ try:
+ os.stat(path)
+ ct = mimetypes.guess_type(path)[0] or "text/plain"
+ return "Content-type: %s\n\n%s" % (ct, file(path).read())
+ except (TypeError, OSError):
+ # illegal fname or unreadable file
+ return ""
+
class hgrequest(object):
def __init__(self, inp=None, out=None, env=None):
self.inp = inp or sys.stdin
@@ -660,9 +685,10 @@
i = self.repo.tagslist()
i.reverse()
- def entries(**map):
+ def entries(notip=False, **map):
parity = 0
for k,n in i:
+ if notip and k == "tip": continue
yield {"parity": parity,
"tag": k,
"tagmanifest": hex(cl.read(n)[0]),
@@ -672,7 +698,8 @@
yield self.t("tags",
manifest=hex(mf),
- entries=entries)
+ entries=lambda **x: entries(False, **x),
+ entriesnotip=lambda **x: entries(True, **x))
def summary(self):
cl = self.repo.changelog
@@ -843,6 +870,7 @@
'ca': [('cmd', ['archive']), ('node', None)],
'tags': [('cmd', ['tags'])],
'tip': [('cmd', ['changeset']), ('node', ['tip'])],
+ 'static': [('cmd', ['static']), ('file', None)]
}
for k in shortcuts.iterkeys():
@@ -858,6 +886,7 @@
expand_form(req.form)
t = self.repo.ui.config("web", "templates", templatepath())
+ static = self.repo.ui.config("web", "static", os.path.join(t,"static"))
m = os.path.join(t, "map")
style = self.repo.ui.config("web", "style", "")
if req.form.has_key('style'):
@@ -962,7 +991,7 @@
nodes = map(bin, req.form['roots'][0].split(" "))
z = zlib.compressobj()
- f = self.repo.changegroup(nodes)
+ f = self.repo.changegroup(nodes, 'serve')
while 1:
chunk = f.read(4096)
if not chunk:
@@ -981,6 +1010,11 @@
req.write(self.t("error"))
+ elif req.form['cmd'][0] == 'static':
+ fname = req.form['file'][0]
+ req.write(staticfile(static, fname)
+ or self.t("error", error="%r not found" % fname))
+
else:
req.write(self.t("error"))
@@ -1152,4 +1186,10 @@
else:
req.write(tmpl("notfound", repo=virtual))
else:
- req.write(tmpl("index", entries=entries))
+ if req.form.has_key('static'):
+ static = os.path.join(templatepath(), "static")
+ fname = req.form['static'][0]
+ req.write(staticfile(static, fname)
+ or tmpl("error", error="%r not found" % fname))
+ else:
+ req.write(tmpl("index", entries=entries))