[Checkins] SVN: five.pt/trunk/src/five/pt/ Avoid unnecessary recompilations and fix security for the TALES 'repeat' object
Leonardo Rochael Almeida
leorochael at gmail.com
Thu Feb 24 06:27:29 EST 2011
Log message for revision 120560:
Avoid unnecessary recompilations and fix security for the TALES 'repeat' object
Changed:
U five.pt/trunk/src/five/pt/pagetemplate.py
U five.pt/trunk/src/five/pt/patches.py
U five.pt/trunk/src/five/pt/tests/test_persistenttemplate.py
-=-
Modified: five.pt/trunk/src/five/pt/pagetemplate.py
===================================================================
--- five.pt/trunk/src/five/pt/pagetemplate.py 2011-02-24 08:28:59 UTC (rev 120559)
+++ five.pt/trunk/src/five/pt/pagetemplate.py 2011-02-24 11:27:29 UTC (rev 120560)
@@ -49,8 +49,8 @@
return b
-class BaseTemplate(pagetemplate.BaseTemplate):
- """Zope 2-compatible page template class."""
+class BaseTemplateBase(pagetemplate.BaseTemplate):
+ """Base for Zope 2-compatible page template classes."""
utility_builtins = {}
encoding = 'utf-8'
@@ -101,8 +101,15 @@
return namespace
+class BaseTemplate(BaseTemplateBase):
+ """Zope 2-compatible page template class."""
-class BaseTemplateFile(BaseTemplate, pagetemplate.BaseTemplateFile):
+ def __init__(self, body, *args, **kw):
+ super(BaseTemplate, self).__init__(body, *args, **kw)
+ # keep the body for comparison and caching purposes
+ self.body = body
+
+class BaseTemplateFile(BaseTemplateBase, pagetemplate.BaseTemplateFile):
"""Zope 2-compatible page template file class."""
Modified: five.pt/trunk/src/five/pt/patches.py
===================================================================
--- five.pt/trunk/src/five/pt/patches.py 2011-02-24 08:28:59 UTC (rev 120559)
+++ five.pt/trunk/src/five/pt/patches.py 2011-02-24 11:27:29 UTC (rev 120560)
@@ -28,7 +28,18 @@
from Acquisition import ImplicitAcquisitionWrapper
from ComputedAttribute import ComputedAttribute
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from App.class_init import InitializeClass
+# declare Chameleon's repeatdict public
+from chameleon.tal import RepeatDict
+
+RepeatDict.security = ClassSecurityInfo()
+RepeatDict.security.declareObjectPublic()
+RepeatDict.__allow_access_to_unprotected_subobjects__ = True
+
+InitializeClass(RepeatDict)
+
try:
from Products.Five.browser.pagetemplatefile import BoundPageTemplate
except ImportError:
@@ -72,7 +83,7 @@
def _get_five_pt_template(self):
template = getattr(self, '_v_template', _marker)
- if template is _marker or self._text != template.source:
+ if template is _marker or self._text != template.body:
self._v_template = template = BaseTemplate(self._text, keep_source=True)
return template
@@ -88,7 +99,7 @@
return template
def call_template(self, *args, **kw):
- # avoid accidental exposure of the extra context
+ # avoid accidental exposure of the extra context parameter
kw.pop(EXTRA_CONTEXT_KEY, None)
template = self._get_five_pt_template()
return template(self, *args, **kw)
Modified: five.pt/trunk/src/five/pt/tests/test_persistenttemplate.py
===================================================================
--- five.pt/trunk/src/five/pt/tests/test_persistenttemplate.py 2011-02-24 08:28:59 UTC (rev 120559)
+++ five.pt/trunk/src/five/pt/tests/test_persistenttemplate.py 2011-02-24 11:27:29 UTC (rev 120560)
@@ -37,6 +37,11 @@
</tal:block>
""".strip()
+repeat_object = """
+<tal:loop repeat="counter python: range(3)"
+ content="python: repeat['counter'].index" />
+""".strip()
+
options_capture_update_base = """
<metal:use use-macro="context/macro_outer/macros/master">
<metal:fills fill-slot="main_slot">
@@ -50,6 +55,8 @@
for name in names)
return options_capture_update_base % (params,)
+_marker = object()
+
class TestPersistent(ZopeTestCase):
def afterSetUp(self):
from Products.Five import zcml
@@ -97,3 +104,27 @@
template.pt_render(extra_context=extra_context)
del extra_context['capture']
self.assertEquals(extra_context, capture)
+
+ def test_avoid_recompilation(self):
+ template = self._makeOne('foo', simple_i18n)
+ macro_outer = self._makeOne('macro_outer', simple_i18n)
+ # templates are only compiled after the first call
+ self.assertEqual(getattr(template, '_v_template', _marker), _marker)
+ template()
+ # or the first fetching of macros
+ self.assertEqual(getattr(macro_outer, '_v_template', _marker), _marker)
+ macro_outer.macros
+
+ template_compiled = template._v_template
+ macro_outer_compiled = macro_outer._v_template
+
+ # but they should not be recompiled afterwards
+ template()
+ macro_outer.macros
+ self.assertTrue(template_compiled is template._v_template)
+ self.assertTrue(macro_outer_compiled is macro_outer._v_template)
+
+ def test_repeat_object_security(self):
+ template = self._makeOne('foo', repeat_object)
+ # this should not raise an Unauthorized error
+ self.assertEquals(template().strip().split(), u'0 1 2'.split())
More information about the checkins
mailing list