from Acquisition import aq_parent from Products.CMFCore.utils import getToolByName from Products.CacheSetup.config import log, CACHE_TOOL_ID, PLONE25 from patch_utils import wrap_method, call_pattern from cmf_utils import _checkConditionalGET, _setCacheHeaders try: from Products.PageTemplates.DeferExpr import LazyWrapper except: LazyWrapper = None if PLONE25: from StringIO import StringIO from zope.app.publisher.interfaces.browser import IBrowserView else: from Products.CMFPlone.patches.unicodehacks import FasterStringIO as StringIO from zope.publisher.interfaces.browser import IBrowserView #### patch FSPageTemplate.pt_render # Goal: if a 304 can be determined, rendering the template is cut # off. Otherwise cache headers are set. from Products.CMFCore.FSPageTemplate import FSPageTemplate def FSPT_pt_render(self, source=0, extra_context={}): pcs = getToolByName(self, CACHE_TOOL_ID, None) # if portal_cache_settings not in place, fall back to the old method if pcs is None or not pcs.getEnabled(): return call_pattern(self, 'pt_render', '__CacheSetup_FSPageTemplate_%s__', source, extra_context) self._updateFromFS() # Make sure the template has been loaded. if not source: request = self.REQUEST object = self.getParentNode() view = self.getId() member = pcs.getMember() (rule, header_set) = pcs.getRuleAndHeaderSet(request, object, view, member) if header_set is not None: expr_context = rule._getExpressionContext(request, object, view, member, keywords=extra_context) else: expr_context = None # If we have a conditional get, set status 304 and return # no content if _checkConditionalGET(self, extra_context, rule, header_set, expr_context): if PLONE25: return '' return u'' result = FSPageTemplate.inheritedAttribute('pt_render')( self, source, extra_context ) if not source: _setCacheHeaders(self, extra_context, rule, header_set, expr_context) return result #### patch PageTemplate.pt_render # Goal: actually set the 304 reponse header if applicable. from Products.PageTemplates.Expressions import getEngine if PLONE25: from TAL.TALInterpreter import TALInterpreter from Products.PageTemplates.PageTemplate import \ PageTemplateTracebackSupplement, PTRuntimeError else: from zope.tal.talinterpreter import TALInterpreter from zope.pagetemplate.pagetemplate import \ PageTemplateTracebackSupplement, PTRuntimeError def PT_pt_render(self, source=0, extra_context={}): """Render this Page Template""" pcs = getToolByName(self, CACHE_TOOL_ID, None) # if portal_cache_settings not in place, fall back to the old method if pcs is None or not pcs.getEnabled(): return call_pattern(self, 'pt_render', '__CacheSetup_PageTemplate_%s__', source, extra_context) if not self._v_cooked: self._cook() __traceback_supplement__ = (PageTemplateTracebackSupplement, self, self.pt_getContext()) if self._v_errors: e = str(self._v_errors) raise PTRuntimeError, ( 'Page Template %s has errors: %s' % (self.id, e)) if not source: # If we have a conditional get, set status 304 and return no # content request = self.REQUEST object = self.getParentNode() # we may get this if we have a Zope 3 browser view if IBrowserView.providedBy(object): view = getattr(object, '__name__', request['ACTUAL_URL'].split('/')[-1]) object = aq_parent(object) else: view = self.getId() view = str(view) member = pcs.getMember() (rule, header_set) = pcs.getRuleAndHeaderSet(request, object, view, member) if header_set is not None: expr_context = rule._getExpressionContext(request, object, view, member, keywords=extra_context) else: expr_context = None if _checkConditionalGET(self, extra_context, rule, header_set, expr_context): if PLONE25: return '' return u'' if PLONE25: output = self.StringIO() else: output = StringIO(u'') c = self.pt_getContext() c.update(extra_context) context = getEngine().getContext(c) TALInterpreter(self._v_program, self._v_macros, context, output, tal=not source, strictinsert=0)() # The following looks like it was left over from when we still did macro caching # I'm commenting it out for now as I don't think we do lazy expressions in cachefu anymore # ##clean up - XXX ## try to eliminate circular references - this may be overkill #if LazyWrapper is not None: # context._compiler = None # context.contexts = None # context.repeat_vars = None # if PLONE25: # items = context.global_vars.items() # else: # items = context.vars.items() # for k,v in items: # if isinstance(v, LazyWrapper): # v._expr = None # v._econtext = None # v._result = None # if PLONE25: # if context.vars: # while len(context.vars): # context.vars._pop() # context.global_vars.clear() # context.global_vars = None # context.local_vars.clear() # context.local_vars = None # else: # context.vars.clear() # context.vars = None # context._scope_stack = None result = output.getvalue() if not source: _setCacheHeaders(self, extra_context, rule, header_set, expr_context) return result def run(): log('Applying CMF patches...') from Products.PageTemplates.PageTemplate import PageTemplate wrap_method(PageTemplate, 'pt_render', PT_pt_render, '__CacheSetup_PageTemplate_%s__') from Products.CMFCore.FSPageTemplate import FSPageTemplate wrap_method(FSPageTemplate, 'pt_render', FSPT_pt_render, '__CacheSetup_FSPageTemplate_%s__') log('CMF Patches applied.')