Package cherrypy :: Module _cpchecker
[hide private]
[frames] | no frames]

Source Code for Module cherrypy._cpchecker

  1  import os 
  2  import warnings 
  3   
  4  import cherrypy 
  5   
  6   
7 -class Checker(object):
8 """A checker for CherryPy sites and their mounted applications. 9 10 on: set this to False to turn off the checker completely. 11 12 When this object is called at engine startup, it executes each 13 of its own methods whose names start with "check_". If you wish 14 to disable selected checks, simply add a line in your global 15 config which sets the appropriate method to False: 16 17 [global] 18 checker.check_skipped_app_config = False 19 20 You may also dynamically add or replace check_* methods in this way. 21 """ 22 23 on = True 24
25 - def __init__(self):
27
28 - def __call__(self):
29 """Run all check_* methods.""" 30 if self.on: 31 oldformatwarning = warnings.formatwarning 32 warnings.formatwarning = self.formatwarning 33 try: 34 for name in dir(self): 35 if name.startswith("check_"): 36 method = getattr(self, name) 37 if method and callable(method): 38 method() 39 finally: 40 warnings.formatwarning = oldformatwarning
41
42 - def formatwarning(self, message, category, filename, lineno, line=None):
43 """Function to format a warning.""" 44 return "CherryPy Checker:\n%s\n\n" % message
45 46 # This value should be set inside _cpconfig. 47 global_config_contained_paths = False 48
49 - def check_skipped_app_config(self):
50 for sn, app in cherrypy.tree.apps.iteritems(): 51 if not isinstance(app, cherrypy.Application): 52 continue 53 if not app.config: 54 msg = "The Application mounted at %r has an empty config." % sn 55 if self.global_config_contained_paths: 56 msg += (" It looks like the config you passed to " 57 "cherrypy.config.update() contains application-" 58 "specific sections. You must explicitly pass " 59 "application config via " 60 "cherrypy.tree.mount(..., config=app_config)") 61 warnings.warn(msg) 62 return
63
64 - def check_static_paths(self):
65 # Use the dummy Request object in the main thread. 66 request = cherrypy.request 67 for sn, app in cherrypy.tree.apps.iteritems(): 68 if not isinstance(app, cherrypy.Application): 69 continue 70 request.app = app 71 for section in app.config: 72 # get_resource will populate request.config 73 request.get_resource(section + "/dummy.html") 74 conf = request.config.get 75 76 if conf("tools.staticdir.on", False): 77 msg = "" 78 root = conf("tools.staticdir.root") 79 dir = conf("tools.staticdir.dir") 80 if dir is None: 81 msg = "tools.staticdir.dir is not set." 82 else: 83 fulldir = "" 84 if os.path.isabs(dir): 85 fulldir = dir 86 if root: 87 msg = ("dir is an absolute path, even " 88 "though a root is provided.") 89 testdir = os.path.join(root, dir[1:]) 90 if os.path.exists(testdir): 91 msg += ("\nIf you meant to serve the " 92 "filesystem folder at %r, remove " 93 "the leading slash from dir." % testdir) 94 else: 95 if not root: 96 msg = "dir is a relative path and no root provided." 97 else: 98 fulldir = os.path.join(root, dir) 99 if not os.path.isabs(fulldir): 100 msg = "%r is not an absolute path." % fulldir 101 102 if fulldir and not os.path.exists(fulldir): 103 if msg: 104 msg += "\n" 105 msg += ("%r (root + dir) is not an existing " 106 "filesystem path." % fulldir) 107 108 if msg: 109 warnings.warn("%s\nsection: [%s]\nroot: %r\ndir: %r" 110 % (msg, section, root, dir))
111 112 113 # -------------------------- Compatibility -------------------------- # 114 115 obsolete = { 116 'server.default_content_type': 'tools.response_headers.headers', 117 'log_access_file': 'log.access_file', 118 'log_config_options': None, 119 'log_file': 'log.error_file', 120 'log_file_not_found': None, 121 'log_request_headers': 'tools.log_headers.on', 122 'log_to_screen': 'log.screen', 123 'show_tracebacks': 'request.show_tracebacks', 124 'throw_errors': 'request.throw_errors', 125 'profiler.on': ('cherrypy.tree.mount(profiler.make_app(' 126 'cherrypy.Application(Root())))'), 127 } 128 129 deprecated = {} 130
131 - def _compat(self, config):
132 """Process config and warn on each obsolete or deprecated entry.""" 133 for section, conf in config.iteritems(): 134 if isinstance(conf, dict): 135 for k, v in conf.iteritems(): 136 if k in self.obsolete: 137 warnings.warn("%r is obsolete. Use %r instead.\n" 138 "section: [%s]" % 139 (k, self.obsolete[k], section)) 140 elif k in self.deprecated: 141 warnings.warn("%r is deprecated. Use %r instead.\n" 142 "section: [%s]" % 143 (k, self.deprecated[k], section)) 144 else: 145 if section in self.obsolete: 146 warnings.warn("%r is obsolete. Use %r instead." 147 % (section, self.obsolete[section])) 148 elif section in self.deprecated: 149 warnings.warn("%r is deprecated. Use %r instead." 150 % (section, self.deprecated[section]))
151
152 - def check_compatibility(self):
153 """Process config and warn on each obsolete or deprecated entry.""" 154 self._compat(cherrypy.config) 155 for sn, app in cherrypy.tree.apps.iteritems(): 156 if not isinstance(app, cherrypy.Application): 157 continue 158 self._compat(app.config)
159 160 161 # ------------------------ Known Namespaces ------------------------ # 162 163 extra_config_namespaces = [] 164
165 - def _known_ns(self, app):
166 ns = ["wsgi"] 167 ns.extend(app.toolboxes.keys()) 168 ns.extend(app.namespaces.keys()) 169 ns.extend(app.request_class.namespaces.keys()) 170 ns.extend(cherrypy.config.namespaces.keys()) 171 ns += self.extra_config_namespaces 172 173 for section, conf in app.config.iteritems(): 174 is_path_section = section.startswith("/") 175 if is_path_section and isinstance(conf, dict): 176 for k, v in conf.iteritems(): 177 atoms = k.split(".") 178 if len(atoms) > 1: 179 if atoms[0] not in ns: 180 # Spit out a special warning if a known 181 # namespace is preceded by "cherrypy." 182 if (atoms[0] == "cherrypy" and atoms[1] in ns): 183 msg = ("The config entry %r is invalid; " 184 "try %r instead.\nsection: [%s]" 185 % (k, ".".join(atoms[1:]), section)) 186 else: 187 msg = ("The config entry %r is invalid, because " 188 "the %r config namespace is unknown.\n" 189 "section: [%s]" % (k, atoms[0], section)) 190 warnings.warn(msg) 191 elif atoms[0] == "tools": 192 if atoms[1] not in dir(cherrypy.tools): 193 msg = ("The config entry %r may be invalid, " 194 "because the %r tool was not found.\n" 195 "section: [%s]" % (k, atoms[1], section)) 196 warnings.warn(msg)
197
198 - def check_config_namespaces(self):
199 """Process config and warn on each unknown config namespace.""" 200 for sn, app in cherrypy.tree.apps.iteritems(): 201 if not isinstance(app, cherrypy.Application): 202 continue 203 self._known_ns(app)
204 205 206 207 208 # -------------------------- Config Types -------------------------- # 209 210 known_config_types = {} 211
212 - def _populate_known_types(self):
213 import __builtin__ 214 builtins = [x for x in vars(__builtin__).values() 215 if type(x) is type(str)] 216 217 def traverse(obj, namespace): 218 for name in dir(obj): 219 vtype = type(getattr(obj, name, None)) 220 if vtype in builtins: 221 self.known_config_types[namespace + "." + name] = vtype
222 223 traverse(cherrypy.request, "request") 224 traverse(cherrypy.response, "response") 225 traverse(cherrypy.server, "server") 226 traverse(cherrypy.engine, "engine") 227 traverse(cherrypy.log, "log")
228
229 - def _known_types(self, config):
230 msg = ("The config entry %r in section %r is of type %r, " 231 "which does not match the expected type %r.") 232 233 for section, conf in config.iteritems(): 234 if isinstance(conf, dict): 235 for k, v in conf.iteritems(): 236 if v is not None: 237 expected_type = self.known_config_types.get(k, None) 238 vtype = type(v) 239 if expected_type and vtype != expected_type: 240 warnings.warn(msg % (k, section, vtype.__name__, 241 expected_type.__name__)) 242 else: 243 k, v = section, conf 244 if v is not None: 245 expected_type = self.known_config_types.get(k, None) 246 vtype = type(v) 247 if expected_type and vtype != expected_type: 248 warnings.warn(msg % (k, section, vtype.__name__, 249 expected_type.__name__))
250
251 - def check_config_types(self):
252 """Assert that config values are of the same type as default values.""" 253 self._known_types(cherrypy.config) 254 for sn, app in cherrypy.tree.apps.iteritems(): 255 if not isinstance(app, cherrypy.Application): 256 continue 257 self._known_types(app.config)
258 259 260 # -------------------- Specific config warnings -------------------- # 261
262 - def check_localhost(self):
263 """Warn if any socket_host is 'localhost'. See #711.""" 264 for k, v in cherrypy.config.iteritems(): 265 if k == 'server.socket_host' and v == 'localhost': 266 warnings.warn("The use of 'localhost' as a socket host can " 267 "cause problems on newer systems, since 'localhost' can " 268 "map to either an IPv4 or an IPv6 address. You should " 269 "use '127.0.0.1' or '[::1]' instead.")
270