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]) |