# HG changeset patch # User Eric Hopper # Date 1151425992 25200 # Node ID 419c42223bee1eb4bdf652266679507a41e16547 # Parent f22e3e8fd4576c7f8b362454de9fa7eeaeb391bb Really fix http headers for web UI and issue 254. This also arranges for static content to allow a keepalive connection. diff --git a/mercurial/hgweb/common.py b/mercurial/hgweb/common.py --- a/mercurial/hgweb/common.py +++ b/mercurial/hgweb/common.py @@ -17,7 +17,7 @@ def get_mtime(repo_path): else: return os.stat(hg_path).st_mtime -def staticfile(directory, fname): +def staticfile(directory, fname, req): """return a file inside directory with guessed content-type header fname always uses '/' as directory separator and isn't allowed to @@ -36,7 +36,9 @@ def staticfile(directory, fname): try: os.stat(path) ct = mimetypes.guess_type(path)[0] or "text/plain" - return "Content-type: %s\n\n%s" % (ct, file(path).read()) + req.header([('Content-type', ct), + ('Content-length', os.path.getsize(path))]) + return file(path).read() except (TypeError, OSError): # illegal fname or unreadable file return "" diff --git a/mercurial/hgweb/hgweb_mod.py b/mercurial/hgweb/hgweb_mod.py --- a/mercurial/hgweb/hgweb_mod.py +++ b/mercurial/hgweb/hgweb_mod.py @@ -10,7 +10,7 @@ import os import os.path import mimetypes from mercurial.demandload import demandload -demandload(globals(), "re zlib ConfigParser cStringIO sys tempfile") +demandload(globals(), "re zlib ConfigParser mimetools cStringIO sys tempfile") demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,templater") demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile") from mercurial.node import * @@ -652,7 +652,10 @@ class hgweb(object): def run(self, req): def header(**map): - yield self.t("header", **map) + header_file = cStringIO.StringIO(''.join(self.t("header", **map))) + msg = mimetools.Message(header_file, 0) + req.header(msg.items()) + yield header_file.read() def footer(**map): yield self.t("footer", @@ -828,7 +831,7 @@ class hgweb(object): static = self.repo.ui.config("web", "static", os.path.join(self.templatepath, "static")) - req.write(staticfile(static, fname) + req.write(staticfile(static, fname, req) or self.t("error", error="%r not found" % fname)) def do_capabilities(self, req): diff --git a/mercurial/hgweb/hgwebdir_mod.py b/mercurial/hgweb/hgwebdir_mod.py --- a/mercurial/hgweb/hgwebdir_mod.py +++ b/mercurial/hgweb/hgwebdir_mod.py @@ -8,7 +8,7 @@ import os from mercurial.demandload import demandload -demandload(globals(), "ConfigParser") +demandload(globals(), "ConfigParser mimetools cStringIO") demandload(globals(), "mercurial:ui,hg,util,templater") demandload(globals(), "mercurial.hgweb.hgweb_mod:hgweb") demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile") @@ -48,7 +48,10 @@ class hgwebdir(object): def run(self, req): def header(**map): - yield tmpl("header", **map) + header_file = cStringIO.StringIO(''.join(tmpl("header", **map))) + msg = mimetools.Message(header_file, 0) + req.header(msg.items()) + yield header_file.read() def footer(**map): yield tmpl("footer", motd=self.motd, **map) @@ -132,7 +135,7 @@ class hgwebdir(object): if req.form.has_key('static'): static = os.path.join(templater.templatepath(), "static") fname = req.form['static'][0] - req.write(staticfile(static, fname) + req.write(staticfile(static, fname, req) or tmpl("error", error="%r not found" % fname)) else: sortable = ["name", "description", "contact", "lastchange"] diff --git a/mercurial/hgweb/request.py b/mercurial/hgweb/request.py --- a/mercurial/hgweb/request.py +++ b/mercurial/hgweb/request.py @@ -57,20 +57,21 @@ class _wsgirequest(object): return self.inp.read(count) def write(self, *things): - if self.server_write is None: - if not self.headers: - self.header() - self.server_write = self.start_response('200 Script output follows', - self.headers) - self.start_response = None - self.headers = None for thing in things: if hasattr(thing, "__iter__"): for part in thing: self.write(part) else: + thing = str(thing) + if self.server_write is None: + if not self.headers: + raise RuntimeError("request.write called before headers sent (%s)." % thing) + self.server_write = self.start_response('200 Script output follows', + self.headers) + self.start_response = None + self.headers = None try: - self.server_write(str(thing)) + self.server_write(thing) except socket.error, inst: if inst[0] != errno.ECONNRESET: raise