Mercurial > hg
comparison 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 |
comparison
equal
deleted
inserted
replaced
2505:01b856927970 | 2506:d0db3462d568 |
---|---|
8 | 8 |
9 from mercurial.demandload import demandload | 9 from mercurial.demandload import demandload |
10 import os, sys, errno | 10 import os, sys, errno |
11 demandload(globals(), "urllib BaseHTTPServer socket SocketServer") | 11 demandload(globals(), "urllib BaseHTTPServer socket SocketServer") |
12 demandload(globals(), "mercurial:ui,hg,util,templater") | 12 demandload(globals(), "mercurial:ui,hg,util,templater") |
13 demandload(globals(), "hgweb_mod:hgweb hgwebdir_mod:hgwebdir request:hgrequest") | 13 demandload(globals(), "hgweb_mod:hgweb hgwebdir_mod:hgwebdir request:wsgiapplication") |
14 from mercurial.i18n import gettext as _ | 14 from mercurial.i18n import gettext as _ |
15 | 15 |
16 def _splitURI(uri): | 16 def _splitURI(uri): |
17 """ Return path and query splited from uri | 17 """ Return path and query splited from uri |
18 | 18 |
22 if '?' in uri: | 22 if '?' in uri: |
23 path, query = uri.split('?', 1) | 23 path, query = uri.split('?', 1) |
24 else: | 24 else: |
25 path, query = uri, '' | 25 path, query = uri, '' |
26 return urllib.unquote(path), query | 26 return urllib.unquote(path), query |
27 | |
28 class _error_logger(object): | |
29 def __init__(self, handler): | |
30 self.handler = handler | |
31 def flush(self): | |
32 pass | |
33 def write(str): | |
34 self.writelines(str.split('\n')) | |
35 def writelines(seq): | |
36 for msg in seq: | |
37 self.handler.log_error("HG error: %s", msg) | |
27 | 38 |
28 class _hgwebhandler(object, BaseHTTPServer.BaseHTTPRequestHandler): | 39 class _hgwebhandler(object, BaseHTTPServer.BaseHTTPRequestHandler): |
29 def __init__(self, *args, **kargs): | 40 def __init__(self, *args, **kargs): |
30 self.protocol_version = 'HTTP/1.1' | 41 self.protocol_version = 'HTTP/1.1' |
31 BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kargs) | 42 BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kargs) |
82 hval = self.headers.getheader(header) | 93 hval = self.headers.getheader(header) |
83 hval = hval.replace('\n', '').strip() | 94 hval = hval.replace('\n', '').strip() |
84 if hval: | 95 if hval: |
85 env[hkey] = hval | 96 env[hkey] = hval |
86 env['SERVER_PROTOCOL'] = self.request_version | 97 env['SERVER_PROTOCOL'] = self.request_version |
87 | 98 env['wsgi.version'] = (1, 0) |
88 req = hgrequest(self.rfile, self.wfile, env) | 99 env['wsgi.url_scheme'] = 'http' |
89 self.send_response(200, "Script output follows") | 100 env['wsgi.input'] = self.rfile |
90 self.close_connection = self.server.make_and_run_handler(req) | 101 env['wsgi.errors'] = _error_logger(self) |
102 env['wsgi.multithread'] = isinstance(self.server, | |
103 SocketServer.ThreadingMixIn) | |
104 env['wsgi.multiprocess'] = isinstance(self.server, | |
105 SocketServer.ForkingMixIn) | |
106 env['wsgi.run_once'] = 0 | |
107 | |
108 self.close_connection = True | |
109 self.saved_status = None | |
110 self.saved_headers = [] | |
111 self.sent_headers = False | |
112 req = self.server.reqmaker(env, self._start_response) | |
113 for data in req: | |
114 if data: | |
115 self._write(data) | |
116 | |
117 def send_headers(self): | |
118 if not self.saved_status: | |
119 raise AssertionError("Sending headers before start_response() called") | |
120 saved_status = self.saved_status.split(None, 1) | |
121 saved_status[0] = int(saved_status[0]) | |
122 self.send_response(*saved_status) | |
123 for h in self.saved_headers: | |
124 self.send_header(*h) | |
125 self.end_headers() | |
126 self.sent_headers = True | |
127 | |
128 def _start_response(self, http_status, headers, exc_info=None): | |
129 code, msg = http_status.split(None, 1) | |
130 code = int(code) | |
131 self.saved_status = http_status | |
132 self.saved_headers = headers | |
133 return self._write | |
134 | |
135 def _write(self, data): | |
136 if not self.saved_status: | |
137 raise AssertionError("data written before start_response() called") | |
138 elif not self.sent_headers: | |
139 self.send_headers() | |
140 self.wfile.write(data) | |
141 self.wfile.flush() | |
91 | 142 |
92 def create_server(ui, repo): | 143 def create_server(ui, repo): |
93 use_threads = True | 144 use_threads = True |
94 | 145 |
95 def openlog(opt, default): | 146 def openlog(opt, default): |
125 self.errorlog = errorlog | 176 self.errorlog = errorlog |
126 self.repo = repo | 177 self.repo = repo |
127 self.webdir_conf = webdir_conf | 178 self.webdir_conf = webdir_conf |
128 self.webdirmaker = hgwebdir | 179 self.webdirmaker = hgwebdir |
129 self.repoviewmaker = hgweb | 180 self.repoviewmaker = hgweb |
130 | 181 self.reqmaker = wsgiapplication(self.make_handler) |
131 def make_and_run_handler(self, req): | 182 |
183 def make_handler(self): | |
132 if self.webdir_conf: | 184 if self.webdir_conf: |
133 hgwebobj = self.webdirmaker(self.webdir_conf) | 185 hgwebobj = self.webdirmaker(self.webdir_conf) |
134 elif self.repo is not None: | 186 elif self.repo is not None: |
135 hgwebobj = self.repoviewmaker(repo.__class__(repo.ui, | 187 hgwebobj = self.repoviewmaker(repo.__class__(repo.ui, |
136 repo.origroot)) | 188 repo.origroot)) |
137 else: | 189 else: |
138 raise hg.RepoError(_('no repo found')) | 190 raise hg.RepoError(_('no repo found')) |
139 hgwebobj.run(req) | 191 return hgwebobj |
140 return req.will_close | |
141 | 192 |
142 class IPv6HTTPServer(MercurialHTTPServer): | 193 class IPv6HTTPServer(MercurialHTTPServer): |
143 address_family = getattr(socket, 'AF_INET6', None) | 194 address_family = getattr(socket, 'AF_INET6', None) |
144 | 195 |
145 def __init__(self, *args, **kwargs): | 196 def __init__(self, *args, **kwargs): |