1 import os
2 import warnings
3
4 import cherrypy
5
6
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
27
41
45
46
47 global_config_contained_paths = False
48
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
65
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
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
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
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
159
160
161
162
163 extra_config_namespaces = []
164
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
181
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
204
205
206
207
208
209
210 known_config_types = {}
211
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
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
258
259
260
261
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