servers.py (6889B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\cherrypy\process\servers.py 2 import sys 3 import time 4 5 class ServerAdapter(object): 6 7 def __init__(self, bus, httpserver = None, bind_addr = None): 8 self.bus = bus 9 self.httpserver = httpserver 10 self.bind_addr = bind_addr 11 self.interrupt = None 12 self.running = False 13 14 def subscribe(self): 15 self.bus.subscribe('start', self.start) 16 self.bus.subscribe('stop', self.stop) 17 18 def unsubscribe(self): 19 self.bus.unsubscribe('start', self.start) 20 self.bus.unsubscribe('stop', self.stop) 21 22 def start(self): 23 if self.bind_addr is None: 24 on_what = 'unknown interface (dynamic?)' 25 elif isinstance(self.bind_addr, tuple): 26 host, port = self.bind_addr 27 on_what = '%s:%s' % (host, port) 28 else: 29 on_what = 'socket file: %s' % self.bind_addr 30 if self.running: 31 self.bus.log('Already serving on %s' % on_what) 32 return 33 self.interrupt = None 34 if not self.httpserver: 35 raise ValueError('No HTTP server has been created.') 36 if isinstance(self.bind_addr, tuple): 37 wait_for_free_port(*self.bind_addr) 38 import threading 39 t = threading.Thread(target=self._start_http_thread) 40 t.setName('HTTPServer ' + t.getName()) 41 t.start() 42 self.wait() 43 self.running = True 44 self.bus.log('Serving on %s' % on_what) 45 46 start.priority = 75 47 48 def _start_http_thread(self): 49 try: 50 self.httpserver.start() 51 except KeyboardInterrupt: 52 self.bus.log('<Ctrl-C> hit: shutting down HTTP server') 53 self.interrupt = sys.exc_info()[1] 54 self.bus.exit() 55 except SystemExit: 56 self.bus.log('SystemExit raised: shutting down HTTP server') 57 self.interrupt = sys.exc_info()[1] 58 self.bus.exit() 59 raise 60 except: 61 self.interrupt = sys.exc_info()[1] 62 self.bus.log('Error in HTTP server: shutting down', traceback=True, level=40) 63 self.bus.exit() 64 raise 65 66 def wait(self): 67 while not getattr(self.httpserver, 'ready', False): 68 if self.interrupt: 69 raise self.interrupt 70 time.sleep(0.1) 71 72 if isinstance(self.bind_addr, tuple): 73 host, port = self.bind_addr 74 wait_for_occupied_port(host, port) 75 76 def stop(self): 77 if self.running: 78 self.httpserver.stop() 79 if isinstance(self.bind_addr, tuple): 80 wait_for_free_port(*self.bind_addr) 81 self.running = False 82 self.bus.log('HTTP Server %s shut down' % self.httpserver) 83 else: 84 self.bus.log('HTTP Server %s already shut down' % self.httpserver) 85 86 stop.priority = 25 87 88 def restart(self): 89 self.stop() 90 self.start() 91 92 93 class FlupCGIServer(object): 94 95 def __init__(self, *args, **kwargs): 96 self.args = args 97 self.kwargs = kwargs 98 self.ready = False 99 100 def start(self): 101 from flup.server.cgi import WSGIServer 102 self.cgiserver = WSGIServer(*self.args, **self.kwargs) 103 self.ready = True 104 self.cgiserver.run() 105 106 def stop(self): 107 self.ready = False 108 109 110 class FlupFCGIServer(object): 111 112 def __init__(self, *args, **kwargs): 113 if kwargs.get('bindAddress', None) is None: 114 import socket 115 if not hasattr(socket, 'fromfd'): 116 raise ValueError('Dynamic FCGI server not available on this platform. You must use a static or external one by providing a legal bindAddress.') 117 self.args = args 118 self.kwargs = kwargs 119 self.ready = False 120 121 def start(self): 122 from flup.server.fcgi import WSGIServer 123 self.fcgiserver = WSGIServer(*self.args, **self.kwargs) 124 self.fcgiserver._installSignalHandlers = lambda : None 125 self.fcgiserver._oldSIGs = [] 126 self.ready = True 127 self.fcgiserver.run() 128 129 def stop(self): 130 self.fcgiserver._keepGoing = False 131 self.fcgiserver._threadPool.maxSpare = self.fcgiserver._threadPool._idleCount 132 self.ready = False 133 134 135 class FlupSCGIServer(object): 136 137 def __init__(self, *args, **kwargs): 138 self.args = args 139 self.kwargs = kwargs 140 self.ready = False 141 142 def start(self): 143 from flup.server.scgi import WSGIServer 144 self.scgiserver = WSGIServer(*self.args, **self.kwargs) 145 self.scgiserver._installSignalHandlers = lambda : None 146 self.scgiserver._oldSIGs = [] 147 self.ready = True 148 self.scgiserver.run() 149 150 def stop(self): 151 self.ready = False 152 self.scgiserver._keepGoing = False 153 self.scgiserver._threadPool.maxSpare = 0 154 155 156 def client_host(server_host): 157 if server_host == '0.0.0.0': 158 return '127.0.0.1' 159 if server_host in ('::', '::0', '::0.0.0.0'): 160 return '::1' 161 return server_host 162 163 164 def check_port(host, port, timeout = 1.0): 165 if not host: 166 raise ValueError("Host values of '' or None are not allowed.") 167 host = client_host(host) 168 port = int(port) 169 import socket 170 try: 171 info = socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM) 172 except socket.gaierror: 173 if ':' in host: 174 info = [(socket.AF_INET6, 175 socket.SOCK_STREAM, 176 0, 177 '', 178 (host, 179 port, 180 0, 181 0))] 182 else: 183 info = [(socket.AF_INET, 184 socket.SOCK_STREAM, 185 0, 186 '', 187 (host, port))] 188 189 for res in info: 190 af, socktype, proto, canonname, sa = res 191 s = None 192 try: 193 s = socket.socket(af, socktype, proto) 194 s.settimeout(timeout) 195 s.connect((host, port)) 196 s.close() 197 raise IOError('Port %s is in use on %s; perhaps the previous httpserver did not shut down properly.' % (repr(port), repr(host))) 198 except socket.error: 199 if s: 200 s.close() 201 202 203 def wait_for_free_port(host, port): 204 if not host: 205 raise ValueError("Host values of '' or None are not allowed.") 206 for trial in range(50): 207 try: 208 check_port(host, port, timeout=0.1) 209 except IOError: 210 time.sleep(0.1) 211 else: 212 return 213 214 raise IOError('Port %r not free on %r' % (port, host)) 215 216 217 def wait_for_occupied_port(host, port): 218 if not host: 219 raise ValueError("Host values of '' or None are not allowed.") 220 for trial in range(50): 221 try: 222 check_port(host, port) 223 except IOError: 224 return 225 226 time.sleep(0.1) 227 228 raise IOError('Port %r not bound on %r' % (port, host))