1099
by matt.giuca
dispatch/__init__.py: Updated header comments to new policy, updated copyright. |
1 |
# IVLE - Informatics Virtual Learning Environment
|
2 |
# Copyright (C) 2007-2009 The University of Melbourne
|
|
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
3 |
#
|
4 |
# This program is free software; you can redistribute it and/or modify
|
|
5 |
# it under the terms of the GNU General Public License as published by
|
|
6 |
# the Free Software Foundation; either version 2 of the License, or
|
|
7 |
# (at your option) any later version.
|
|
8 |
#
|
|
9 |
# This program is distributed in the hope that it will be useful,
|
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12 |
# GNU General Public License for more details.
|
|
13 |
#
|
|
14 |
# You should have received a copy of the GNU General Public License
|
|
15 |
# along with this program; if not, write to the Free Software
|
|
16 |
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
17 |
||
1099.1.1
by Matt Giuca
Began implementing new dispatch framework (with Will Grant and Nick Chadwick). |
18 |
# Author: Matt Giuca, Will Grant
|
1099
by matt.giuca
dispatch/__init__.py: Updated header comments to new policy, updated copyright. |
19 |
|
20 |
"""
|
|
21 |
This is a mod_python handler program. The correct way to call it is to have
|
|
22 |
Apache send all requests to be handled by the module 'dispatch'.
|
|
23 |
||
24 |
Top-level handler. Handles all requests to all pages in IVLE.
|
|
25 |
Handles authentication (not authorization).
|
|
26 |
Then passes the request along to the appropriate ivle app.
|
|
27 |
"""
|
|
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
28 |
|
29 |
import sys |
|
30 |
import os |
|
31 |
import os.path |
|
32 |
import urllib |
|
33 |
import cgi |
|
34 |
import traceback |
|
35 |
import logging |
|
36 |
import socket |
|
37 |
import time |
|
1099.1.72
by Nick Chadwick
Dispatch now generates an index for each plugin type, allowing plugins to |
38 |
import inspect |
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
39 |
|
40 |
import mod_python |
|
1099.1.1
by Matt Giuca
Began implementing new dispatch framework (with Will Grant and Nick Chadwick). |
41 |
import routes |
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
42 |
|
43 |
from ivle import util |
|
44 |
import ivle.conf |
|
45 |
import ivle.conf.apps |
|
1099.1.5
by William Grant
ivle.dispatch{,.{login,request}}: Fix mod_python imports to ensure that we can |
46 |
from ivle.dispatch.request import Request |
47 |
from ivle.dispatch import login |
|
1099.1.95
by William Grant
Error views are now retrieved from a class method of the view, not the plugin |
48 |
from ivle.webapp.base.plugins import ViewPlugin |
1099.1.110
by William Grant
Implement an authorization system in the new framework. This breaks the REST |
49 |
from ivle.webapp.errors import HTTPError, Unauthorized |
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
50 |
import apps |
51 |
import html |
|
52 |
||
1099.1.1
by Matt Giuca
Began implementing new dispatch framework (with Will Grant and Nick Chadwick). |
53 |
# XXX List of plugins, which will eventually be read in from conf
|
54 |
plugins_HACK = [ |
|
1099.1.68
by William Grant
Move the remaining images to the new framework, in the new ivle.webapp.core |
55 |
'ivle.webapp.core#Plugin', |
1099.1.11
by William Grant
ivle.dispatch: Change plugins_HACK spec such that it takes a sequence of |
56 |
'ivle.webapp.admin.user#Plugin', |
1099.1.22
by root
ivle.dispatch: Reorder things in plugins_HACK to fix wildcards clobbering |
57 |
'ivle.webapp.tutorial#Plugin', |
1099.1.20
by William Grant
ivle.webapp.admin.subject: Port www/apps/subjects to new framework. |
58 |
'ivle.webapp.admin.subject#Plugin', |
1099.1.43
by William Grant
ivle.webapp.browser: Move to ivle.webapp.filesystem.browser. |
59 |
'ivle.webapp.filesystem.browser#Plugin', |
1099.1.48
by William Grant
ivle.webapp.filesystem.diff: Port www/apps/diff to new framework. This moves |
60 |
'ivle.webapp.filesystem.diff#Plugin', |
1099.1.54
by William Grant
ivle.webapp.filesystem.svnlog: Port www/apps/svnlog to new framework. As with |
61 |
'ivle.webapp.filesystem.svnlog#Plugin', |
1099.1.17
by Nick Chadwick
Moved groups over to the new class-based xhtml templating way of being |
62 |
'ivle.webapp.groups#Plugin', |
1099.1.29
by William Grant
ivle.webapp.console.service: Port www/apps/consoleservice to new framework. |
63 |
'ivle.webapp.console#Plugin', |
1099.1.41
by William Grant
Port www/apps/logout to new framework (in ivle.webapp.security). |
64 |
'ivle.webapp.security#Plugin', |
1099.1.59
by William Grant
Provide a media file framework in ivle.webapp.media. |
65 |
'ivle.webapp.media#Plugin', |
1099.1.80
by William Grant
Port the forum app to the new framework. With it also comes new cookie |
66 |
'ivle.webapp.forum#Plugin', |
1099.2.1
by Nick Chadwick
Added help to the plugins hack in dispatch. |
67 |
'ivle.webapp.help#Plugin', |
1099.1.108
by William Grant
Port the tos app to the new framework, and fix ivle.webapp.help's reference |
68 |
'ivle.webapp.tos#Plugin', |
1099.1.72
by Nick Chadwick
Dispatch now generates an index for each plugin type, allowing plugins to |
69 |
]
|
1099.1.1
by Matt Giuca
Began implementing new dispatch framework (with Will Grant and Nick Chadwick). |
70 |
|
1099.1.72
by Nick Chadwick
Dispatch now generates an index for each plugin type, allowing plugins to |
71 |
def generate_route_mapper(view_plugins): |
1099.1.1
by Matt Giuca
Began implementing new dispatch framework (with Will Grant and Nick Chadwick). |
72 |
"""
|
73 |
Build a Mapper object for doing URL matching using 'routes', based on the
|
|
1099.1.59
by William Grant
Provide a media file framework in ivle.webapp.media. |
74 |
given plugin registry.
|
1099.1.1
by Matt Giuca
Began implementing new dispatch framework (with Will Grant and Nick Chadwick). |
75 |
"""
|
1099.1.13
by William Grant
ivle.dispatch: Throw the routes mapper into req.mapper, and make it explicit. |
76 |
m = routes.Mapper(explicit=True) |
1099.1.72
by Nick Chadwick
Dispatch now generates an index for each plugin type, allowing plugins to |
77 |
for plugin in view_plugins: |
1099.1.1
by Matt Giuca
Began implementing new dispatch framework (with Will Grant and Nick Chadwick). |
78 |
# Establish a URL pattern for each element of plugin.urls
|
1099.1.72
by Nick Chadwick
Dispatch now generates an index for each plugin type, allowing plugins to |
79 |
assert hasattr(plugin, 'urls'), "%r does not have any urls" % plugin |
80 |
for url in plugin.urls: |
|
1099.1.1
by Matt Giuca
Began implementing new dispatch framework (with Will Grant and Nick Chadwick). |
81 |
routex = url[0] |
82 |
view_class = url[1] |
|
83 |
kwargs_dict = url[2] if len(url) >= 3 else {} |
|
84 |
m.connect(routex, view=view_class, **kwargs_dict) |
|
85 |
return m |
|
86 |
||
1099.1.59
by William Grant
Provide a media file framework in ivle.webapp.media. |
87 |
def get_plugin(pluginstr): |
88 |
plugin_path, classname = pluginstr.split('#') |
|
89 |
# Load the plugin module from somewhere in the Python path
|
|
90 |
# (Note that plugin_path is a fully-qualified Python module name).
|
|
91 |
return (plugin_path, |
|
92 |
getattr(__import__(plugin_path, fromlist=[classname]), classname)) |
|
93 |
||
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
94 |
def handler(req): |
95 |
"""Handles a request which may be to anywhere in the site except media.
|
|
96 |
Intended to be called by mod_python, as a handler.
|
|
97 |
||
98 |
req: An Apache request object.
|
|
99 |
"""
|
|
100 |
# Make the request object into an IVLE request which can be passed to apps
|
|
101 |
apachereq = req |
|
102 |
try: |
|
103 |
req = Request(req, html.write_html_head) |
|
104 |
except Exception: |
|
105 |
# Pass the apachereq to error reporter, since ivle req isn't created
|
|
106 |
# yet.
|
|
107 |
handle_unknown_exception(apachereq, *sys.exc_info()) |
|
108 |
# Tell Apache not to generate its own errors as well
|
|
1099.1.4
by William Grant
ivle.dispatch: Move some imports around so that it can be imported from |
109 |
return mod_python.apache.OK |
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
110 |
|
111 |
# Run the main handler, and catch all exceptions
|
|
112 |
try: |
|
113 |
return handler_(req, apachereq) |
|
114 |
except mod_python.apache.SERVER_RETURN: |
|
115 |
# An apache error. We discourage these, but they might still happen.
|
|
116 |
# Just raise up.
|
|
117 |
raise
|
|
118 |
except Exception: |
|
119 |
handle_unknown_exception(req, *sys.exc_info()) |
|
120 |
# Tell Apache not to generate its own errors as well
|
|
1099.1.4
by William Grant
ivle.dispatch: Move some imports around so that it can be imported from |
121 |
return mod_python.apache.OK |
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
122 |
|
123 |
def handler_(req, apachereq): |
|
124 |
"""
|
|
125 |
Nested handler function. May raise exceptions. The top-level handler is
|
|
126 |
just used to catch exceptions.
|
|
127 |
Takes both an IVLE request and an Apache req.
|
|
128 |
"""
|
|
129 |
# Hack? Try and get the user login early just in case we throw an error
|
|
130 |
# (most likely 404) to stop us seeing not logged in even when we are.
|
|
131 |
if not req.publicmode: |
|
132 |
req.user = login.get_user_details(req) |
|
133 |
||
1099.1.1
by Matt Giuca
Began implementing new dispatch framework (with Will Grant and Nick Chadwick). |
134 |
### BEGIN New plugins framework ###
|
135 |
# XXX This should be done ONCE per Python process, not per request.
|
|
136 |
# (Wait till WSGI)
|
|
137 |
# XXX No authentication is done here
|
|
1099.1.59
by William Grant
Provide a media file framework in ivle.webapp.media. |
138 |
req.plugins = dict([get_plugin(pluginstr) for pluginstr in plugins_HACK]) |
1099.1.72
by Nick Chadwick
Dispatch now generates an index for each plugin type, allowing plugins to |
139 |
# Index the plugins by base class
|
140 |
req.plugin_index = {} |
|
141 |
for plugin in req.plugins.values(): |
|
142 |
# Getmro returns a tuple of all the super-classes of the plugin
|
|
143 |
for base in inspect.getmro(plugin): |
|
144 |
if base not in req.plugin_index: |
|
145 |
req.plugin_index[base] = [] |
|
146 |
req.plugin_index[base].append(plugin) |
|
1099.1.59
by William Grant
Provide a media file framework in ivle.webapp.media. |
147 |
req.reverse_plugins = dict([(v, k) for (k, v) in req.plugins.items()]) |
1099.1.72
by Nick Chadwick
Dispatch now generates an index for each plugin type, allowing plugins to |
148 |
req.mapper = generate_route_mapper(req.plugin_index[ViewPlugin]) |
1099.1.59
by William Grant
Provide a media file framework in ivle.webapp.media. |
149 |
|
1099.1.13
by William Grant
ivle.dispatch: Throw the routes mapper into req.mapper, and make it explicit. |
150 |
matchdict = req.mapper.match(req.uri) |
1099.1.1
by Matt Giuca
Began implementing new dispatch framework (with Will Grant and Nick Chadwick). |
151 |
if matchdict is not None: |
152 |
viewcls = matchdict['view'] |
|
153 |
# Get the remaining arguments, less 'view', 'action' and 'controller'
|
|
154 |
# (The latter two seem to be built-in, and we don't want them).
|
|
155 |
kwargs = matchdict.copy() |
|
156 |
del kwargs['view'] |
|
1099.1.84
by William Grant
Handle HTTPErrors nicely in the new framework. Currently there is no facility |
157 |
try: |
1099.1.86
by William Grant
Also capture the view object creation in the new framework's exception handler. |
158 |
# Instantiate the view, which should be a BaseView class
|
159 |
view = viewcls(req, **kwargs) |
|
1099.1.110
by William Grant
Implement an authorization system in the new framework. This breaks the REST |
160 |
|
161 |
# Check that the request (mainly the user) is permitted to access
|
|
162 |
# the view.
|
|
163 |
if not view.authorize(req): |
|
164 |
raise Unauthorized() |
|
1099.1.86
by William Grant
Also capture the view object creation in the new framework's exception handler. |
165 |
# Render the output
|
1099.1.84
by William Grant
Handle HTTPErrors nicely in the new framework. Currently there is no facility |
166 |
view.render(req) |
167 |
except HTTPError, e: |
|
168 |
# A view explicitly raised an HTTP error. Respect it.
|
|
169 |
req.status = e.code |
|
1099.1.91
by William Grant
Add support for custom error views. Plugins can now declare that errors |
170 |
|
171 |
# Try to find a custom error view.
|
|
1099.1.95
by William Grant
Error views are now retrieved from a class method of the view, not the plugin |
172 |
if hasattr(viewcls, 'get_error_view'): |
173 |
errviewcls = viewcls.get_error_view(e) |
|
174 |
else: |
|
175 |
errviewcls = None |
|
176 |
||
1099.1.91
by William Grant
Add support for custom error views. Plugins can now declare that errors |
177 |
if errviewcls: |
178 |
errview = errviewcls(req, e) |
|
179 |
errview.render(req) |
|
180 |
return req.OK |
|
181 |
else: |
|
182 |
req.write(e.message) |
|
183 |
return e.code |
|
1099.1.84
by William Grant
Handle HTTPErrors nicely in the new framework. Currently there is no facility |
184 |
except Exception, e: |
185 |
# A non-HTTPError appeared. We have an unknown exception. Panic.
|
|
186 |
handle_unknown_exception(req, *sys.exc_info()) |
|
1099.1.88
by William Grant
Make sure that we don't use the old framework if the new framework crashes. |
187 |
return req.OK |
1099.1.84
by William Grant
Handle HTTPErrors nicely in the new framework. Currently there is no facility |
188 |
else: |
189 |
req.store.commit() |
|
190 |
return req.OK |
|
1099.1.1
by Matt Giuca
Began implementing new dispatch framework (with Will Grant and Nick Chadwick). |
191 |
### END New plugins framework ###
|
192 |
||
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
193 |
# Check req.app to see if it is valid. 404 if not.
|
194 |
if req.app is not None and req.app not in ivle.conf.apps.app_url: |
|
1081
by me at id
ivle.conf, ivle.dispatch: Redo some of Nick's changes made between the |
195 |
req.throw_error(Request.HTTP_NOT_FOUND, |
196 |
"There is no application called %s." % repr(req.app)) |
|
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
197 |
|
198 |
# Special handling for public mode - only allow the public app, call it
|
|
199 |
# and get out.
|
|
200 |
# NOTE: This will not behave correctly if the public app uses
|
|
201 |
# write_html_head_foot, but "serve" does not.
|
|
202 |
if req.publicmode: |
|
203 |
if req.app != ivle.conf.apps.public_app: |
|
204 |
req.throw_error(Request.HTTP_FORBIDDEN, |
|
205 |
"This application is not available on the public site.") |
|
206 |
app = ivle.conf.apps.app_url[ivle.conf.apps.public_app] |
|
207 |
apps.call_app(app.dir, req) |
|
208 |
return req.OK |
|
209 |
||
210 |
# app is the App object for the chosen app
|
|
211 |
if req.app is None: |
|
212 |
app = ivle.conf.apps.app_url[ivle.conf.apps.default_app] |
|
213 |
else: |
|
214 |
app = ivle.conf.apps.app_url[req.app] |
|
215 |
||
216 |
# Check if app requires auth. If so, perform authentication and login.
|
|
217 |
# This will either return a User object, None, or perform a redirect
|
|
218 |
# which we will not catch here.
|
|
219 |
if app.requireauth: |
|
220 |
req.user = login.login(req) |
|
221 |
logged_in = req.user is not None |
|
222 |
else: |
|
223 |
req.user = login.get_user_details(req) |
|
224 |
logged_in = True |
|
225 |
||
226 |
if logged_in: |
|
227 |
# Keep the user's session alive by writing to the session object.
|
|
228 |
# req.get_session().save()
|
|
229 |
# Well, it's a fine idea, but it creates considerable grief in the
|
|
230 |
# concurrent update department, so instead, we'll just make the
|
|
231 |
# sessions not time out.
|
|
232 |
req.get_session().unlock() |
|
233 |
||
234 |
# If user did not specify an app, HTTP redirect to default app and
|
|
235 |
# exit.
|
|
236 |
if req.app is None: |
|
237 |
req.throw_redirect(util.make_path(ivle.conf.apps.default_app)) |
|
238 |
||
239 |
# Set the default title to the app's tab name, if any. Otherwise URL
|
|
240 |
# name.
|
|
241 |
if app.name is not None: |
|
242 |
req.title = app.name |
|
243 |
else: |
|
244 |
req.title = req.app |
|
245 |
||
246 |
# Call the specified app with the request object
|
|
247 |
apps.call_app(app.dir, req) |
|
248 |
||
249 |
# if not logged in, login.login will have written the login box.
|
|
250 |
# Just clean up and exit.
|
|
251 |
||
252 |
# MAKE SURE we write the HTTP (and possibly HTML) header. This
|
|
253 |
# wouldn't happen if nothing else ever got written, so we have to make
|
|
254 |
# sure.
|
|
255 |
req.ensure_headers_written() |
|
256 |
||
257 |
# When done, write out the HTML footer if the app has requested it
|
|
258 |
if req.write_html_head_foot: |
|
259 |
html.write_html_foot(req) |
|
260 |
||
261 |
# Note: Apache will not write custom HTML error messages here.
|
|
262 |
# Use req.throw_error to do that.
|
|
263 |
return req.OK |
|
264 |
||
265 |
def handle_unknown_exception(req, exc_type, exc_value, exc_traceback): |
|
266 |
"""
|
|
267 |
Given an exception that has just been thrown from IVLE, print its details
|
|
268 |
to the request.
|
|
269 |
This is a full handler. It assumes nothing has been written, and writes a
|
|
270 |
complete HTML page.
|
|
271 |
req: May be EITHER an IVLE req or an Apache req.
|
|
272 |
IVLE reqs may have the HTML head/foot written (on a 400 error), but
|
|
273 |
the handler code may pass an apache req if an exception occurs before
|
|
274 |
the IVLE request is created.
|
|
275 |
"""
|
|
276 |
req.content_type = "text/html" |
|
277 |
logfile = os.path.join(ivle.conf.log_path, 'ivle_error.log') |
|
278 |
logfail = False |
|
279 |
# For some reason, some versions of mod_python have "_server" instead of
|
|
280 |
# "main_server". So we check for both.
|
|
281 |
try: |
|
1099.1.4
by William Grant
ivle.dispatch: Move some imports around so that it can be imported from |
282 |
admin_email = mod_python.apache.main_server.server_admin |
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
283 |
except AttributeError: |
284 |
try: |
|
1099.1.4
by William Grant
ivle.dispatch: Move some imports around so that it can be imported from |
285 |
admin_email = mod_python.apache._server.server_admin |
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
286 |
except AttributeError: |
287 |
admin_email = "" |
|
288 |
try: |
|
289 |
httpcode = exc_value.httpcode |
|
290 |
req.status = httpcode |
|
291 |
except AttributeError: |
|
292 |
httpcode = None |
|
1099.1.4
by William Grant
ivle.dispatch: Move some imports around so that it can be imported from |
293 |
req.status = mod_python.apache.HTTP_INTERNAL_SERVER_ERROR |
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
294 |
try: |
1087
by chadnickbok
Fixes Issue #3 |
295 |
publicmode = req.publicmode |
296 |
except AttributeError: |
|
1088
by chadnickbok
Fixed an issue with my previous patch to this file. Now, if |
297 |
publicmode = True |
1087
by chadnickbok
Fixes Issue #3 |
298 |
try: |
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
299 |
login = req.user.login |
300 |
except AttributeError: |
|
301 |
login = None |
|
1087
by chadnickbok
Fixes Issue #3 |
302 |
try: |
303 |
role = req.user.role |
|
304 |
except AttributeError: |
|
305 |
role = None |
|
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
306 |
|
307 |
# Log File
|
|
308 |
try: |
|
309 |
for h in logging.getLogger().handlers: |
|
310 |
logging.getLogger().removeHandler(h) |
|
311 |
logging.basicConfig(level=logging.INFO, |
|
312 |
format='%(asctime)s %(levelname)s: ' + |
|
313 |
'(HTTP: ' + str(req.status) + |
|
314 |
', Ref: ' + str(login) + '@' + |
|
315 |
str(socket.gethostname()) + str(req.uri) + |
|
316 |
') %(message)s', |
|
317 |
filename=logfile, |
|
318 |
filemode='a') |
|
319 |
except IOError: |
|
320 |
logfail = True |
|
321 |
logging.debug('Logging Unhandled Exception') |
|
322 |
||
323 |
# We handle 3 types of error.
|
|
324 |
# IVLEErrors with 4xx response codes (client error).
|
|
325 |
# IVLEErrors with 5xx response codes (handled server error).
|
|
326 |
# Other exceptions (unhandled server error).
|
|
327 |
# IVLEErrors should not have other response codes than 4xx or 5xx
|
|
328 |
# (eg. throw_redirect should have been used for 3xx codes).
|
|
329 |
# Therefore, that is treated as an unhandled error.
|
|
330 |
||
331 |
if (exc_type == util.IVLEError and httpcode >= 400 |
|
332 |
and httpcode <= 499): |
|
333 |
# IVLEErrors with 4xx response codes are client errors.
|
|
334 |
# Therefore, these have a "nice" response (we even coat it in the IVLE
|
|
335 |
# HTML wrappers).
|
|
336 |
||
337 |
req.write_html_head_foot = True |
|
338 |
req.write_javascript_settings = False |
|
339 |
req.write('<div id="ivle_padding">\n') |
|
340 |
try: |
|
341 |
codename, msg = req.get_http_codename(httpcode) |
|
342 |
except AttributeError: |
|
343 |
codename, msg = None, None |
|
344 |
# Override the default message with the supplied one,
|
|
345 |
# if available.
|
|
346 |
if exc_value.message is not None: |
|
347 |
msg = exc_value.message |
|
348 |
if codename is not None: |
|
349 |
req.write("<h1>Error: %s</h1>\n" % cgi.escape(codename)) |
|
350 |
else: |
|
351 |
req.write("<h1>Error</h1>\n") |
|
352 |
if msg is not None: |
|
353 |
req.write("<p>%s</p>\n" % cgi.escape(msg)) |
|
354 |
else: |
|
355 |
req.write("<p>An unknown error occured.</p>\n") |
|
356 |
||
357 |
# Logging
|
|
358 |
logging.info(str(msg)) |
|
359 |
||
360 |
req.write("<p>(HTTP error code %d)</p>\n" % httpcode) |
|
361 |
if logfail: |
|
362 |
req.write("<p>Warning: Could not open Error Log: '%s'</p>\n" |
|
363 |
%cgi.escape(logfile)) |
|
364 |
req.write('</div>\n') |
|
365 |
html.write_html_foot(req) |
|
366 |
else: |
|
367 |
# A "bad" error message. We shouldn't get here unless IVLE
|
|
368 |
# misbehaves (which is currently very easy, if things aren't set up
|
|
369 |
# correctly).
|
|
370 |
# Write the traceback.
|
|
371 |
# If this is a non-4xx IVLEError, get the message and httpcode and
|
|
372 |
# make the error message a bit nicer (but still include the
|
|
373 |
# traceback).
|
|
374 |
# We also need to special-case IVLEJailError, as we can get another
|
|
375 |
# almost-exception out of it.
|
|
376 |
||
377 |
codename, msg = None, None |
|
378 |
||
379 |
if exc_type is util.IVLEJailError: |
|
380 |
msg = exc_value.type_str + ": " + exc_value.message |
|
381 |
tb = 'Exception information extracted from IVLEJailError:\n' |
|
382 |
tb += urllib.unquote(exc_value.info) |
|
383 |
else: |
|
384 |
try: |
|
385 |
codename, msg = req.get_http_codename(httpcode) |
|
386 |
except AttributeError: |
|
387 |
pass
|
|
388 |
# Override the default message with the supplied one,
|
|
389 |
# if available.
|
|
390 |
if hasattr(exc_value, 'message') and exc_value.message is not None: |
|
391 |
msg = exc_value.message |
|
392 |
# Prepend the exception type
|
|
393 |
if exc_type != util.IVLEError: |
|
394 |
msg = exc_type.__name__ + ": " + msg |
|
395 |
||
396 |
tb = ''.join(traceback.format_exception(exc_type, exc_value, |
|
397 |
exc_traceback)) |
|
398 |
||
399 |
# Logging
|
|
400 |
logging.error('%s\n%s'%(str(msg), tb)) |
|
1087
by chadnickbok
Fixes Issue #3 |
401 |
# Error messages are only displayed is the user is NOT a student,
|
402 |
# or if there has been a problem logging the error message
|
|
1096
by me at id
ivle.dispatch: Only show tracebacks if we are logged in and not a student, or |
403 |
show_errors = (not publicmode) and ((login and \ |
404 |
str(role) != "student") or logfail) |
|
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
405 |
req.write("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" |
406 |
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
407 |
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
408 |
<head><title>IVLE Internal Server Error</title></head>
|
|
409 |
<body>
|
|
410 |
<h1>IVLE Internal Server Error""") |
|
1087
by chadnickbok
Fixes Issue #3 |
411 |
if (show_errors): |
412 |
if (codename is not None |
|
1099.1.4
by William Grant
ivle.dispatch: Move some imports around so that it can be imported from |
413 |
and httpcode != mod_python.apache.HTTP_INTERNAL_SERVER_ERROR): |
1087
by chadnickbok
Fixes Issue #3 |
414 |
req.write(": %s" % cgi.escape(codename)) |
415 |
||
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
416 |
req.write("""</h1> |
417 |
<p>An error has occured which is the fault of the IVLE developers or
|
|
1087
by chadnickbok
Fixes Issue #3 |
418 |
administration. The developers have been notified.</p>
|
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
419 |
""") |
1087
by chadnickbok
Fixes Issue #3 |
420 |
if (show_errors): |
421 |
if msg is not None: |
|
422 |
req.write("<p>%s</p>\n" % cgi.escape(msg)) |
|
423 |
if httpcode is not None: |
|
424 |
req.write("<p>(HTTP error code %d)</p>\n" % httpcode) |
|
425 |
req.write(""" |
|
426 |
<p>Please report this to <a href="mailto:%s">%s</a> (the system |
|
427 |
administrator). Include the following information:</p>
|
|
428 |
""" % (cgi.escape(admin_email), cgi.escape(admin_email))) |
|
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
429 |
|
1087
by chadnickbok
Fixes Issue #3 |
430 |
req.write("<pre>\n%s\n</pre>\n"%cgi.escape(tb)) |
431 |
if logfail: |
|
432 |
req.write("<p>Warning: Could not open Error Log: '%s'</p>\n" |
|
433 |
%cgi.escape(logfile)) |
|
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
434 |
req.write("</body></html>") |