59
49
# Make the request object into an IVLE request which can be passed to apps
62
req = Request(req, html.write_html_head)
64
# Pass the apachereq to error reporter, since ivle req isn't created
66
handle_unknown_exception(apachereq, *sys.exc_info())
67
# Tell Apache not to generate its own errors as well
70
# Run the main handler, and catch all exceptions
72
return handler_(req, apachereq)
73
except mod_python.apache.SERVER_RETURN:
74
# An apache error. We discourage these, but they might still happen.
78
handle_unknown_exception(req, *sys.exc_info())
79
# Tell Apache not to generate its own errors as well
82
def handler_(req, apachereq):
84
Nested handler function. May raise exceptions. The top-level handler is
85
just used to catch exceptions.
86
Takes both an IVLE request and an Apache req.
88
# Hack? Try and get the user login early just in case we throw an error
89
# (most likely 404) to stop us seeing not logged in even when we are.
90
if not req.publicmode:
91
req.user = login.get_user_details(req)
51
req = Request(req, html.write_html_head)
93
53
# Check req.app to see if it is valid. 404 if not.
94
54
if req.app is not None and req.app not in conf.apps.app_url:
95
55
# Maybe it is a special app!
96
#if req.app == 'logout':
99
req.throw_error(Request.HTTP_NOT_FOUND,
100
"There is no application called %s." % repr(req.app))
56
if req.app == 'logout':
59
# TODO: Nicer 404 message?
60
req.throw_error(Request.HTTP_NOT_FOUND)
102
# Special handling for public mode - only allow the public app, call it
62
# Special handling for public mode - just call public app and get out
104
63
# NOTE: This will not behave correctly if the public app uses
105
64
# write_html_head_foot, but "serve" does not.
106
65
if req.publicmode:
107
if req.app != conf.apps.public_app:
108
req.throw_error(Request.HTTP_FORBIDDEN,
109
"This application is not available on the public site.")
110
66
app = conf.apps.app_url[conf.apps.public_app]
111
67
apps.call_app(app.dir, req)
118
74
app = conf.apps.app_url[req.app]
120
76
# Check if app requires auth. If so, perform authentication and login.
121
# This will either return a User object, None, or perform a redirect
122
# which we will not catch here.
123
77
if app.requireauth:
124
req.user = login.login(req)
125
logged_in = req.user is not None
78
req.username = login.login(req)
79
logged_in = req.username is not None
127
req.user = login.get_user_details(req)
81
req.username = login.get_username(req)
131
85
# Keep the user's session alive by writing to the session object.
132
# req.get_session().save()
133
# Well, it's a fine idea, but it creates considerable grief in the
134
# concurrent update department, so instead, we'll just make the
135
# sessions not time out.
136
req.get_session().unlock()
86
req.get_session().save()
138
87
# If user did not specify an app, HTTP redirect to default app and
140
89
if req.app is None:
161
109
# When done, write out the HTML footer if the app has requested it
162
110
if req.write_html_head_foot:
163
# Show the console if required
164
if logged_in and app.useconsole:
165
plugins.console.present(req, windowpane=True)
166
111
html.write_html_foot(req)
168
113
# Note: Apache will not write custom HTML error messages here.
169
114
# Use req.throw_error to do that.
172
def handle_unknown_exception(req, exc_type, exc_value, exc_traceback):
174
Given an exception that has just been thrown from IVLE, print its details
176
This is a full handler. It assumes nothing has been written, and writes a
178
req: May be EITHER an IVLE req or an Apache req.
179
IVLE reqs may have the HTML head/foot written (on a 400 error), but
180
the handler code may pass an apache req if an exception occurs before
181
the IVLE request is created.
183
req.content_type = "text/html"
184
logfile = os.path.join(conf.conf.log_path, 'ivle_error.log')
186
# For some reason, some versions of mod_python have "_server" instead of
187
# "main_server". So we check for both.
189
admin_email = apache.main_server.server_admin
190
except AttributeError:
192
admin_email = apache._server.server_admin
193
except AttributeError:
196
httpcode = exc_value.httpcode
197
req.status = httpcode
198
except AttributeError:
200
req.status = apache.HTTP_INTERNAL_SERVER_ERROR
202
login = req.user.login
203
except AttributeError:
208
for h in logging.getLogger().handlers:
209
logging.getLogger().removeHandler(h)
210
logging.basicConfig(level=logging.INFO,
211
format='%(asctime)s %(levelname)s: ' +
212
'(HTTP: ' + str(req.status) +
213
', Ref: ' + str(login) + '@' +
214
str(socket.gethostname()) + str(req.uri) +
220
logging.debug('Logging Unhandled Exception')
222
# We handle 3 types of error.
223
# IVLEErrors with 4xx response codes (client error).
224
# IVLEErrors with 5xx response codes (handled server error).
225
# Other exceptions (unhandled server error).
226
# IVLEErrors should not have other response codes than 4xx or 5xx
227
# (eg. throw_redirect should have been used for 3xx codes).
228
# Therefore, that is treated as an unhandled error.
230
if (exc_type == util.IVLEError and httpcode >= 400
231
and httpcode <= 499):
232
# IVLEErrors with 4xx response codes are client errors.
233
# Therefore, these have a "nice" response (we even coat it in the IVLE
236
req.write_html_head_foot = True
237
req.write_javascript_settings = False
238
req.write('<div id="ivle_padding">\n')
240
codename, msg = req.get_http_codename(httpcode)
241
except AttributeError:
242
codename, msg = None, None
243
# Override the default message with the supplied one,
245
if exc_value.message is not None:
246
msg = exc_value.message
247
if codename is not None:
248
req.write("<h1>Error: %s</h1>\n" % cgi.escape(codename))
250
req.write("<h1>Error</h1>\n")
252
req.write("<p>%s</p>\n" % cgi.escape(msg))
254
req.write("<p>An unknown error occured.</p>\n")
257
logging.info(str(msg))
259
req.write("<p>(HTTP error code %d)</p>\n" % httpcode)
261
req.write("<p>Warning: Could not open Error Log: '%s'</p>\n"
262
%cgi.escape(logfile))
263
req.write('</div>\n')
264
html.write_html_foot(req)
266
# A "bad" error message. We shouldn't get here unless IVLE
267
# misbehaves (which is currently very easy, if things aren't set up
269
# Write the traceback.
270
# If this is a non-4xx IVLEError, get the message and httpcode and
271
# make the error message a bit nicer (but still include the
273
# We also need to special-case IVLEJailError, as we can get another
274
# almost-exception out of it.
276
codename, msg = None, None
278
if exc_type is util.IVLEJailError:
279
msg = exc_value.type_str + ": " + exc_value.message
280
tb = 'Exception information extracted from IVLEJailError:\n'
281
tb += urllib.unquote(exc_value.info)
284
codename, msg = req.get_http_codename(httpcode)
285
except AttributeError:
287
# Override the default message with the supplied one,
289
if hasattr(exc_value, 'message') and exc_value.message is not None:
290
msg = exc_value.message
291
# Prepend the exception type
292
if exc_type != util.IVLEError:
293
msg = exc_type.__name__ + ": " + msg
295
tb = ''.join(traceback.format_exception(exc_type, exc_value,
299
logging.error('%s\n%s'%(str(msg), tb))
301
req.write("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
302
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
303
<html xmlns="http://www.w3.org/1999/xhtml">
304
<head><title>IVLE Internal Server Error</title></head>
306
<h1>IVLE Internal Server Error""")
307
if (codename is not None
308
and httpcode != apache.HTTP_INTERNAL_SERVER_ERROR):
309
req.write(": %s" % cgi.escape(codename))
311
<p>An error has occured which is the fault of the IVLE developers or
315
req.write("<p>%s</p>\n" % cgi.escape(msg))
316
if httpcode is not None:
317
req.write("<p>(HTTP error code %d)</p>\n" % httpcode)
319
<p>Please report this to <a href="mailto:%s">%s</a> (the system
320
administrator). Include the following information:</p>
321
""" % (cgi.escape(admin_email), cgi.escape(admin_email)))
323
req.write("<pre>\n%s\n</pre>\n"%cgi.escape(tb))
325
req.write("<p>Warning: Could not open Error Log: '%s'</p>\n"
326
%cgi.escape(logfile))
327
req.write("</body></html>")
118
"""Log out the current user (if any) by destroying the session state.
119
Then redirect to the top-level IVLE page."""
120
session = req.get_session()
123
req.throw_redirect(util.make_path(''))