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") +demandload(globals(), "re zlib ConfigParser cStringIO") demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,templater") demandload(globals(), "mercurial.hgweb.request:hgrequest") demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile") @@ -761,26 +761,32 @@ class hgweb(object): req.form['filenode'][0])) elif cmd == 'heads': - req.httphdr("application/mercurial-0.1") - h = self.repo.heads() - req.write(" ".join(map(hex, h)) + "\n") + resp = " ".join(map(hex, self.repo.heads())) + "\n" + req.httphdr("application/mercurial-0.1", length=len(resp)) + req.write(resp) elif cmd == 'branches': - req.httphdr("application/mercurial-0.1") nodes = [] if req.form.has_key('nodes'): nodes = map(bin, req.form['nodes'][0].split(" ")) + resp = cStringIO.StringIO() for b in self.repo.branches(nodes): - req.write(" ".join(map(hex, b)) + "\n") + resp.write(" ".join(map(hex, b)) + "\n") + resp = resp.getvalue() + req.httphdr("application/mercurial-0.1", length=len(resp)) + req.write(resp) elif cmd == 'between': - req.httphdr("application/mercurial-0.1") nodes = [] if req.form.has_key('pairs'): pairs = [map(bin, p.split("-")) for p in req.form['pairs'][0].split(" ")] + resp = cStringIO.StringIO() for b in self.repo.between(pairs): - req.write(" ".join(map(hex, b)) + "\n") + resp.write(" ".join(map(hex, b)) + "\n") + resp = resp.getvalue() + req.httphdr("application/mercurial-0.1", length=len(resp)) + req.write(resp) elif cmd == 'changegroup': req.httphdr("application/mercurial-0.1") @@ -819,3 +825,4 @@ class hgweb(object): else: req.write(self.t("error")) + req.done() diff --git a/mercurial/hgweb/request.py b/mercurial/hgweb/request.py --- a/mercurial/hgweb/request.py +++ b/mercurial/hgweb/request.py @@ -16,6 +16,7 @@ class hgrequest(object): self.out = out or sys.stdout self.env = env or os.environ self.form = cgi.parse(self.inp, self.env, keep_blank_values=1) + self.will_close = True def write(self, *things): for thing in things: @@ -29,16 +30,30 @@ class hgrequest(object): if inst[0] != errno.ECONNRESET: raise + def done(self): + if self.will_close: + self.inp.close() + self.out.close() + else: + self.out.flush() + def header(self, headers=[('Content-type','text/html')]): for header in headers: self.out.write("%s: %s\r\n" % header) self.out.write("\r\n") - def httphdr(self, type, file="", size=0): + def httphdr(self, type, filename=None, length=0): headers = [('Content-type', type)] - if file: - headers.append(('Content-disposition', 'attachment; filename=%s' % file)) - if size > 0: - headers.append(('Content-length', str(size))) + if filename: + headers.append(('Content-disposition', 'attachment; filename=%s' % + filename)) + # we do not yet support http 1.1 chunked transfer, so we have + # to force connection to close if content-length not known + if length: + headers.append(('Content-length', str(length))) + self.will_close = False + else: + headers.append(('Connection', 'close')) + self.will_close = True self.header(headers) diff --git a/mercurial/hgweb/server.py b/mercurial/hgweb/server.py --- a/mercurial/hgweb/server.py +++ b/mercurial/hgweb/server.py @@ -27,6 +27,7 @@ def _splitURI(uri): class _hgwebhandler(object, BaseHTTPServer.BaseHTTPRequestHandler): def __init__(self, *args, **kargs): + self.protocol_version = 'HTTP/1.1' BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kargs) def log_error(self, format, *args): @@ -85,7 +86,7 @@ class _hgwebhandler(object, BaseHTTPServ req = hgrequest(self.rfile, self.wfile, env) self.send_response(200, "Script output follows") - self.server.make_and_run_handler(req) + self.close_connection = self.server.make_and_run_handler(req) def create_server(ui, repo): use_threads = True @@ -135,6 +136,7 @@ def create_server(ui, repo): else: raise hg.RepoError(_('no repo found')) hgwebobj.run(req) + return req.will_close class IPv6HTTPServer(MercurialHTTPServer): address_family = getattr(socket, 'AF_INET6', None)