Really fix http headers for web UI and issue 254.
authorEric Hopper <hopper@omnifarious.org>
Tue, 27 Jun 2006 09:33:12 -0700
changeset 2514 419c42223bee
parent 2513 f22e3e8fd457
child 2515 a6700c222314
child 2532 84655f721f39
Really fix http headers for web UI and issue 254. This also arranges for static content to allow a keepalive connection.
mercurial/hgweb/common.py
mercurial/hgweb/hgweb_mod.py
mercurial/hgweb/hgwebdir_mod.py
mercurial/hgweb/request.py
--- a/mercurial/hgweb/common.py	Tue Jun 27 09:30:50 2006 -0700
+++ b/mercurial/hgweb/common.py	Tue Jun 27 09:33:12 2006 -0700
@@ -17,7 +17,7 @@
     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 @@
     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 ""
--- a/mercurial/hgweb/hgweb_mod.py	Tue Jun 27 09:30:50 2006 -0700
+++ b/mercurial/hgweb/hgweb_mod.py	Tue Jun 27 09:33:12 2006 -0700
@@ -10,7 +10,7 @@
 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 @@
 
     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 @@
         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):
--- a/mercurial/hgweb/hgwebdir_mod.py	Tue Jun 27 09:30:50 2006 -0700
+++ b/mercurial/hgweb/hgwebdir_mod.py	Tue Jun 27 09:33:12 2006 -0700
@@ -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 @@
 
     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 @@
             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"]
--- a/mercurial/hgweb/request.py	Tue Jun 27 09:30:50 2006 -0700
+++ b/mercurial/hgweb/request.py	Tue Jun 27 09:33:12 2006 -0700
@@ -57,20 +57,21 @@
         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