mercurial/hgweb/server.py
changeset 5124 06154aff2b1a
parent 5123 f94dbc6c7eaf
parent 4939 cdd33a048289
child 5129 ff461baa9c4e
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])