Tutorial
Return to main page
Date: 09/14/10 at 13:42:57
model_url()s for objects outside a virtual root
Author: junkafarianDate: 09/14/10 at 13:42:57
If part of your application is served behind a virtual root, repoze.bfg.url.model_url will return any urls for objects outside of the virtual root using the same url as is configured in the request object passed to the utility.
I found a need to serve the root of the traversal graph on one domain and a child object on another which meant any references to objects external to the vroot resulted in 404's.
This amendment to the default TraversalContextURL implementation allows you to specify an alternative domain to serve requests outside of the virtual root alongside configuring the virtual root using environ variables.
I found a need to serve the root of the traversal graph on one domain and a child object on another which meant any references to objects external to the vroot resulted in 404's.
This amendment to the default TraversalContextURL implementation allows you to specify an alternative domain to serve requests outside of the virtual root alongside configuring the virtual root using environ variables.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | from zope.interface import implements from repoze.bfg.interfaces import IContextURL from repoze.bfg.interfaces import VH_ROOT_KEY from repoze.bfg.traversal import find_model from repoze.bfg.traversal import find_root from repoze.bfg.traversal import model_path NON_VH_URL_KEY = 'HTTP_X_NON_VHM_URL' class TraversalContextURL(object): """ The IContextURL adapter used to generate URLs for a context object obtained via graph traversal""" implements(IContextURL) vroot_varname = VH_ROOT_KEY non_vroot_varname = NON_VH_URL_KEY def __init__(self, context, request): self.context = context self.request = request def virtual_root(self): environ = self.request.environ vroot_varname = self.vroot_varname if vroot_varname in environ: return find_model(self.context, environ[vroot_varname]) # shortcut instead of using find_root; we probably already # have it on the request try: return self.request.root except AttributeError: return find_root(self.context) def __call__(self): """ Generate a URL based on the :term:`lineage` of a :term:`model` object obtained via :term:`traversal`. If any model in the context lineage has a Unicode name, it will be converted to a UTF-8 string before being attached to the URL. If a ``HTTP_X_VHM_ROOT`` key is present in the WSGI environment, its value will be treated as a 'virtual root path': the path of the URL generated by this will be left-stripped of this virtual root path value. """ path = model_path(self.context) if path != '/': path = path + '/' request = self.request environ = request.environ vroot_varname = self.vroot_varname non_vroot_varname = self.non_vroot_varname app_url = request.application_url # never ends in a slash # if the path starts with the virtual root path, trim it out if vroot_varname in environ: vroot_path = environ[vroot_varname] if path.startswith(vroot_path): path = path[len(vroot_path):] elif non_vroot_varname in environ: # If an alternative domain is configured, use that app_url = environ[non_vroot_varname].rstrip('/') # never ends in a slash return app_url + path #### tests #### from repoze.bfg.tests.test_traversal import TraversalContextURLTests as BFGTraversalContextURLTests from repoze.bfg.tests.test_traversal import DummyContext, DummyRequest class TraversalContextURLTests(BFGTraversalContextURLTests): def _getTargetClass(self): return TraversalContextURL def test_call_outside_vroot_no_non_vhm_url(self): """ If the ``NON_VH_URL_KEY`` var is not set, the original behaviour should remain. """ from repoze.bfg.interfaces import VH_ROOT_KEY root = DummyContext() root.__parent__ = None root.__name__ = None one = DummyContext() one.__parent__ = root one.__name__ = 'one' two = DummyContext() two.__parent__ = one two.__name__ = 'two' three = DummyContext() three.__parent__ = root three.__name__ = 'three' request = DummyRequest({VH_ROOT_KEY:'/one'}) context_url = self._makeOne(three, request) result = context_url() self.assertEqual(result, 'http://example.com:5432/three/') request = DummyRequest({VH_ROOT_KEY:'/one/two'}) context_url = self._makeOne(three, request) result = context_url() self.assertEqual(result, 'http://example.com:5432/three/') def test_call_outside_vroot_with_non_vhm_url(self): """ If the ``NON_VH_URL_KEY`` var is set, any model_url() calls for objects located outside the vroot should use the configured url. """ from repoze.bfg.interfaces import VH_ROOT_KEY root = DummyContext() root.__parent__ = None root.__name__ = None one = DummyContext() one.__parent__ = root one.__name__ = 'one' two = DummyContext() two.__parent__ = one two.__name__ = 'two' three = DummyContext() three.__parent__ = root three.__name__ = 'three' request = DummyRequest({VH_ROOT_KEY:'/one', NON_VH_URL_KEY:'http://example.com:4321'}) context_url = self._makeOne(three, request) result = context_url() self.assertEqual(result, 'http://example.com:4321/three/') context_url = self._makeOne(two, request) result = context_url() self.assertEqual(result, 'http://example.com:5432/two/') request = DummyRequest({VH_ROOT_KEY:'/one/two', NON_VH_URL_KEY:'http://example.com:4321'}) context_url = self._makeOne(three, request) result = context_url() self.assertEqual(result, 'http://example.com:4321/three/') context_url = self._makeOne(two, request) result = context_url() self.assertEqual(result, 'http://example.com:5432/') |