Ticket #461: routingWSGI.diff
-
_cpserver.py
old new 7 7 import warnings 8 8 9 9 import cherrypy 10 from cherrypy import _cphttptools, filters, _cpwsgi 10 from cherrypy import _cphttptools, filters 11 11 from cherrypy.lib import autoreload, profiler, cptools 12 12 13 13 # Use a flag to indicate the state of the application server. … … 35 35 self.on_start_thread_list = [] 36 36 self.on_stop_server_list = [] 37 37 self.on_stop_thread_list = [] 38 38 39 39 # Backward compatibility: 40 40 self.onStopServerList = [] 41 41 self.onStartThreadList = [] 42 42 self.onStartServerList = [] 43 43 self.onStopThreadList = [] 44 45 self.wsgi_app = _cpwsgi.wsgiApp 46 47 def start(self, init_only = False, server_class = _missing, **kwargs): 44 45 def start(self, init_only = False, server_class = _missing, 46 server = None, **kwargs): 48 47 """Main function. MUST be called from the main thread. 49 48 50 49 Set initOnly to True to keep this function from blocking. … … 62 61 63 62 conf = cherrypy.config.get 64 63 65 if server_class is _missing: 66 server_class = conf("server.class", _missing) 67 if server_class is _missing: 68 import _cpwsgi 69 server_class = _cpwsgi.WSGIServer 70 elif server_class and isinstance(server_class, basestring): 71 # Dynamically load the class from the given string 72 server_class = cptools.attributes(server_class) 64 if server is None: 65 if server_class is _missing: 66 server_class = conf("server.class", _missing) 67 if server_class is _missing: 68 import _cpwsgi 69 server_class = _cpwsgi.WSGIServer 70 elif server_class and isinstance(server_class, basestring): 71 # Dynamically load the class from the given string 72 server_class = cptools.attributes(server_class) 73 self.httpserverclass = server_class 74 if server_class is not None: 75 self.httpserver = server_class() 76 else: 77 self.httpserverclass = server.__class__ 78 self.httpserver = server 73 79 74 80 self.blocking = not init_only 75 self.httpserverclass = server_class76 81 77 82 # Hmmm...we *could* check config in _start instead, but I think 78 83 # most people would like CP to fail before autoreload kicks in. … … 81 86 # Autoreload, but check server_class. If None, we're not starting 82 87 # our own webserver, and therefore could do Very Bad Things when 83 88 # autoreload calls sys.exit. 84 if server_class is not None: 89 if server_class is None and server is None: 90 pass 91 else: 85 92 if conf('autoreload.on', False): 86 93 try: 87 94 freq = conf('autoreload.frequency', 1) … … 133 140 134 141 def start_http_server(self, blocking=True): 135 142 """Start the requested HTTP server.""" 136 if self.httpserver is not None: 137 msg = ("You seem to have an HTTP server still running." 138 "Please call server.stop_http_server() " 139 "before continuing.") 140 warnings.warn(msg) 141 142 if self.httpserverclass is None: 143 if not self.httpserver: 143 144 return 144 145 145 146 if cherrypy.config.get('server.socket_port'): … … 154 155 else: 155 156 on_what = "socket file: %s" % cherrypy.config.get('server.socket_file') 156 157 157 # Instantiate the server.158 if self.httpserverclass == _cpwsgi.WSGIServer:159 self.httpserver = self.httpserverclass(self.wsgi_app)160 161 else:162 self.httpserver = self.httpserverclass()163 164 158 # HTTP servers MUST be started in a new thread, so that the 165 159 # main thread persists to receive KeyboardInterrupt's. This 166 160 # wrapper traps an interrupt in the http server's main thread … … 178 172 cherrypy.log("Serving HTTP on %s" % on_what, 'HTTP') 179 173 180 174 def wait_for_http_ready(self): 181 if self.httpserver classis not None:175 if self.httpserver is not None: 182 176 while not getattr(self.httpserver, "ready", True): 183 177 time.sleep(.1) 184 178 -
_cpwsgi.py
old new 164 164 165 165 _cpwsgiserver has been designed to not reference CherryPy in any way, 166 166 so that it can be used in other frameworks and applications. Therefore, 167 we wrap it here .167 we wrap it here, so we can set our own mount points from cherrypy.tree. 168 168 169 169 """ 170 170 171 171 RequestHandlerClass = CPHTTPRequest 172 172 173 def __init__(self , app=wsgiApp):173 def __init__(self): 174 174 conf = cherrypy.config.get 175 175 176 176 sockFile = cherrypy.config.get('server.socket_file') … … 179 179 else: 180 180 bind_addr = (conf("server.socket_host"), conf("server.socket_port")) 181 181 182 pts = cherrypy.tree.mount_points 183 if pts: 184 apps = [(base, wsgiApp) for base in pts.keys()] 185 else: 186 apps = [("", wsgiApp)] 187 182 188 s = _cpwsgiserver.CherryPyWSGIServer 183 s.__init__(self, bind_addr, app ,189 s.__init__(self, bind_addr, apps, 184 190 conf("server.thread_pool"), 185 191 conf("server.socket_host"), 186 192 request_queue_size = conf('server.socket_queue_size'), -
_cpwsgiserver.py
old new 64 64 else: 65 65 qs = "" 66 66 self.environ["REQUEST_METHOD"] = method 67 self.environ["SCRIPT_NAME"] = "" 68 self.environ["PATH_INFO"] = path 67 68 for mount_point, wsgi_app in self.server.mount_points: 69 # The mount_points list should be sorted by length, descending. 70 if path.startswith(mount_point): 71 self.environ["SCRIPT_NAME"] = mount_point 72 self.environ["PATH_INFO"] = path[len(mount_point):] 73 self.wsgi_app = wsgi_app 74 break 75 else: 76 msg = "Not Found" 77 proto = self.environ.get("SERVER_PROTOCOL", "HTTP/1.0") 78 self.wfile.write("%s 404 %s\r\n" % (proto, msg)) 79 self.wfile.write("Content-Length: %s\r\n\r\n" % len(msg)) 80 self.wfile.write(msg) 81 self.wfile.flush() 82 self.ready = False 83 return 84 69 85 self.environ["QUERY_STRING"] = qs 70 86 self.environ["SERVER_PROTOCOL"] = version 71 87 self.environ["SERVER_NAME"] = self.server.server_name … … 160 176 try: 161 177 request.parse_request() 162 178 if request.ready: 163 response = self.server.wsgi_app(request.environ,164 request.start_response)179 response = request.wsgi_app(request.environ, 180 request.start_response) 165 181 for line in response: 166 182 request.write(line) 167 183 except socket.error, e: … … 191 207 be careful w/ max 192 208 ''' 193 209 self.requests = Queue.Queue(max) 194 self.wsgi_app = wsgi_app 210 211 if callable(wsgi_app): 212 # We've been handed a single wsgi_app, in CP-2.1 style. 213 # Assume it's mounted at "". 214 self.mount_points = [("", wsgi_app)] 215 else: 216 # We've been handed a list of (mount_point, wsgi_app) tuples, 217 # so that the server can call different wsgi_apps, and also 218 # correctly set SCRIPT_NAME. 219 self.mount_points = wsgi_app 220 self.mount_points.sort() 221 self.mount_points.reverse() 222 195 223 self.bind_addr = bind_addr 196 224 self.numthreads = numthreads or 1 197 225 if not server_name: … … 286 314 def stop(self): 287 315 """Gracefully shutdown a server that is serving forever.""" 288 316 self.ready = False 289 self.socket.close() 317 s = getattr(self, "socket", None) 318 if s and hasattr(s, "close"): 319 s.close() 290 320 291 321 # Must shut down threads here so the code that calls 292 322 # this method can know when all threads are stopped. -
test/helper.py
old new 67 67 """Wrapper for WSGI server so we can test thrown errors.""" 68 68 69 69 def __init__(self): 70 _cpwsgi.WSGIServer.__init__(self, error_middleware) 70 _cpwsgi.WSGIServer.__init__(self) 71 self.mount_points = [(base, error_middleware) 72 for base, wsgiapp in self.mount_points] 71 73 72 74 73 75 class CPWebCase(webtest.WebCase): -
test/test_core.py
old new 631 631 self.assertInBody(msg) 632 632 633 633 # Test server.throw_errors (ticket #186). 634 httpcls = cherrypy.server.httpserverclass 635 if httpcls:634 s = cherrypy.server.httpserver 635 if s: 636 636 self.getPage("/error/rethrow") 637 637 self.assertBody("THROWN ERROR: ValueError") 638 638 else: … … 836 836 self.getPage("/maxrequestsize/index") 837 837 self.assertBody("OK") 838 838 839 httpcls = cherrypy.server.httpserverclass 840 if httpcls:839 s = cherrypy.server.httpserver 840 if s: 841 841 cherrypy.config.update({'server.max_request_header_size': 10}) 842 842 self.getPage("/maxrequestsize/index") 843 843 self.assertStatus("413 Request Entity Too Large") … … 865 865 self.getPage('/maxrequestsize/upload', h, "POST", b) 866 866 self.assertBody('Size: 5') 867 867 868 httpcls = cherrypy.server.httpserverclass 869 if httpcls:868 s = cherrypy.server.httpserver 869 if s: 870 870 cherrypy.config.update({ 871 871 '%s/maxrequestsize' % self.prefix(): {'server.max_request_body_size': 3}}) 872 872 self.getPage('/maxrequestsize/upload', h, "POST", b) -
test/test_logdebuginfo_filter.py
old new 34 34 #self.assertInBody('Session data size') 35 35 36 36 def testBug326(self): 37 httpcls = cherrypy.server.httpserverclass 38 if httpcls and httpcls.__name__ == "WSGIServer": 37 from cherrypy import _cpwsgi 38 s = cherrypy.server.httpserver 39 if s and isinstance(s, _cpwsgi.WSGIServer): 39 40 h = [("Content-type", "multipart/form-data; boundary=x"), 40 41 ("Content-Length", "110")] 41 42 b = """--x … … 46 47 --x-- 47 48 """ 48 49 cherrypy.config.update({ 49 ('%s/bug326' % self.prefix ): {50 ('%s/bug326' % self.prefix()): { 50 51 'server.max_request_body_size': 3, 51 52 'server.environment': 'development', 52 53 }

