_cptree.py (6589B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\cherrypy\_cptree.py 2 import os 3 import cherrypy 4 from cherrypy._cpcompat import ntou 5 from cherrypy import _cpconfig, _cplogging, _cprequest, _cpwsgi, tools 6 from cherrypy.lib import httputil 7 8 class Application(object): 9 root = None 10 config = {} 11 namespaces = _cpconfig.NamespaceSet() 12 toolboxes = {'tools': cherrypy.tools} 13 log = None 14 wsgiapp = None 15 request_class = _cprequest.Request 16 response_class = _cprequest.Response 17 relative_urls = False 18 19 def __init__(self, root, script_name = '', config = None): 20 self.log = _cplogging.LogManager(id(self), cherrypy.log.logger_root) 21 self.root = root 22 self.script_name = script_name 23 self.wsgiapp = _cpwsgi.CPWSGIApp(self) 24 self.namespaces = self.namespaces.copy() 25 self.namespaces['log'] = lambda k, v: setattr(self.log, k, v) 26 self.namespaces['wsgi'] = self.wsgiapp.namespace_handler 27 self.config = self.__class__.config.copy() 28 if config: 29 self.merge(config) 30 31 def __repr__(self): 32 return '%s.%s(%r, %r)' % (self.__module__, 33 self.__class__.__name__, 34 self.root, 35 self.script_name) 36 37 script_name_doc = 'The URI "mount point" for this app. A mount point is that portion of\n the URI which is constant for all URIs that are serviced by this\n application; it does not include scheme, host, or proxy ("virtual host")\n portions of the URI.\n \n For example, if script_name is "/my/cool/app", then the URL\n "http://www.example.com/my/cool/app/page1" might be handled by a\n "page1" method on the root object.\n \n The value of script_name MUST NOT end in a slash. If the script_name\n refers to the root of the URI, it MUST be an empty string (not "/").\n \n If script_name is explicitly set to None, then the script_name will be\n provided for each call from request.wsgi_environ[\'SCRIPT_NAME\'].\n ' 38 39 def _get_script_name(self): 40 if self._script_name is None: 41 return cherrypy.serving.request.wsgi_environ['SCRIPT_NAME'].rstrip('/') 42 return self._script_name 43 44 def _set_script_name(self, value): 45 if value: 46 value = value.rstrip('/') 47 self._script_name = value 48 49 script_name = property(fget=_get_script_name, fset=_set_script_name, doc=script_name_doc) 50 51 def merge(self, config): 52 _cpconfig.merge(self.config, config) 53 self.namespaces(self.config.get('/', {})) 54 55 def find_config(self, path, key, default = None): 56 trail = path or '/' 57 while trail: 58 nodeconf = self.config.get(trail, {}) 59 if key in nodeconf: 60 return nodeconf[key] 61 lastslash = trail.rfind('/') 62 if lastslash == -1: 63 break 64 elif lastslash == 0 and trail != '/': 65 trail = '/' 66 else: 67 trail = trail[:lastslash] 68 69 return default 70 71 def get_serving(self, local, remote, scheme, sproto): 72 req = self.request_class(local, remote, scheme, sproto) 73 req.app = self 74 for name, toolbox in self.toolboxes.items(): 75 req.namespaces[name] = toolbox 76 77 resp = self.response_class() 78 cherrypy.serving.load(req, resp) 79 cherrypy.engine.timeout_monitor.acquire() 80 cherrypy.engine.publish('acquire_thread') 81 return (req, resp) 82 83 def release_serving(self): 84 req = cherrypy.serving.request 85 cherrypy.engine.timeout_monitor.release() 86 try: 87 req.close() 88 except: 89 cherrypy.log(traceback=True, severity=40) 90 91 cherrypy.serving.clear() 92 93 def __call__(self, environ, start_response): 94 return self.wsgiapp(environ, start_response) 95 96 97 class Tree(object): 98 apps = {} 99 100 def __init__(self): 101 self.apps = {} 102 103 def mount(self, root, script_name = '', config = None): 104 if script_name is None: 105 raise TypeError("The 'script_name' argument may not be None. Application objects may, however, possess a script_name of None (in order to inpect the WSGI environ for SCRIPT_NAME upon each request). You cannot mount such Applications on this Tree; you must pass them to a WSGI server interface directly.") 106 script_name = script_name.rstrip('/') 107 if isinstance(root, Application): 108 app = root 109 if script_name != '' and script_name != app.script_name: 110 raise ValueError('Cannot specify a different script name and pass an Application instance to cherrypy.mount') 111 script_name = app.script_name 112 else: 113 app = Application(root, script_name) 114 if script_name == '' and root is not None and not hasattr(root, 'favicon_ico'): 115 favicon = os.path.join(os.getcwd(), os.path.dirname(__file__), 'favicon.ico') 116 root.favicon_ico = tools.staticfile.handler(favicon) 117 if config: 118 app.merge(config) 119 self.apps[script_name] = app 120 return app 121 122 def graft(self, wsgi_callable, script_name = ''): 123 script_name = script_name.rstrip('/') 124 self.apps[script_name] = wsgi_callable 125 126 def script_name(self, path = None): 127 if path is None: 128 try: 129 request = cherrypy.serving.request 130 path = httputil.urljoin(request.script_name, request.path_info) 131 except AttributeError: 132 return 133 134 while True: 135 if path in self.apps: 136 return path 137 if path == '': 138 return 139 path = path[:path.rfind('/')] 140 141 def __call__(self, environ, start_response): 142 env1x = environ 143 if environ.get(ntou('wsgi.version')) == (ntou('u'), 0): 144 env1x = _cpwsgi.downgrade_wsgi_ux_to_1x(environ) 145 path = httputil.urljoin(env1x.get('SCRIPT_NAME', ''), env1x.get('PATH_INFO', '')) 146 sn = self.script_name(path or '/') 147 if sn is None: 148 start_response('404 Not Found', []) 149 return [] 150 app = self.apps[sn] 151 environ = environ.copy() 152 if environ.get(u'wsgi.version') == (u'u', 0): 153 enc = environ[u'wsgi.url_encoding'] 154 environ[u'SCRIPT_NAME'] = sn.decode(enc) 155 environ[u'PATH_INFO'] = path[len(sn.rstrip('/')):].decode(enc) 156 else: 157 environ['SCRIPT_NAME'] = sn 158 environ['PATH_INFO'] = path[len(sn.rstrip('/')):] 159 return app(environ, start_response)