Mercurial > public > mercurial-scm > hg-stable
diff mercurial/hgweb/server.py @ 2506:d0db3462d568
This patch make several WSGI related alterations.
First, it changes the server to be almost a generic WSGI server.
Second, it changes request.py to have wsgiapplication and
_wsgirequest. wsgiapplication is a class that creates _wsgirequests
when called by a WSGI compliant server. It needs to know whether
or not it should create hgwebdir or hgweb requests.
Lastly, wsgicgi.py is added, and the CGI scripts are altered to
use it to launch wsgiapplications in a WSGI compliant way.
As a side effect, all the keepalive code has been removed from
request.py. This code needs to be moved so that it is exclusively
in server.py
author | Eric Hopper <hopper@omnifarious.org> |
---|---|
date | Tue, 27 Jun 2006 00:09:33 -0700 |
parents | 01b856927970 |
children | 7e01da2bc7f3 |
line wrap: on
line diff
--- a/mercurial/hgweb/server.py Tue Jun 27 00:09:31 2006 -0700 +++ b/mercurial/hgweb/server.py Tue Jun 27 00:09:33 2006 -0700 @@ -10,7 +10,7 @@ import os, sys, errno demandload(globals(), "urllib BaseHTTPServer socket SocketServer") demandload(globals(), "mercurial:ui,hg,util,templater") -demandload(globals(), "hgweb_mod:hgweb hgwebdir_mod:hgwebdir request:hgrequest") +demandload(globals(), "hgweb_mod:hgweb hgwebdir_mod:hgwebdir request:wsgiapplication") from mercurial.i18n import gettext as _ def _splitURI(uri): @@ -25,6 +25,17 @@ path, query = uri, '' return urllib.unquote(path), query +class _error_logger(object): + def __init__(self, handler): + self.handler = handler + def flush(self): + pass + def write(str): + self.writelines(str.split('\n')) + def writelines(seq): + for msg in seq: + self.handler.log_error("HG error: %s", msg) + class _hgwebhandler(object, BaseHTTPServer.BaseHTTPRequestHandler): def __init__(self, *args, **kargs): self.protocol_version = 'HTTP/1.1' @@ -84,10 +95,50 @@ if hval: env[hkey] = hval env['SERVER_PROTOCOL'] = self.request_version + env['wsgi.version'] = (1, 0) + env['wsgi.url_scheme'] = 'http' + env['wsgi.input'] = self.rfile + env['wsgi.errors'] = _error_logger(self) + env['wsgi.multithread'] = isinstance(self.server, + SocketServer.ThreadingMixIn) + env['wsgi.multiprocess'] = isinstance(self.server, + SocketServer.ForkingMixIn) + env['wsgi.run_once'] = 0 - req = hgrequest(self.rfile, self.wfile, env) - self.send_response(200, "Script output follows") - self.close_connection = self.server.make_and_run_handler(req) + self.close_connection = True + self.saved_status = None + self.saved_headers = [] + self.sent_headers = False + req = self.server.reqmaker(env, self._start_response) + for data in req: + if data: + self._write(data) + + def send_headers(self): + if not self.saved_status: + raise AssertionError("Sending headers before start_response() called") + saved_status = self.saved_status.split(None, 1) + saved_status[0] = int(saved_status[0]) + self.send_response(*saved_status) + for h in self.saved_headers: + self.send_header(*h) + self.end_headers() + self.sent_headers = True + + def _start_response(self, http_status, headers, exc_info=None): + code, msg = http_status.split(None, 1) + code = int(code) + self.saved_status = http_status + self.saved_headers = headers + return self._write + + def _write(self, data): + if not self.saved_status: + raise AssertionError("data written before start_response() called") + elif not self.sent_headers: + self.send_headers() + self.wfile.write(data) + self.wfile.flush() def create_server(ui, repo): use_threads = True @@ -127,8 +178,9 @@ self.webdir_conf = webdir_conf self.webdirmaker = hgwebdir self.repoviewmaker = hgweb + self.reqmaker = wsgiapplication(self.make_handler) - def make_and_run_handler(self, req): + def make_handler(self): if self.webdir_conf: hgwebobj = self.webdirmaker(self.webdir_conf) elif self.repo is not None: @@ -136,8 +188,7 @@ repo.origroot)) else: raise hg.RepoError(_('no repo found')) - hgwebobj.run(req) - return req.will_close + return hgwebobj class IPv6HTTPServer(MercurialHTTPServer): address_family = getattr(socket, 'AF_INET6', None)