_cpchecker.py (11356B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\cherrypy\_cpchecker.py 2 import os 3 import warnings 4 import cherrypy 5 from cherrypy._cpcompat import iteritems, copykeys, builtins 6 7 class Checker(object): 8 on = True 9 10 def __init__(self): 11 self._populate_known_types() 12 13 def __call__(self): 14 if self.on: 15 oldformatwarning = warnings.formatwarning 16 warnings.formatwarning = self.formatwarning 17 try: 18 for name in dir(self): 19 if name.startswith('check_'): 20 method = getattr(self, name) 21 if method and hasattr(method, '__call__'): 22 method() 23 24 finally: 25 warnings.formatwarning = oldformatwarning 26 27 def formatwarning(self, message, category, filename, lineno, line = None): 28 return 'CherryPy Checker:\n%s\n\n' % message 29 30 global_config_contained_paths = False 31 32 def check_app_config_entries_dont_start_with_script_name(self): 33 for sn, app in cherrypy.tree.apps.items(): 34 if not isinstance(app, cherrypy.Application): 35 continue 36 if not app.config: 37 continue 38 if sn == '': 39 continue 40 sn_atoms = sn.strip('/').split('/') 41 for key in app.config.keys(): 42 key_atoms = key.strip('/').split('/') 43 if key_atoms[:len(sn_atoms)] == sn_atoms: 44 warnings.warn('The application mounted at %r has config entries that start with its script name: %r' % (sn, key)) 45 46 def check_site_config_entries_in_app_config(self): 47 for sn, app in iteritems(cherrypy.tree.apps): 48 if not isinstance(app, cherrypy.Application): 49 continue 50 msg = [] 51 for section, entries in iteritems(app.config): 52 if section.startswith('/'): 53 for key, value in iteritems(entries): 54 for n in ('engine.', 'server.', 'tree.', 'checker.'): 55 if key.startswith(n): 56 msg.append('[%s] %s = %s' % (section, key, value)) 57 58 if msg: 59 msg.insert(0, 'The application mounted at %r contains the following config entries, which are only allowed in site-wide config. Move them to a [global] section and pass them to cherrypy.config.update() instead of tree.mount().' % sn) 60 warnings.warn(os.linesep.join(msg)) 61 62 def check_skipped_app_config(self): 63 for sn, app in cherrypy.tree.apps.items(): 64 if not isinstance(app, cherrypy.Application): 65 continue 66 if not app.config: 67 msg = 'The Application mounted at %r has an empty config.' % sn 68 if self.global_config_contained_paths: 69 msg += ' It looks like the config you passed to cherrypy.config.update() contains application-specific sections. You must explicitly pass application config via cherrypy.tree.mount(..., config=app_config)' 70 warnings.warn(msg) 71 return 72 73 def check_app_config_brackets(self): 74 for sn, app in cherrypy.tree.apps.items(): 75 if not isinstance(app, cherrypy.Application): 76 continue 77 if not app.config: 78 continue 79 for key in app.config.keys(): 80 if key.startswith('[') or key.endswith(']'): 81 warnings.warn('The application mounted at %r has config section names with extraneous brackets: %r. Config *files* need brackets; config *dicts* (e.g. passed to tree.mount) do not.' % (sn, key)) 82 83 def check_static_paths(self): 84 request = cherrypy.request 85 for sn, app in cherrypy.tree.apps.items(): 86 if not isinstance(app, cherrypy.Application): 87 continue 88 request.app = app 89 for section in app.config: 90 request.get_resource(section + '/dummy.html') 91 conf = request.config.get 92 if conf('tools.staticdir.on', False): 93 msg = '' 94 root = conf('tools.staticdir.root') 95 dir = conf('tools.staticdir.dir') 96 if dir is None: 97 msg = 'tools.staticdir.dir is not set.' 98 else: 99 fulldir = '' 100 if os.path.isabs(dir): 101 fulldir = dir 102 if root: 103 msg = 'dir is an absolute path, even though a root is provided.' 104 testdir = os.path.join(root, dir[1:]) 105 if os.path.exists(testdir): 106 msg += '\nIf you meant to serve the filesystem folder at %r, remove the leading slash from dir.' % testdir 107 elif not root: 108 msg = 'dir is a relative path and no root provided.' 109 else: 110 fulldir = os.path.join(root, dir) 111 if not os.path.isabs(fulldir): 112 msg = '%r is not an absolute path.' % fulldir 113 if fulldir and not os.path.exists(fulldir): 114 if msg: 115 msg += '\n' 116 msg += '%r (root + dir) is not an existing filesystem path.' % fulldir 117 if msg: 118 warnings.warn('%s\nsection: [%s]\nroot: %r\ndir: %r' % (msg, 119 section, 120 root, 121 dir)) 122 123 obsolete = {'server.default_content_type': 'tools.response_headers.headers', 124 'log_access_file': 'log.access_file', 125 'log_config_options': None, 126 'log_file': 'log.error_file', 127 'log_file_not_found': None, 128 'log_request_headers': 'tools.log_headers.on', 129 'log_to_screen': 'log.screen', 130 'show_tracebacks': 'request.show_tracebacks', 131 'throw_errors': 'request.throw_errors', 132 'profiler.on': 'cherrypy.tree.mount(profiler.make_app(cherrypy.Application(Root())))'} 133 deprecated = {} 134 135 def _compat(self, config): 136 for section, conf in config.items(): 137 if isinstance(conf, dict): 138 for k, v in conf.items(): 139 if k in self.obsolete: 140 warnings.warn('%r is obsolete. Use %r instead.\nsection: [%s]' % (k, self.obsolete[k], section)) 141 elif k in self.deprecated: 142 warnings.warn('%r is deprecated. Use %r instead.\nsection: [%s]' % (k, self.deprecated[k], section)) 143 144 elif section in self.obsolete: 145 warnings.warn('%r is obsolete. Use %r instead.' % (section, self.obsolete[section])) 146 elif section in self.deprecated: 147 warnings.warn('%r is deprecated. Use %r instead.' % (section, self.deprecated[section])) 148 149 def check_compatibility(self): 150 self._compat(cherrypy.config) 151 for sn, app in cherrypy.tree.apps.items(): 152 if not isinstance(app, cherrypy.Application): 153 continue 154 self._compat(app.config) 155 156 extra_config_namespaces = [] 157 158 def _known_ns(self, app): 159 ns = ['wsgi'] 160 ns.extend(copykeys(app.toolboxes)) 161 ns.extend(copykeys(app.namespaces)) 162 ns.extend(copykeys(app.request_class.namespaces)) 163 ns.extend(copykeys(cherrypy.config.namespaces)) 164 ns += self.extra_config_namespaces 165 for section, conf in app.config.items(): 166 is_path_section = section.startswith('/') 167 if is_path_section and isinstance(conf, dict): 168 for k, v in conf.items(): 169 atoms = k.split('.') 170 if len(atoms) > 1: 171 if atoms[0] not in ns: 172 if atoms[0] == 'cherrypy' and atoms[1] in ns: 173 msg = 'The config entry %r is invalid; try %r instead.\nsection: [%s]' % (k, '.'.join(atoms[1:]), section) 174 else: 175 msg = 'The config entry %r is invalid, because the %r config namespace is unknown.\nsection: [%s]' % (k, atoms[0], section) 176 warnings.warn(msg) 177 elif atoms[0] == 'tools': 178 if atoms[1] not in dir(cherrypy.tools): 179 msg = 'The config entry %r may be invalid, because the %r tool was not found.\nsection: [%s]' % (k, atoms[1], section) 180 warnings.warn(msg) 181 182 def check_config_namespaces(self): 183 for sn, app in cherrypy.tree.apps.items(): 184 if not isinstance(app, cherrypy.Application): 185 continue 186 self._known_ns(app) 187 188 known_config_types = {} 189 190 def _populate_known_types(self): 191 b = [ x for x in vars(builtins).values() if type(x) is type(str) ] 192 193 def traverse(obj, namespace): 194 for name in dir(obj): 195 if name == 'body_params': 196 continue 197 vtype = type(getattr(obj, name, None)) 198 if vtype in b: 199 self.known_config_types[namespace + '.' + name] = vtype 200 201 traverse(cherrypy.request, 'request') 202 traverse(cherrypy.response, 'response') 203 traverse(cherrypy.server, 'server') 204 traverse(cherrypy.engine, 'engine') 205 traverse(cherrypy.log, 'log') 206 207 def _known_types(self, config): 208 msg = 'The config entry %r in section %r is of type %r, which does not match the expected type %r.' 209 for section, conf in config.items(): 210 if isinstance(conf, dict): 211 for k, v in conf.items(): 212 if v is not None: 213 expected_type = self.known_config_types.get(k, None) 214 vtype = type(v) 215 if expected_type and vtype != expected_type: 216 warnings.warn(msg % (k, 217 section, 218 vtype.__name__, 219 expected_type.__name__)) 220 221 else: 222 k, v = section, conf 223 if v is not None: 224 expected_type = self.known_config_types.get(k, None) 225 vtype = type(v) 226 if expected_type and vtype != expected_type: 227 warnings.warn(msg % (k, 228 section, 229 vtype.__name__, 230 expected_type.__name__)) 231 232 def check_config_types(self): 233 self._known_types(cherrypy.config) 234 for sn, app in cherrypy.tree.apps.items(): 235 if not isinstance(app, cherrypy.Application): 236 continue 237 self._known_types(app.config) 238 239 def check_localhost(self): 240 for k, v in cherrypy.config.items(): 241 if k == 'server.socket_host' and v == 'localhost': 242 warnings.warn("The use of 'localhost' as a socket host can cause problems on newer systems, since 'localhost' can map to either an IPv4 or an IPv6 address. You should use '127.0.0.1' or '[::1]' instead.")