Welcome, guest | Sign In | My Account | Store | Cart

Notice! PyPM is being replaced with the ActiveState Platform, which enhances PyPM’s build and deploy capabilities. Create your free Platform account to download ActivePython or customize Python with the packages you require and get automatic updates.

Download
ActivePython
INSTALL>
pypm install z3ext.cacheheaders

How to install z3ext.cacheheaders

  1. Download and install ActivePython
  2. Open Command Prompt
  3. Type pypm install z3ext.cacheheaders
 Python 2.7Python 3.2Python 3.3
Windows (32-bit)
1.2.0 Available View build log
Windows (64-bit)
1.2.0 Available View build log
Mac OS X (10.5+)
1.2.0 Available View build log
Linux (32-bit)
1.2.0 Available View build log
Linux (64-bit)
1.2.0 Available View build log
Web
 
Author
License
ZPL 2.1
Lastest release
version 1.2.0 on Jan 5th, 2011

Browser caching headers

Publication with support 304 response code

>>> import time, datetime, pytz
>>> from zope import component, interface
>>> from z3ext.cacheheaders import interfaces
>>> from z3ext.cacheheaders.publication import \
...    BrowserFactory, BrowserPublication
>>> factory = BrowserFactory()
>>> factory.canHandle({})
True
>>> rclass, pclass = factory()
>>> pclass == BrowserPublication
True
>>> pub = BrowserPublication(None)
>>> from zope.publisher.browser import TestRequest
>>> from zope.publisher.interfaces.http import IHTTPRequest
>>> request = TestRequest()
>>> response = request.response
>>> request.setPublication(pub)

We need object

>>> class IContent(interface.Interface):
...   pass
>>> class Content(object):
...   interface.implements(IContent)
...   marker = 0
...
...   def __call__(self):
...      self.marker = 1
...      return 'Content body'
>>> ob = Content()
>>> print pub.callObject(request, ob)
Content body

If we want control caching headers we need define ICacheStrategy adapter. this package predefine some cache strategies. Simplest is StatusCache, it's base on object modification date (IModificationInfo interface) So to use static cache fist we need IModificationInfo adapter

>>> from z3ext.cacheheaders.staticcache import getStaticCache
>>> getStaticCache(ob) is None
True
>>> class ModInfo(object):
...   interface.implements(interfaces.IModificationInfo)
...   component.adapts(IContent)
...
...   dt = datetime.datetime(2007, 10, 10, 0, 0, 0, 0, tzinfo=pytz.utc)
...
...   def __init__(self, context):
...      self.context = context
...
...   def modified(self):
...      return long(time.mktime(self.dt.utctimetuple()))
>>> component.provideAdapter(ModInfo)
>>> strategy = getStaticCache(ob).__bind__(request)
>>> interfaces.ICacheStrategy.providedBy(strategy)
True

This strategy uses 'If-Modified-Since' request header.

>>> request._environ['IF_MODIFIED_SINCE'] = 'Mon, 10 Dec 2007 00:00:00 GMT'
>>> strategy.isModified()
False
>>> request._environ['IF_MODIFIED_SINCE'] = 'Mon, 10 Sep 2007 00:00:00 GMT'
>>> strategy.isModified()
True

If format is wrong isModified is always True

>>> request._environ['IF_MODIFIED_SINCE'] = 'wrong format'
>>> strategy.isModified()
True
>>> request._environ['IF_MODIFIED_SINCE'] = 'Mon, 10 Dec 2007 00:00:00 GMT'

Static Cache set 'Cache-Control', 'Expires', 'Last-Modified' headers for browser

>>> strategy.setCacheHeaders()
>>> response.getHeader('Cache-Control')
'public,max-age=86400'
>>> response.getHeader('Expires')
'..., ... GMT'
>>> response.getHeader('Last-Modified')
'Wed, 10 Oct 2007 01:00:00 GMT'

It also should automaticly convert modified date to utc timezone

>>> ModInfo.dt = datetime.datetime(2007, 10, 10, 0, 0, 0, 0)
>>> strategy = getStaticCache(ob).__bind__(request)
>>> strategy.setCacheHeaders()
>>> response.getHeader('Last-Modified')
'Wed, 10 Oct 2007 01:00:00 GMT'
>>> ModInfo.dt = datetime.datetime(
...   2007, 10, 9, 18, 0, 0, 0, pytz.timezone('Asia/Almaty'))
>>> strategy = getStaticCache(ob).__bind__(request)
>>> strategy.setCacheHeaders()
>>> response.getHeader('Last-Modified')
'Wed, 10 Oct 2007 01:00:00 GMT'
>>> ModInfo.dt = datetime.datetime(2007, 10, 10, 0, 0, 0, 0, tzinfo=pytz.utc)

To use this cache we have to register adater

>>> component.provideAdapter(getStaticCache, (IContent,))

Now we can use this strategy in publication. If content doesn't changed we should get just 304 response code

>>> print pub.callObject(request, ob)
<BLANKLINE>
>>> response.getStatus()
304

Or content

>>> response.setStatus('200')
>>> request._environ['IF_MODIFIED_SINCE'] = 'Mon, 10 Sep 2007 00:00:00 GMT'
>>> print pub.callObject(request, ob)
Content body
>>> response.getStatus()
200
>>> response.getHeader('Last-Modified')
'Wed, 10 Oct 2007 01:00:00 GMT'

Additional feature, calculating duration of call.

>>> pub.beforeTraversal(request)
>>> time.sleep(2)
>>> pub.afterCall(request, ob)
>>> response.getHeader('X-Generated-Time')
'... sec'

CHANGES

1.2.0 (2009-11-24)
  • Added AfterExceptionCallEvent event
1.1.1 (2009-08-28)
  • Tring to get object instead of MethodType object for AfterCallEvent
1.1.0 (2009-08-11)
  • Added AfterCallEvent event
1.0.3 (2009-04-17)
  • Do no use zope.component.interfaces.IView
1.0.1 (2008-03-28)
  • Added buldout config for tests
  • Code moved to svn.zope.org
1.0.0 (2008-02-02)
  • Initial release

Subscribe to package updates

Last updated Jan 5th, 2011

Download Stats

Last month:1

What does the lock icon mean?

Builds marked with a lock icon are only available via PyPM to users with a current ActivePython Business Edition subscription.

Need custom builds or support?

ActivePython Enterprise Edition guarantees priority access to technical support, indemnification, expert consulting and quality-assured language builds.

Plan on re-distributing ActivePython?

Get re-distribution rights and eliminate legal risks with ActivePython OEM Edition.