Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

Changeset 1217

Show
Ignore:
Timestamp:
08/05/06 17:14:46
Author:
fumanchu
Message:

Fix for #537 (Support for listening on multiple ports). cherrypy.server now has no "httpserver" attribute; instead, it has an "httpservers" attribute, a dict of the form {server object: bind_addr} where bind_addr is usually (host, port). New start_all method. Calling stop stops all httpservers, and restart stops all then restarts all.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/cherrypy/_cpserver.py

    r1204 r1217  
    11"""Manage an HTTP server with CherryPy.""" 
    22 
     3import socket 
    34import threading 
    45import time 
     
    910 
    1011class Server(object): 
    11     """Manager for an HTTP server.""" 
     12    """Manager for a set of HTTP servers.""" 
    1213     
    1314    def __init__(self): 
    14         self.httpserver = None 
     15        self.httpservers = {} 
    1516        self.interrupt = None 
    1617     
     
    1819        """Main function. MUST be called from the main thread.""" 
    1920        self.interrupt = None 
    20          
     21        httpserver, bind_addr = self.httpserver_from_config(server) 
     22        self.httpservers[httpserver] = bind_addr 
     23        self._start_http(httpserver) 
     24     
     25    def httpserver_from_config(self, httpserver=None): 
     26        """Return a (httpserver, bind_addr) pair based on config settings.""" 
    2127        conf = cherrypy.config.get 
    22         if server is None: 
    23             server = conf('server.instance', None) 
    24         if server is None: 
     28        if httpserver is None: 
     29            httpserver = conf('server.instance', None) 
     30        if httpserver is None: 
    2531            import _cpwsgi 
    26             server = _cpwsgi.WSGIServer() 
    27         if isinstance(server, basestring): 
    28             server = attributes(server)() 
    29         self.httpserver = server 
     32            httpserver = _cpwsgi.WSGIServer() 
     33        if isinstance(httpserver, basestring): 
     34            httpserver = attributes(httpserver)() 
    3035         
    3136        if conf('server.socket_port'): 
    3237            host = conf('server.socket_host') 
    3338            port = conf('server.socket_port') 
    34             wait_for_free_port(host, port) 
    3539            if not host: 
    3640                host = 'localhost' 
    37             on_what = "http://%s:%s/" % (host, port) 
     41            return httpserver, (host, port) 
    3842        else: 
    39             on_what = "socket file: %s" % conf('server.socket_file') 
     43            return httpserver, conf('server.socket_file') 
     44     
     45    def start_all(self): 
     46        """Start all registered HTTP servers.""" 
     47        for httpserver in self.httpservers: 
     48            self._start_http(httpserver) 
     49     
     50    def _start_http(self, httpserver): 
     51        """Start the given httpserver in a new thread.""" 
     52        bind_addr = self.httpservers[httpserver] 
     53        if isinstance(bind_addr, tuple): 
     54            wait_for_free_port(*bind_addr) 
     55            on_what = "http://%s:%s/" % bind_addr 
     56        else: 
     57            on_what = "socket file: %s" % bind_addr 
    4058         
    41         # HTTP servers MUST be started in a new thread, so that the 
    42         # main thread persists to receive KeyboardInterrupt's. If an 
    43         # exception is raised in the http server's thread then it's 
    44         # trapped here, and the http server and engine are shut down. 
    45         def _start_http(): 
    46             try: 
    47                 self.httpserver.start() 
    48             except KeyboardInterrupt, exc: 
    49                 cherrypy.log("<Ctrl-C> hit: shutting down HTTP server", "SERVER") 
    50                 self.interrupt = exc 
    51                 self.stop() 
    52                 cherrypy.engine.stop() 
    53             except SystemExit, exc: 
    54                 cherrypy.log("SystemExit raised: shutting down HTTP server", "SERVER") 
    55                 self.interrupt = exc 
    56                 self.stop() 
    57                 cherrypy.engine.stop() 
    58                 raise 
    59         t = threading.Thread(target=_start_http) 
     59        t = threading.Thread(target=self._start_http_thread, args=(httpserver,)) 
    6060        t.setName("CPHTTPServer " + t.getName()) 
    6161        t.start() 
    6262         
    63         self.wait(
     63        self.wait(httpserver
    6464        cherrypy.log("Serving HTTP on %s" % on_what, 'HTTP') 
    6565     
    66     def wait(self): 
    67         """Wait until the HTTP server is ready to receive requests.""" 
    68         while (not getattr(self.httpserver, "ready", False) 
    69                and not self.interrupt): 
    70             time.sleep(.1) 
    71         if self.interrupt: 
    72             raise self.interrupt 
     66    def _start_http_thread(self, httpserver): 
     67        """HTTP servers MUST be started in new threads, so that the 
     68        main thread persists to receive KeyboardInterrupt's. If an 
     69        exception is raised in the httpserver's thread then it's 
     70        trapped here, and the httpserver(s) and engine are shut down. 
     71        """ 
     72        try: 
     73            httpserver.start() 
     74        except KeyboardInterrupt, exc: 
     75            cherrypy.log("<Ctrl-C> hit: shutting down HTTP servers", "SERVER") 
     76            self.interrupt = exc 
     77            self.stop() 
     78            cherrypy.engine.stop() 
     79        except SystemExit, exc: 
     80            cherrypy.log("SystemExit raised: shutting down HTTP servers", "SERVER") 
     81            self.interrupt = exc 
     82            self.stop() 
     83            cherrypy.engine.stop() 
     84            raise 
     85     
     86    def wait(self, httpserver=None): 
     87        """Wait until the HTTP server is ready to receive requests. 
    7388         
    74         # Wait for port to be occupied 
    75         if cherrypy.config.get('server.socket_port'): 
    76             host = cherrypy.config.get('server.socket_host') 
    77             port = cherrypy.config.get('server.socket_port') 
    78             wait_for_occupied_port(host, port) 
     89        If no httpserver is specified, wait for all registered httpservers. 
     90        """ 
     91        if httpserver is None: 
     92            httpservers = self.httpservers.items() 
     93        else: 
     94            httpservers = [(httpserver, self.httpservers[httpserver])] 
     95         
     96        for httpserver, bind_addr in httpservers: 
     97            while not (getattr(httpserver, "ready", False) or self.interrupt): 
     98                time.sleep(.1) 
     99            if self.interrupt: 
     100                raise self.interrupt 
     101             
     102            # Wait for port to be occupied 
     103            if isinstance(bind_addr, tuple): 
     104                wait_for_occupied_port(*bind_addr) 
    79105     
    80106    def stop(self): 
    81         """Stop the HTTP server.""" 
    82         try: 
    83             httpstop = self.httpserver.stop 
    84         except AttributeError: 
    85             pass 
    86         else: 
    87             # httpstop() MUST block until the server is *truly* stopped. 
    88             httpstop() 
    89             conf = cherrypy.config.get 
    90             if conf('server.socket_port'): 
    91                 host = conf('server.socket_host') 
    92                 port = conf('server.socket_port') 
    93                 wait_for_free_port(host, port) 
    94             cherrypy.log("HTTP Server shut down", "HTTP") 
     107        """Stop all HTTP server(s).""" 
     108        for httpserver, bind_addr in self.httpservers.items(): 
     109            try: 
     110                httpstop = httpserver.stop 
     111            except AttributeError: 
     112                pass 
     113            else: 
     114                # httpstop() MUST block until the server is *truly* stopped. 
     115                httpstop() 
     116                if isinstance(bind_addr, tuple): 
     117                    wait_for_free_port(*bind_addr) 
     118                cherrypy.log("HTTP Server shut down", "HTTP") 
    95119     
    96120    def restart(self): 
     
    98122        self.stop() 
    99123        self.interrupt = None 
    100         self.start() 
     124        self.start_all() 
    101125 
    102126 
    103127def check_port(host, port): 
    104128    """Raise an error if the given port is not free on the given host.""" 
    105     sock_file = cherrypy.config.get('server.socket_file') 
    106     if sock_file: 
    107         return 
    108      
    109129    if not host: 
    110130        host = 'localhost' 
    111131    port = int(port) 
    112      
    113     import socket 
    114132     
    115133    # AF_INET or AF_INET6 socket 
     
    127145            s.close() 
    128146            raise IOError("Port %s is in use on %s; perhaps the previous " 
    129                           "server did not shut down properly." % 
     147                          "httpserver did not shut down properly." % 
    130148                          (repr(port), repr(host))) 
    131149        except socket.error: 
  • trunk/cherrypy/lib/wsgiapp.py

    r1137 r1217  
    3232    environ["QUERY_STRING"] = cherrypy.request.query_string 
    3333    environ["SERVER_PROTOCOL"] = cherrypy.request.protocol 
    34     server_name = getattr(cherrypy.server.httpserver, 'server_name', "None") 
    35     environ["SERVER_NAME"] = server_name  
    36     environ["SERVER_PORT"] = cherrypy.config.get('server.socket_port') 
     34    environ["SERVER_NAME"] = cherrypy.request.wsgi_environ['SERVER_NAME'] 
     35    environ["SERVER_PORT"] = cherrypy.request.wsgi_environ['SERVER_PORT'] 
    3736    environ["REMOTE_HOST"] = cherrypy.request.remote_host 
    3837    environ["REMOTE_ADDR"] = cherrypy.request.remote_addr 
  • trunk/cherrypy/test/helper.py

    r1194 r1217  
    131131        apps.sort() 
    132132        apps.reverse() 
    133         cherrypy.server.httpserver.mount_points = apps 
     133        for s in cherrypy.server.httpservers: 
     134            s.mount_points = apps 
    134135         
    135136        suite = CPTestLoader.loadTestsFromName(testmod) 
  • trunk/cherrypy/test/test_states.py

    r1204 r1217  
    154154            cherrypy.engine.start(blocking=False) 
    155155            cherrypy.server.start(self.server_class) 
    156             cherrypy.server.httpserver.interrupt = KeyboardInterrupt 
     156            cherrypy.server.httpservers.values()[0].interrupt = KeyboardInterrupt 
    157157            while cherrypy.engine.state != 0: 
    158158                time.sleep(0.1) 
     
    243243            tr.out.close() 
    244244    finally: 
    245         if cherrypy.server.httpserver.ready: 
    246             cherrypy.server.stop() 
     245        cherrypy.server.stop() 
    247246        cherrypy.engine.stop() 
    248247 

Hosted by WebFaction

Log in as guest/cpguest to create tickets