summaryrefslogtreecommitdiff
path: root/repoze
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-12-10 15:54:43 +0000
committerChris McDonough <chrism@agendaless.com>2009-12-10 15:54:43 +0000
commit29f5c1a101802e0ba66d72195fbe4e9d340a96a0 (patch)
tree83f40864db4d6a8859e2ea6ef1bb1e8d6b359226 /repoze
parent09bbfc5279971f5dfeadb514591b978edeeaa820 (diff)
downloadpyramid-29f5c1a101802e0ba66d72195fbe4e9d340a96a0.tar.gz
pyramid-29f5c1a101802e0ba66d72195fbe4e9d340a96a0.tar.bz2
pyramid-29f5c1a101802e0ba66d72195fbe4e9d340a96a0.zip
- Added a "Special Exceptions" section to the "Views" narrative
documentation chapter explaining the effect of raising ``repoze.bfg.exceptions.NotFound`` and ``repoze.bfg.exceptions.Forbidden`` from within view code. - When the ``repoze.bfg.exceptions.NotFound`` or ``repoze.bfg.exceptions.Forbidden`` error is raised from within a custom root factory or the ``factory`` of a route, the appropriate response is now sent to the requesting user agent (the result of the notfound view or the forbidden view, respectively). When these errors are raised from within a root factory, the ``context`` passed to the notfound or forbidden view will be ``None``. Also, the request will not be decorated with ``view_name``, ``subpath``, ``context``, etc. as would normally be the case if traversal had been allowed to take place.
Diffstat (limited to 'repoze')
-rw-r--r--repoze/bfg/router.py116
-rw-r--r--repoze/bfg/tests/test_router.py43
2 files changed, 101 insertions, 58 deletions
diff --git a/repoze/bfg/router.py b/repoze/bfg/router.py
index deffa4e17..630aa201c 100644
--- a/repoze/bfg/router.py
+++ b/repoze/bfg/router.py
@@ -65,71 +65,73 @@ class Router(object):
try:
# setup
request = Request(environ)
+ context = None
threadlocals['request'] = request
attrs = request.__dict__
attrs['registry'] = registry
has_listeners and registry.notify(NewRequest(request))
+
+ try:
+ # root resolution
+ root_factory = self.root_factory
+ if self.routes_mapper is not None:
+ info = self.routes_mapper(request)
+ match, route = info['match'], info['route']
+ if route is not None:
+ environ['wsgiorg.routing_args'] = ((), match)
+ environ['bfg.routes.route'] = route
+ environ['bfg.routes.matchdict'] = match
+ request.matchdict = match
+ iface = registry.queryUtility(IRouteRequest,
+ name=route.name)
+ if iface is not None:
+ alsoProvides(request, iface)
+ root_factory = route.factory or self.root_factory
+
+ root = root_factory(request)
+ attrs['root'] = root
+
+ # view lookup
+ traverser = registry.adapters.queryAdapter(root, ITraverser)
+ if traverser is None:
+ traverser = ModelGraphTraverser(root)
+ tdict = traverser(request)
+ context, view_name, subpath, traversed, vroot, vroot_path = (
+ tdict['context'], tdict['view_name'], tdict['subpath'],
+ tdict['traversed'], tdict['virtual_root'],
+ tdict['virtual_root_path'])
+ attrs.update(tdict)
+ has_listeners and registry.notify(AfterTraversal(request))
+ provides = map(providedBy, (context, request))
+ view_callable = registry.adapters.lookup(
+ provides, IView, name=view_name, default=None)
- # root resolution
- root_factory = self.root_factory
- if self.routes_mapper is not None:
- info = self.routes_mapper(request)
- match, route = info['match'], info['route']
- if route is not None:
- environ['wsgiorg.routing_args'] = ((), match)
- environ['bfg.routes.route'] = route
- environ['bfg.routes.matchdict'] = match
- request.matchdict = match
- iface = registry.queryUtility(IRouteRequest,
- name=route.name)
- if iface is not None:
- alsoProvides(request, iface)
- root_factory = route.factory or self.root_factory
-
- root = root_factory(request)
- attrs['root'] = root
-
- # view lookup
- traverser = registry.adapters.queryAdapter(root, ITraverser)
- if traverser is None:
- traverser = ModelGraphTraverser(root)
- tdict = traverser(request)
- context, view_name, subpath, traversed, vroot, vroot_path = (
- tdict['context'], tdict['view_name'], tdict['subpath'],
- tdict['traversed'], tdict['virtual_root'],
- tdict['virtual_root_path'])
- attrs.update(tdict)
- has_listeners and registry.notify(AfterTraversal(request))
- provides = map(providedBy, (context, request))
- view_callable = registry.adapters.lookup(
- provides, IView, name=view_name, default=None)
-
- # view execution
- if view_callable is None:
- if self.debug_notfound:
- msg = (
- 'debug_notfound of url %s; path_info: %r, context: %r, '
- 'view_name: %r, subpath: %r, traversed: %r, '
- 'root: %r, vroot: %r, vroot_path: %r' % (
- request.url, request.path_info, context, view_name,
- subpath, traversed, root, vroot, vroot_path)
- )
- logger and logger.debug(msg)
+ # view execution
+ if view_callable is None:
+ if self.debug_notfound:
+ msg = (
+ 'debug_notfound of url %s; path_info: %r, context: %r, '
+ 'view_name: %r, subpath: %r, traversed: %r, '
+ 'root: %r, vroot: %r, vroot_path: %r' % (
+ request.url, request.path_info, context, view_name,
+ subpath, traversed, root, vroot, vroot_path)
+ )
+ logger and logger.debug(msg)
+ else:
+ msg = request.path_info
+ environ['repoze.bfg.message'] = msg
+ response = self.notfound_view(context, request)
else:
- msg = request.path_info
+ response = view_callable(context, request)
+
+ except Forbidden, why:
+ msg = why[0]
+ environ['repoze.bfg.message'] = msg
+ response = self.forbidden_view(context, request)
+ except NotFound, why:
+ msg = why[0]
environ['repoze.bfg.message'] = msg
response = self.notfound_view(context, request)
- else:
- try:
- response = view_callable(context, request)
- except Forbidden, why:
- msg = why[0]
- environ['repoze.bfg.message'] = msg
- response = self.forbidden_view(context, request)
- except NotFound, why:
- msg = why[0]
- environ['repoze.bfg.message'] = msg
- response = self.notfound_view(context, request)
# response handling
has_listeners and registry.notify(NewResponse(response))
diff --git a/repoze/bfg/tests/test_router.py b/repoze/bfg/tests/test_router.py
index 45e66b8fe..5352c6d79 100644
--- a/repoze/bfg/tests/test_router.py
+++ b/repoze/bfg/tests/test_router.py
@@ -42,7 +42,8 @@ class TestRouter(unittest.TestCase):
def _registerTraverserFactory(self, context, view_name='', subpath=None,
traversed=None, virtual_root=None,
- virtual_root_path=None, **kw):
+ virtual_root_path=None, raise_error=None,
+ **kw):
from repoze.bfg.interfaces import ITraverser
if virtual_root is None:
@@ -59,6 +60,8 @@ class TestRouter(unittest.TestCase):
self.root = root
def __call__(self, request):
+ if raise_error:
+ raise raise_error
values = {'root':self.root,
'context':context,
'view_name':view_name,
@@ -504,6 +507,44 @@ class TestRouter(unittest.TestCase):
self.failUnless(req_iface.providedBy(request))
self.failUnless(IFoo.providedBy(request))
+ def test_root_factory_raises_notfound(self):
+ from repoze.bfg.interfaces import IRootFactory
+ from repoze.bfg.exceptions import NotFound
+ from zope.interface import Interface
+ from zope.interface import directlyProvides
+ def rootfactory(request):
+ raise NotFound('from root factory')
+ self.registry.registerUtility(rootfactory, IRootFactory)
+ class IContext(Interface):
+ pass
+ context = DummyContext()
+ directlyProvides(context, IContext)
+ environ = self._makeEnviron()
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ app_iter = router(environ, start_response)
+ self.assertEqual(start_response.status, '404 Not Found')
+ self.failUnless('from root factory' in app_iter[0])
+
+ def test_root_factory_raises_forbidden(self):
+ from repoze.bfg.interfaces import IRootFactory
+ from repoze.bfg.exceptions import Forbidden
+ from zope.interface import Interface
+ from zope.interface import directlyProvides
+ def rootfactory(request):
+ raise Forbidden('from root factory')
+ self.registry.registerUtility(rootfactory, IRootFactory)
+ class IContext(Interface):
+ pass
+ context = DummyContext()
+ directlyProvides(context, IContext)
+ environ = self._makeEnviron()
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ app_iter = router(environ, start_response)
+ self.assertEqual(start_response.status, '401 Unauthorized')
+ self.failUnless('from root factory' in app_iter[0])
+
class DummyContext:
pass