Changeset 691
- Timestamp:
- 09/28/05 16:53:32
- Files:
-
- trunk/cherrypy/_cphttpserver.py (modified) (13 diffs)
- trunk/cherrypy/_cpwsgiserver.py (modified) (6 diffs)
- trunk/cherrypy/server.py (modified) (5 diffs)
- trunk/cherrypy/test/helper.py (modified) (4 diffs)
- trunk/cherrypy/test/test.py (modified) (1 diff)
- trunk/cherrypy/test/test_states.py (modified) (4 diffs)
- trunk/cherrypy/test/webtest.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/cherrypy/_cphttpserver.py
r685 r691 138 138 class CherryHTTPServer(BaseHTTPServer.HTTPServer): 139 139 140 ready = False 141 140 142 def __init__(self): 141 143 # Set protocol_version … … 173 175 174 176 def server_bind(self): 175 # Removed getfqdn call because it was timing out on localhost when calling gethostbyaddr 177 # Removed getfqdn call because it was timing out 178 # on localhost when calling gethostbyaddr 176 179 self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 177 180 self.socket.bind(self.server_address) 178 181 179 182 def get_request(self): 180 # With Python 2.3 it seems that an accept socket in timeout (nonblocking) mode 181 # results in request sockets that are also set in nonblocking mode. Since that doesn't play 182 # well with makefile() (where wfile and rfile are set in SocketServer.py) we explicitly set 183 # the request socket to blocking 183 # With Python 2.3 it seems that an accept socket in timeout 184 # (nonblocking) mode results in request sockets that are also set 185 # in nonblocking mode. Since that doesn't play well with makefile() 186 # (where wfile and rfile are set in SocketServer.py) we explicitly 187 # set the request socket to blocking 184 188 185 189 request, client_address = self.socket.accept() … … 195 199 # interrupts on Win32, which don't interrupt accept() by default 196 200 return 1 197 ## except (KeyboardInterrupt, SystemExit):198 ## cherrypy.log("<Ctrl-C> hit: shutting down http server", "HTTP")199 ## self.shutdown()200 201 201 202 def serve_forever(self): 202 203 """Override serve_forever to handle shutdown.""" 203 204 self.__running = 1 205 self.ready = True 204 206 while self.__running: 205 207 self.handle_request() … … 208 210 def shutdown(self): 209 211 self.__running = 0 212 # Close the socket 213 self.server_close() 210 214 stop = shutdown 211 215 … … 216 220 217 221 def __init__(self, RequestHandlerClass, requestQueue): 222 self.ready = False 218 223 threading.Thread.__init__(self) 219 224 self._RequestHandlerClass = RequestHandlerClass … … 221 226 222 227 def run(self): 228 self.ready = True 223 229 while 1: 224 230 request, client_address = self._requestQueue.get() … … 264 270 265 271 allow_reuse_address = 1 272 ready = False 266 273 267 274 def __init__(self): … … 276 283 self.request_queue_size = cherrypy.config.get('server.socketQueueSize') 277 284 278 # I know it says "do not override", but I have to in order to implement SSL support ! 285 # I know it says "do not override", 286 # but I have to in order to implement SSL support ! 279 287 SocketServer.BaseServer.__init__(self, server_address, CherryHTTPRequestHandler) 280 288 self.socket = socket.socket(self.address_family, self.socket_type) … … 303 311 """Gracefully shutdown a server that is serve_forever()ing.""" 304 312 self.__running = 0 313 # Close the socket so restarts work. 314 self.server_close() 305 315 306 316 # Must shut down threads here so the code that calls … … 310 320 current = threading.currentThread() 311 321 for worker in self._workerThreads: 312 if worker is not current :322 if worker is not current and worker.isAlive: 313 323 worker.join() 314 324 self._workerThreads = [] … … 322 332 for worker in self._workerThreads: 323 333 worker.start() 334 324 335 self.__running = 1 336 337 for worker in self._workerThreads: 338 while not worker.ready: 339 time.sleep(.1) 340 self.ready = True 341 325 342 while self.__running: 326 343 if not self.handle_request(): … … 335 352 try: 336 353 request, client_address = self.get_request() 337 ## except (KeyboardInterrupt, SystemExit):338 ## cherrypy.log("<Ctrl-C> hit: shutting down", "HTTP")339 ## return 0340 354 except socket.error, e: 341 355 return 1 … … 344 358 345 359 def get_request(self): 346 # With Python 2.3 it seems that an accept socket in timeout (nonblocking) mode 347 # results in request sockets that are also set in nonblocking mode. Since that doesn't play 348 # well with makefile() (where wfile and rfile are set in SocketServer.py) we explicitly set 349 # the request socket to blocking 350 360 # With Python 2.3 it seems that an accept socket in timeout 361 # (nonblocking) mode results in request sockets that are also set 362 # in nonblocking mode. Since that doesn't play well with makefile() 363 # (where wfile and rfile are set in SocketServer.py) we explicitly 364 # set the request socket to blocking 365 351 366 request, client_address = self.socket.accept() 352 367 if hasattr(request,'setblocking'): trunk/cherrypy/_cpwsgiserver.py
r654 r691 225 225 226 226 def __init__(self, server): 227 self.ready = False 227 228 self.server = server 228 229 threading.Thread.__init__(self) 229 230 230 231 def run(self): 232 self.ready = True 231 233 while self.server._running: 232 234 request = self.server.requests.get() … … 264 266 265 267 class CherryPyWSGIServer(object): 268 266 269 version = "CherryPy/2.1.0-rc1" 270 ready = False 271 267 272 def __init__(self, bind_addr, wsgi_app, numthreads=10, server_name=None, 268 273 stderr=sys.stderr, bufsize=-1, max=-1, … … 295 300 self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 296 301 self.socket.bind(self.bind_addr) 302 # Timeout so KeyboardInterrupt can be caught on Win32 297 303 self.socket.settimeout(1) 298 304 self.socket.listen(5) … … 305 311 for worker in self._workerThreads: 306 312 worker.start() 313 for worker in self._workerThreads: 314 while not worker.ready: 315 time.sleep(.1) 316 self.ready = True 307 317 308 318 while self._running: … … 312 322 """Gracefully shutdown a server that is serving forever.""" 313 323 self._running = False 324 self.socket.close() 314 325 315 326 # Must shut down threads here so the code that calls … … 318 329 self.requests.put(_SHUTDOWNREQUEST) 319 330 331 # Don't join currentThread (when stop is called inside a request). 320 332 current = threading.currentThread() 321 333 for worker in self._workerThreads: 322 334 if worker is not current: 323 335 worker.join() 336 324 337 self._workerThreads = [] 325 338 trunk/cherrypy/server.py
r688 r691 64 64 65 65 def _start(initOnly=False, serverClass=None): 66 """ 67 Main function. All it does is this: 68 - output config options 69 - create response and request objects 70 - starts a server 71 - initilizes built in filters 72 """ 73 74 if cherrypy.codecoverage: 75 from cherrypy.lib import covercp 76 covercp.start() 77 78 # Use a flag to indicate the state of the cherrypy application server. 79 # 0 = Not started 80 # None = In process of starting 81 # 1 = Started, ready to receive requests 82 cherrypy._appserver_state = None 83 84 # Output config options to log 85 if cherrypy.config.get("server.logConfigOptions", True): 86 cherrypy.config.outputConfigMap() 87 88 # Check the config options 89 # TODO 90 # config.checkConfigOptions() 91 92 # If sessions are stored in files and we 93 # use threading, we need a lock on the file 94 if (cherrypy.config.get('server.threadPool') > 1 95 and cherrypy.config.get('session.storageType') == 'file'): 96 cherrypy._sessionFileLock = threading.RLock() 97 98 # set cgi.maxlen which will limit the size of POST request bodies 99 import cgi 100 cgi.maxlen = cherrypy.config.get('server.maxRequestSize') 101 102 # Call the functions from cherrypy.server.onStartServerList 103 for func in cherrypy.server.onStartServerList: 104 func() 105 106 # Set up the profiler if requested. 107 if cherrypy.config.get("profiling.on", False): 108 ppath = cherrypy.config.get("profiling.path", "") 109 cherrypy.profiler = profiler.Profiler(ppath) 110 else: 111 cherrypy.profiler = None 112 113 # Initilize the built in filters 114 cherrypy._cputil._cpInitDefaultFilters() 115 cherrypy._cputil._cpInitUserDefinedFilters() 116 117 if initOnly: 118 cherrypy._appserver_state = 1 119 else: 120 run_server(serverClass) 121 122 def check_port(host, port): 123 """Raise an error if the given port is not free on the given host.""" 124 125 import socket 126 try: 127 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 128 s.connect((host, int(port))) 129 s.close() 130 raise IOError("Port %s is in use on %s; perhaps the previous " 131 "server did not shut down properly." % (port, host)) 132 except socket.error: 133 pass 66 """Main function.""" 67 try: 68 if cherrypy.codecoverage: 69 from cherrypy.lib import covercp 70 covercp.start() 71 72 # Use a flag to indicate the state of the cherrypy application server. 73 # 0 = Not started 74 # None = In process of starting 75 # 1 = Started, ready to receive requests 76 cherrypy._appserver_state = None 77 78 # Output config options to log 79 if cherrypy.config.get("server.logConfigOptions", True): 80 cherrypy.config.outputConfigMap() 81 82 # Check the config options 83 # TODO 84 # config.checkConfigOptions() 85 86 # If sessions are stored in files and we 87 # use threading, we need a lock on the file 88 if (cherrypy.config.get('server.threadPool') > 1 89 and cherrypy.config.get('session.storageType') == 'file'): 90 cherrypy._sessionFileLock = threading.RLock() 91 92 # set cgi.maxlen which will limit the size of POST request bodies 93 import cgi 94 cgi.maxlen = cherrypy.config.get('server.maxRequestSize') 95 96 # Call the functions from cherrypy.server.onStartServerList 97 for func in cherrypy.server.onStartServerList: 98 func() 99 100 # Set up the profiler if requested. 101 if cherrypy.config.get("profiling.on", False): 102 ppath = cherrypy.config.get("profiling.path", "") 103 cherrypy.profiler = profiler.Profiler(ppath) 104 else: 105 cherrypy.profiler = None 106 107 # Initilize the built in filters 108 cherrypy._cputil._cpInitDefaultFilters() 109 cherrypy._cputil._cpInitUserDefinedFilters() 110 111 if initOnly: 112 cherrypy._appserver_state = 1 113 else: 114 run_server(serverClass) 115 except: 116 # _start may be called as the target of a Thread, in which case 117 # any errors would pass silently. Log them at least. 118 cherrypy.log(cherrypy._cputil.formatExc()) 119 raise 120 134 121 135 122 def run_server(serverClass=None): 136 123 """Prepare the requested server and then run it.""" 137 138 124 if cherrypy._httpserver is not None: 139 125 warnings.warn("You seem to have an HTTP server still running." 140 126 "Please call cherrypy.server.stop() before continuing.") 127 128 if cherrypy.config.get('server.socketPort'): 129 host = cherrypy.config.get('server.socketHost') 130 port = cherrypy.config.get('server.socketPort') 131 132 wait_for_free_port(host, port) 133 134 if not host: 135 host = 'localhost' 136 onWhat = "http://%s:%s/" % (host, port) 137 else: 138 onWhat = "socket file: %s" % cherrypy.config.get('server.socketFile') 139 cherrypy.log("Serving HTTP on %s" % onWhat, 'HTTP') 141 140 142 141 # Instantiate the server. … … 148 147 import _cpwsgi 149 148 serverClass = _cpwsgi.WSGIServer 150 151 if cherrypy.config.get('server.socketPort'):152 host = cherrypy.config.get('server.socketHost')153 port = cherrypy.config.get('server.socketPort')154 check_port(host, port)155 if not host:156 host = 'localhost'157 onWhat = "http://%s:%s/" % (host, port)158 else:159 onWhat = "socket file: %s" % cherrypy.config.get('server.socketFile')160 cherrypy.log("Serving HTTP on %s" % onWhat, 'HTTP')161 162 # Start the http server. This must be done after check_port, above.163 149 cherrypy._httpserver = serverClass() 164 try: 165 try: 166 cherrypy._appserver_state = 1 167 # This should block until the http server stops. 168 cherrypy._httpserver.start() 169 except (KeyboardInterrupt, SystemExit): 170 pass 171 finally: 172 cherrypy.log("<Ctrl-C> hit: shutting down", "HTTP") 150 151 # Start the http server. Must be done after wait_for_free_port (above). 152 # Note that _httpserver.start() will block this thread, so there 153 # isn't any notification in this thread that the HTTP server is 154 # truly ready. See wait_until_ready() for all the things that 155 # other threads should wait for before proceeding with requests. 156 try: 157 cherrypy._appserver_state = 1 158 # This should block until the http server stops. 159 cherrypy._httpserver.start() 160 except (KeyboardInterrupt, SystemExit): 161 cherrypy.log("<Ctrl-C> hit: shutting down server", "HTTP") 173 162 stop() 174 163 … … 189 178 if cherrypy._appserver_state == 0: 190 179 raise cherrypy.NotReady("No thread has called cherrypy.server.start().") 191 192 trials = 0 193 while cherrypy._appserver_state == None: 194 # Give the server thread time to complete. 195 trials += 1 196 if trials > 10: 197 raise cherrypy.NotReady("cherrypy.server.start() encountered errors.") 198 time.sleep(1) 180 elif cherrypy._appserver_state == None: 181 raise cherrypy.NotReady("cherrypy.server.start() encountered errors.") 199 182 200 183 threadID = threading._get_ident() … … 225 208 pass 226 209 else: 210 # httpstop() should block until the server is *truly* stopped. 227 211 httpstop() 212 cherrypy.log("HTTP Server shut down", "HTTP") 228 213 229 214 # Call the functions from cherrypy.server.onStopThreadList … … 239 224 cherrypy._httpserver = None 240 225 cherrypy._appserver_state = 0 226 cherrypy.log("CherryPy shut down", "HTTP") 241 227 242 228 def restart(): 243 229 """Stop and start CherryPy.""" 244 230 http = getattr(cherrypy, '_httpserver', None) 231 stop() 245 232 if http: 246 stop()247 # Give HTTP servers time to shut down their thread pools.248 time.sleep(1)249 233 # Start the server in a new thread 250 234 thread_args = {"serverClass": http.__class__} 251 t hreading.Thread(target=_start, kwargs=thread_args).start()252 else:253 stop()235 t = threading.Thread(target=_start, kwargs=thread_args) 236 t.start() 237 else: 254 238 _start(initOnly=True) 239 wait_until_ready() 240 241 def wait_until_ready(): 242 """Block the caller until CherryPy is ready to receive requests.""" 243 244 while cherrypy._appserver_state != 1: 245 time.sleep(.1) 246 247 http = getattr(cherrypy, '_httpserver', None) 248 if http: 249 # Wait for HTTP server to start up 250 while not http.ready: 251 time.sleep(.1) 252 253 # Wait for port to be occupied 254 if cherrypy.config.get('server.socketPort'): 255 host = cherrypy.config.get('server.socketHost') 256 port = cherrypy.config.get('server.socketPort') 257 wait_for_occupied_port(host, port) 258 259 def check_port(host, port): 260 """Raise an error if the given port is not free on the given host.""" 261 262 import socket 263 try: 264 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 265 s.connect((host, int(port))) 266 s.close() 267 raise IOError("Port %s is in use on %s; perhaps the previous " 268 "server did not shut down properly." % (port, host)) 269 except socket.error: 270 pass 271 272 def wait_for_free_port(host, port): 273 for trial in xrange(50): 274 try: 275 check_port(host, port) 276 except IOError: 277 # Give the old server thread time to free the port. 278 time.sleep(.1) 279 else: 280 return 281 282 cherrypy.log("Port %s not free" % port, 'HTTP') 283 raise cherrypy.NotReady("Port not free.") 284 285 def wait_for_occupied_port(host, port): 286 for trial in xrange(50): 287 try: 288 check_port(host, port) 289 except IOError: 290 return 291 else: 292 time.sleep(.1) 293 294 cherrypy.log("Port %s not bound" % port, 'HTTP') 295 raise cherrypy.NotReady("Port not bound.") trunk/cherrypy/test/helper.py
r689 r691 64 64 65 65 def startServer(serverClass=None): 66 """Start the given server (default serverless) in a new thread."""66 """Start server in a new thread (same thread if serverClass is None).""" 67 67 if serverClass is None: 68 68 cherrypy.server.start(initOnly=True) … … 71 71 args=(False, serverClass)) 72 72 t.start() 73 time.sleep(1)73 cherrypy.server.wait_until_ready() 74 74 75 75 … … 77 77 """Stop the current CP server.""" 78 78 cherrypy.server.stop() 79 if cherrypy.config.get('server.threadPool') > 1:80 # With thread-pools, it can take up to 1 sec for the server to stop81 time.sleep(1.1)82 79 83 80 … … 192 189 cherrypy.config.update(conf.copy()) 193 190 191 194 192 def run_test_suite(moduleNames, server, conf): 195 193 """Run the given test modules using the given server and conf. trunk/cherrypy/test/test.py
r686 r691 307 307 print 308 308 print "Running tests:", name 309 reload(test_states) 309 310 test_states.run(cls, conf) 310 311 helper.run_test_suite(self.tests, cls, conf) trunk/cherrypy/test/test_states.py
r686 r691 63 63 self.assertEqual(cherrypy._appserver_state, 1) 64 64 65 if cherrypy._httpserver:65 if self.serverClass: 66 66 host = cherrypy.config.get('server.socketHost') 67 67 port = cherrypy.config.get('server.socketPort') … … 79 79 80 80 def test_1_KeyboardInterrupts(self): 81 helper.startServer(self.serverClass) 82 83 if cherrypy._httpserver: 81 if self.serverClass: 84 82 # Raise a keyboard interrupt in the HTTP server's main thread. 83 85 84 def raiser(x=None): 86 85 raise KeyboardInterrupt 86 87 helper.startServer(self.serverClass) 88 87 89 name = cherrypy._httpserver.__class__.__name__ 88 90 if name == "WSGIServer": … … 90 92 elif name in ("CherryHTTPServer", "PooledThreadServer"): 91 93 cherrypy._httpserver.handle_request = raiser 94 else: 95 raise ValueError("Unknown HTTP server: %s" % name) 96 92 97 # Give the server time to shut down. 93 time.sleep(1) 94 self.assertEqual(cherrypy._appserver_state, 0) 98 while cherrypy._appserver_state != 0: 99 time.sleep(.1) 100 self.assertEqual(cherrypy._httpserver, None) 95 101 96 102 # Once the server has stopped, we should get a NotReady error again. 97 103 self.assertRaises(cherrypy.NotReady, self.getPage, "/") 98 ## 99 ## def test_2_Restart(self): 100 ## # Test server start 101 ## helper.startServer(self.serverClass) 102 ## self.getPage("/") 103 ## self.assertBody("Hello World") 104 ## 105 ## # Test server stop 106 ## cherrypy.server.restart() 107 ## self.assertEqual(cherrypy._appserver_state, 1) 108 ## self.getPage("/") 109 ## self.assertBody("Hello World") 104 105 def test_2_Restart(self): 106 # Test server start 107 import cherrypy 108 109 helper.startServer(self.serverClass) 110 self.getPage("/") 111 self.assertBody("Hello World") 112 113 # Test server restart 114 cherrypy.server.restart() 115 116 self.assertEqual(cherrypy._appserver_state, 1) 117 self.getPage("/") 118 self.assertBody("Hello World") 110 119 111 120 … … 126 135 'server.threadPool': 10, 127 136 'server.logToScreen': False, 137 'server.logConfigOptions': False, 128 138 'server.environment': "production", 129 139 'server.showTracebacks': True, trunk/cherrypy/test/webtest.py
r678 r691 329 329 while trial < 10: 330 330 try: 331 conn = httplib.HTTPConnection( '%s:%s' % (host, port))331 conn = httplib.HTTPConnection(host, port) 332 332 conn.putrequest(method.upper(), url) 333 333

