Back to index

plone3  3.1.7
FSFile.py
Go to the documentation of this file.
00001 ##############################################################################
00002 #
00003 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
00004 #
00005 # This software is subject to the provisions of the Zope Public License,
00006 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
00007 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
00008 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00009 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
00010 # FOR A PARTICULAR PURPOSE.
00011 #
00012 ##############################################################################
00013 """ Customizable image objects that come from the filesystem.
00014 
00015 $Id: FSFile.py 76464 2007-06-07 15:38:16Z tseaver $
00016 """
00017 
00018 import codecs
00019 
00020 import Globals
00021 from AccessControl import ClassSecurityInfo
00022 from OFS.Cache import Cacheable
00023 from OFS.Image import File
00024 from zope.contenttype import guess_content_type
00025 
00026 from DirectoryView import registerFileExtension
00027 from DirectoryView import registerMetaType
00028 from FSObject import FSObject
00029 from permissions import FTPAccess
00030 from permissions import View
00031 from permissions import ViewManagementScreens
00032 from utils import _checkConditionalGET
00033 from utils import _dtmldir
00034 from utils import _FSCacheHeaders
00035 from utils import _setCacheHeaders
00036 from utils import _ViewEmulator
00037 
00038 
00039 class FSFile(FSObject):
00040 
00041     """FSFiles act like images but are not directly
00042     modifiable from the management interface."""
00043     # Note that OFS.Image.File is not a base class because it is mutable.
00044 
00045     meta_type = 'Filesystem File'
00046     content_type = 'unknown/unknown'
00047 
00048     manage_options = ({'label':'Customize', 'action':'manage_main'},)
00049 
00050     security = ClassSecurityInfo()
00051     security.declareObjectProtected(View)
00052 
00053     security.declareProtected(ViewManagementScreens, 'manage_main')
00054     manage_main = Globals.DTMLFile('custfile', _dtmldir)
00055 
00056     def __init__(self, id, filepath, fullname=None, properties=None):
00057         id = fullname or id # Use the whole filename.
00058         FSObject.__init__(self, id, filepath, fullname, properties)
00059 
00060     def _createZODBClone(self):
00061         return File(self.getId(), '', self._readFile(1))
00062 
00063     def _get_content_type(self, file, body, id, content_type=None):
00064         # Consult self.content_type first, this is either
00065         # the default (unknown/unknown) or it got a value from a
00066         # .metadata file
00067         default_type = 'unknown/unknown'
00068         if getattr(self, 'content_type', default_type) != default_type:
00069             return self.content_type
00070 
00071         # Next, look at file headers
00072         headers=getattr(file, 'headers', None)
00073         if headers and headers.has_key('content-type'):
00074             content_type=headers['content-type']
00075         else:
00076             # Last resort: Use the (imperfect) content type guessing
00077             # mechanism from OFS.Image, which ultimately uses the
00078             # Python mimetypes module.
00079             if not isinstance(body, basestring):
00080                 body = body.data
00081             content_type, enc=guess_content_type(
00082                 getattr(file, 'filename',id), body, content_type)
00083             if (enc is None
00084                 and (content_type.startswith('text/') or
00085                      content_type.startswith('application/'))
00086                 and body.startswith(codecs.BOM_UTF8)):
00087                 content_type += '; charset=utf-8'
00088 
00089         return content_type
00090 
00091     def _readFile(self, reparse):
00092         """Read the data from the filesystem.
00093         """
00094         file = open(self._filepath, 'rb')
00095         try:
00096             data = file.read()
00097         finally:
00098             file.close()
00099 
00100         if reparse or self.content_type == 'unknown/unknown':
00101             self.ZCacheable_invalidate()
00102             self.content_type=self._get_content_type(file, data, self.id)
00103         return data
00104 
00105     #### The following is mainly taken from OFS/File.py ###
00106 
00107     def __str__(self):
00108         self._updateFromFS()
00109         return str( self._readFile( 0 ) )
00110 
00111     def modified(self):
00112         return self.getModTime()
00113 
00114     security.declareProtected(View, 'index_html')
00115     def index_html(self, REQUEST, RESPONSE):
00116         """
00117         The default view of the contents of a File or Image.
00118 
00119         Returns the contents of the file or image.  Also, sets the
00120         Content-Type HTTP header to the objects content type.
00121         """
00122         self._updateFromFS()
00123         view = _ViewEmulator().__of__(self)
00124 
00125         # If we have a conditional get, set status 304 and return
00126         # no content
00127         if _checkConditionalGET(view, extra_context={}):
00128             return ''
00129 
00130         RESPONSE.setHeader('Content-Type', self.content_type)
00131 
00132         # old-style If-Modified-Since header handling.
00133         if self._setOldCacheHeaders():
00134             # Make sure the CachingPolicyManager gets a go as well
00135             _setCacheHeaders(view, extra_context={})
00136             return ''
00137 
00138         data = self._readFile(0)
00139         data_len = len(data)
00140         RESPONSE.setHeader('Content-Length', data_len)
00141 
00142         #There are 2 Cache Managers which can be in play....
00143         #need to decide which to use to determine where the cache headers
00144         #are decided on.
00145         if self.ZCacheable_getManager() is not None:
00146             self.ZCacheable_set(None)
00147         else:
00148             _setCacheHeaders(view, extra_context={})
00149         return data
00150 
00151     def _setOldCacheHeaders(self):
00152         # return False to disable this simple caching behaviour
00153         return _FSCacheHeaders(self)
00154 
00155     security.declareProtected(View, 'getContentType')
00156     def getContentType(self):
00157         """Get the content type of a file or image.
00158 
00159         Returns the content type (MIME type) of a file or image.
00160         """
00161         self._updateFromFS()
00162         return self.content_type
00163 
00164     security.declareProtected(FTPAccess, 'manage_FTPget')
00165     manage_FTPget = index_html
00166 
00167 Globals.InitializeClass(FSFile)
00168 
00169 registerFileExtension('doc', FSFile)
00170 registerFileExtension('txt', FSFile)
00171 registerFileExtension('pdf', FSFile)
00172 registerFileExtension('swf', FSFile)
00173 registerFileExtension('jar', FSFile)
00174 registerFileExtension('cab', FSFile)
00175 registerFileExtension('ico', FSFile)
00176 registerFileExtension('js', FSFile)
00177 registerFileExtension('css', FSFile)
00178 registerMetaType('File', FSFile)