Provide tools.response.render_http_exception and use that

After the webob->werkzeug transition, controller functions can raise
werkzeug.HttpExceptions. We need to catch these in app.py when calling
the controller and handle them, rendering the corresponding error Response()
object. For consistency, we also want to allow meddleware functions to
raise HttpExceptions (e.g. the csrf meddleware needs to complain about lack
of cookies), so wrap the request and response parts of the meddleware too.

Finally, the urlmap.match() can also raise HttpExceptions, so we give it the
same treatment (render_http_exception). I am not sure, if we do not need to
handle the Redirect exception there in any different way though...

The new function render_http_exception makes use of the render_error infrastructure
to return a nicely templated error page. It also checks if the stock error
messages was used in cases where we have localizations (403, 404) and use those.

It is now possible to do things like "raise Forbidden(_('You suckr'))" or
raise NotFound(_('where is my left show again')) if you want to return
customized error messages to the user.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
This commit is contained in:
Sebastian Spaeth 2012-12-23 11:57:45 +01:00
parent 511d5b8966
commit 785b287fcb
2 changed files with 46 additions and 15 deletions

View File

@ -24,7 +24,7 @@ from werkzeug.exceptions import HTTPException, NotFound
from mediagoblin import meddleware, __version__
from mediagoblin.tools import common, translate, template
from mediagoblin.tools.response import render_404
from mediagoblin.tools.response import render_http_exception
from mediagoblin.tools.theme import register_themes
from mediagoblin.tools import request as mg_request
from mediagoblin.mg_globals import setup_globals
@ -188,12 +188,11 @@ class MediaGoblinApp(object):
try:
endpoint, url_values = map_adapter.match()
request.matchdict = url_values
except NotFound as exc:
return render_404(request)(environ, start_response)
except HTTPException as exc:
# exceptions that match() is documented to return:
# MethodNotAllowed, RequestRedirect TODO: need to handle ???
return exc(environ, start_response)
# Stop and render exception
return render_http_exception(
request, exc,
exc.get_description(environ))(environ, start_response)
view_func = view_functions[endpoint]
@ -209,19 +208,32 @@ class MediaGoblinApp(object):
controller = view_func
# pass the request through our meddleware classes
for m in self.meddleware:
response = m.process_request(request, controller)
if response is not None:
return response(environ, start_response)
try:
for m in self.meddleware:
response = m.process_request(request, controller)
if response is not None:
return response(environ, start_response)
except HTTPException as e:
return render_http_exception(
request, e,
e.get_description(environ))(environ, start_response)
request.start_response = start_response
# get the response from the controller
response = controller(request)
# get the Http response from the controller
try:
response = controller(request)
except HTTPException as e:
response = render_http_exception(
request, e, e.get_description(environ))
# pass the response through the meddleware
for m in self.meddleware[::-1]:
m.process_response(request, response)
# pass the response through the meddlewares
try:
for m in self.meddleware[::-1]:
m.process_response(request, response)
except HTTPException as e:
response = render_http_exeption(
request, e, e.get_description(environ))
return response(environ, start_response)

View File

@ -63,6 +63,25 @@ def render_404(request):
return render_error(request, 404, err_msg=err_msg)
def render_http_exception(request, exc, description):
"""Return Response() given a werkzeug.HTTPException
:param exc: werkzeug.HTTPException or subclass thereof
:description: message describing the error."""
# If we were passed the HTTPException stock description on
# exceptions where we have localized ones, use those:
stock_desc = (description == exc.__class__.description)
if stock_desc and exc.code == 403:
return render_403(request)
elif stock_desc and exc.code == 404:
return render_404(request)
return render_error(request, title=exc.args[0],
err_msg=description,
status=exc.code)
def redirect(request, *args, **kwargs):
"""Redirects to an URL, using urlgen params or location string