Back to index

plone3  3.1.7
resource.py
Go to the documentation of this file.
00001 from zope.publisher.interfaces.browser import IBrowserPublisher
00002 from zope.interface import implements
00003 from concatfileresource import ConcatFiles
00004 from interfaces import ICachedResource
00005 import cachingadapter   # force adapter registration
00006 
00007 try:
00008     from zope.publisher.browser import BrowserView
00009     from zope.datetime import time as timeFromDateTimeString
00010 except ImportError:
00011     # Zope < 2.10
00012     from zope.app.publisher.browser import BrowserView
00013     from zope.app.datetimeutils import time as timeFromDateTimeString
00014 
00015 try:
00016     import Products.Five
00017 except ImportError:
00018     __five__ = False
00019     from zope.app.publisher.browser.resource import Resource
00020 else:
00021     __five__ = True
00022     try:
00023         # Zope 2.8 / Five 1.0.2
00024         from Products.Five.resource import Resource
00025         __five_pre_1_3_ = True
00026     except ImportError:
00027         # Zope 2.9 / Five 1.3
00028         from Products.Five.browser.resource import Resource
00029         __five_pre_1_3__ = False
00030 
00031 class GenericResource(BrowserView, Resource):
00032     """A publishable resource"""
00033 
00034     if __five__:
00035         #implements(IBrowserPublisher)
00036 
00037         def __browser_default__(self, request):
00038             return self, (request.REQUEST_METHOD,)
00039 
00040     else:
00041         implements(IBrowserPublisher)
00042 
00043         def publishTraverse(self, request, name):
00044             '''See interface IBrowserPublisher'''
00045             raise LookupError(name)
00046 
00047         def browserDefault(self, request):
00048             '''See interface IBrowserPublisher'''
00049             return getattr(self, request.method), ()
00050 
00051     # for unit tests
00052     def _testData(self):
00053         return self.context.data
00054 
00055     def chooseContext(self):
00056         """Choose the appropriate context"""
00057         return self.context
00058 
00059     def GET(self):
00060         """Default document"""
00061 
00062         file = self.chooseContext()
00063         request = self.request
00064         response = request.response
00065 
00066         # Control in-memory caching
00067         cache_in_memory = file.caching == 'memory'
00068         if cache_in_memory:
00069             last_mod = file.lmt
00070             if last_mod > file.data_last_fetched:
00071                 # force delete file contents
00072                 file.purgeData()
00073 
00074         # HTTP If-Modified-Since header handling. This is duplicated
00075         # from OFS.Image.Image - it really should be consolidated
00076         # somewhere...
00077         if __five__:
00078             header = request.get_header('If-Modified-Since')
00079         else:
00080             header = request.getHeader('If-Modified-Since', None)
00081         if header is not None:
00082             header = header.split(';')[0]
00083             # Some proxies seem to send invalid date strings for this
00084             # header. If the date string is not valid, we ignore it
00085             # rather than raise an error to be generally consistent
00086             # with common servers such as Apache (which can usually
00087             # understand the screwy date string as a lucky side effect
00088             # of the way they parse it).
00089             try:    mod_since=long(timeFromDateTimeString(header))
00090             except: mod_since=None
00091             if mod_since is not None:
00092                 if not cache_in_memory:
00093                     last_mod = file.lmt
00094                 if last_mod > 0 and int(last_mod) <= mod_since:
00095                     response.setStatus(304)
00096                     return ''
00097 
00098         response.setHeader('Content-Type', file.content_type)
00099         response.setHeader('Last-Modified', file.lmh)
00100         # Cache for one day
00101         response.setHeader('Cache-Control', 'public,max-age=86400')
00102         data = file.data
00103 
00104         if not cache_in_memory:
00105             # force delete file contents
00106             file.purgeData()
00107 
00108         return data
00109 
00110     def HEAD(self):
00111         file = self.chooseContext()
00112         response = self.request.response
00113         response.setHeader('Content-Type', file.content_type)
00114         response.setHeader('Last-Modified', file.lmh)
00115         # Cache for one day
00116         response.setHeader('Cache-Control', 'public,max-age=86400')
00117         return ''
00118 
00119 class ResourceFactory(object):
00120 
00121     factory = None
00122     resource = None
00123 
00124     def __init__(self, path, name, compress_level, caching, lmt_check_period,
00125                 resource_factory=None, checker=None):
00126         self.__name = name
00127         self.__path = path
00128         self.__compress_level = compress_level
00129         self.__caching = caching
00130         self.__lmt_check_period = lmt_check_period
00131         if resource_factory is not None:
00132             self.resource = resource_factory
00133         # z3 only
00134         self.__checker = checker
00135 
00136     def __call__(self, request):
00137         try:
00138             rsrc = self.__rsrc
00139         except AttributeError:
00140             # Delayed creation. That assures that registry is set up by this time.
00141             rsrc = self.__rsrc = ICachedResource(self.factory(self.__path, self.__name,
00142                     self.__compress_level, self.__caching, self.__lmt_check_period))
00143         resource = self.resource(rsrc, request)
00144         # z3 only
00145         resource.__name__ = self.__name
00146         if self.__checker is not None:
00147             # z3 only
00148             resource.__Security_checker__ = self.__checker
00149         return resource
00150 
00151 class ConcatResourceFactory(ResourceFactory):
00152     """A factory for concat resources"""
00153 
00154     factory = ConcatFiles
00155     resource = GenericResource