comparison mercurial/hgweb/server.py @ 5124:06154aff2b1a

merge with -stable
author Benoit Boissinot <benoit.boissinot@ens-lyon.org>
date Wed, 08 Aug 2007 23:00:01 +0200
parents f94dbc6c7eaf cdd33a048289
children ff461baa9c4e
comparison
equal deleted inserted replaced
5123:f94dbc6c7eaf 5124:06154aff2b1a
35 def writelines(self, seq): 35 def writelines(self, seq):
36 for msg in seq: 36 for msg in seq:
37 self.handler.log_error("HG error: %s", msg) 37 self.handler.log_error("HG error: %s", msg)
38 38
39 class _hgwebhandler(object, BaseHTTPServer.BaseHTTPRequestHandler): 39 class _hgwebhandler(object, BaseHTTPServer.BaseHTTPRequestHandler):
40
41 url_scheme = 'http'
42
40 def __init__(self, *args, **kargs): 43 def __init__(self, *args, **kargs):
41 self.protocol_version = 'HTTP/1.1' 44 self.protocol_version = 'HTTP/1.1'
42 BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kargs) 45 BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kargs)
43 46
44 def log_error(self, format, *args): 47 def log_error(self, format, *args):
51 accesslog = self.server.accesslog 54 accesslog = self.server.accesslog
52 accesslog.write("%s - - [%s] %s\n" % (self.client_address[0], 55 accesslog.write("%s - - [%s] %s\n" % (self.client_address[0],
53 self.log_date_time_string(), 56 self.log_date_time_string(),
54 format % args)) 57 format % args))
55 58
59 def do_write(self):
60 try:
61 self.do_hgweb()
62 except socket.error, inst:
63 if inst[0] != errno.EPIPE:
64 raise
65
56 def do_POST(self): 66 def do_POST(self):
57 try: 67 try:
58 try: 68 self.do_write()
59 self.do_hgweb()
60 except socket.error, inst:
61 if inst[0] != errno.EPIPE:
62 raise
63 except StandardError, inst: 69 except StandardError, inst:
64 self._start_response("500 Internal Server Error", []) 70 self._start_response("500 Internal Server Error", [])
65 self._write("Internal Server Error") 71 self._write("Internal Server Error")
66 tb = "".join(traceback.format_exception(*sys.exc_info())) 72 tb = "".join(traceback.format_exception(*sys.exc_info()))
67 self.log_error("Exception happened during processing request '%s':\n%s", 73 self.log_error("Exception happened during processing request '%s':\n%s",
99 hval = hval.replace('\n', '').strip() 105 hval = hval.replace('\n', '').strip()
100 if hval: 106 if hval:
101 env[hkey] = hval 107 env[hkey] = hval
102 env['SERVER_PROTOCOL'] = self.request_version 108 env['SERVER_PROTOCOL'] = self.request_version
103 env['wsgi.version'] = (1, 0) 109 env['wsgi.version'] = (1, 0)
104 env['wsgi.url_scheme'] = 'http' 110 env['wsgi.url_scheme'] = self.url_scheme
105 env['wsgi.input'] = self.rfile 111 env['wsgi.input'] = self.rfile
106 env['wsgi.errors'] = _error_logger(self) 112 env['wsgi.errors'] = _error_logger(self)
107 env['wsgi.multithread'] = isinstance(self.server, 113 env['wsgi.multithread'] = isinstance(self.server,
108 SocketServer.ThreadingMixIn) 114 SocketServer.ThreadingMixIn)
109 env['wsgi.multiprocess'] = isinstance(self.server, 115 env['wsgi.multiprocess'] = isinstance(self.server,
162 raise AssertionError("Content-length header sent, but more bytes than specified are being written.") 168 raise AssertionError("Content-length header sent, but more bytes than specified are being written.")
163 self.length = self.length - len(data) 169 self.length = self.length - len(data)
164 self.wfile.write(data) 170 self.wfile.write(data)
165 self.wfile.flush() 171 self.wfile.flush()
166 172
173 class _shgwebhandler(_hgwebhandler):
174
175 url_scheme = 'https'
176
177 def setup(self):
178 self.connection = self.request
179 self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
180 self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
181
182 def do_write(self):
183 from OpenSSL.SSL import SysCallError
184 try:
185 super(_shgwebhandler, self).do_write()
186 except SysCallError, inst:
187 if inst.args[0] != errno.EPIPE:
188 raise
189
190 def handle_one_request(self):
191 from OpenSSL.SSL import SysCallError, ZeroReturnError
192 try:
193 super(_shgwebhandler, self).handle_one_request()
194 except (SysCallError, ZeroReturnError):
195 self.close_connection = True
196 pass
197
167 def create_server(ui, repo): 198 def create_server(ui, repo):
168 use_threads = True 199 use_threads = True
169 200
170 def openlog(opt, default): 201 def openlog(opt, default):
171 if opt and opt != '-': 202 if opt and opt != '-':
190 getconfig, getconfigbool = create_getconfig("web", ui, repo.ui) 221 getconfig, getconfigbool = create_getconfig("web", ui, repo.ui)
191 address = getconfig("address", "") 222 address = getconfig("address", "")
192 port = int(getconfig("port", 8000)) 223 port = int(getconfig("port", 8000))
193 use_ipv6 = getconfigbool("ipv6") 224 use_ipv6 = getconfigbool("ipv6")
194 webdir_conf = getconfig("webdir_conf") 225 webdir_conf = getconfig("webdir_conf")
226 ssl_cert = getconfig("certificate")
195 accesslog = openlog(getconfig("accesslog", "-"), sys.stdout) 227 accesslog = openlog(getconfig("accesslog", "-"), sys.stdout)
196 errorlog = openlog(getconfig("errorlog", "-"), sys.stderr) 228 errorlog = openlog(getconfig("errorlog", "-"), sys.stderr)
197 229
198 if use_threads: 230 if use_threads:
199 try: 231 try:
236 if addr in ('', '::'): 268 if addr in ('', '::'):
237 addr = socket.gethostname() 269 addr = socket.gethostname()
238 270
239 self.addr, self.port = addr, port 271 self.addr, self.port = addr, port
240 272
273 if ssl_cert:
274 try:
275 from OpenSSL import SSL
276 ctx = SSL.Context(SSL.SSLv23_METHOD)
277 except ImportError:
278 raise util.Abort("SSL support is unavailable")
279 ctx.use_privatekey_file(ssl_cert)
280 ctx.use_certificate_file(ssl_cert)
281 sock = socket.socket(self.address_family, self.socket_type)
282 self.socket = SSL.Connection(ctx, sock)
283 self.server_bind()
284 self.server_activate()
285
241 class IPv6HTTPServer(MercurialHTTPServer): 286 class IPv6HTTPServer(MercurialHTTPServer):
242 address_family = getattr(socket, 'AF_INET6', None) 287 address_family = getattr(socket, 'AF_INET6', None)
243 288
244 def __init__(self, *args, **kwargs): 289 def __init__(self, *args, **kwargs):
245 if self.address_family is None: 290 if self.address_family is None:
246 raise hg.RepoError(_('IPv6 not available on this system')) 291 raise hg.RepoError(_('IPv6 not available on this system'))
247 super(IPv6HTTPServer, self).__init__(*args, **kwargs) 292 super(IPv6HTTPServer, self).__init__(*args, **kwargs)
248 293
294 if ssl_cert:
295 handler = _shgwebhandler
296 else:
297 handler = _hgwebhandler
298
249 try: 299 try:
250 if use_ipv6: 300 if use_ipv6:
251 return IPv6HTTPServer((address, port), _hgwebhandler) 301 return IPv6HTTPServer((address, port), handler)
252 else: 302 else:
253 return MercurialHTTPServer((address, port), _hgwebhandler) 303 return MercurialHTTPServer((address, port), handler)
254 except socket.error, inst: 304 except socket.error, inst:
255 raise util.Abort(_('cannot start server: %s') % inst.args[1]) 305 raise util.Abort(_('cannot start server: %s') % inst.args[1])