changeset 3848:231c5e16df31

action sendcached renamed to cache (no other changes)
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Mon, 14 Jul 2008 16:01:20 +0200
parents b13f6b68fe43
children d9a525a1450e
files MoinMoin/action/cache.py MoinMoin/action/sendcached.py
diffstat 2 files changed, 210 insertions(+), 210 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/action/cache.py	Mon Jul 14 16:01:20 2008 +0200
@@ -0,0 +1,210 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - Send a raw object from the caching system
+
+    This can be used e.g. for all image generating extensions:
+    E.g. a thumbnail generating extension just uses sendcached.put_cache to
+    write the thumbnails into the cache and emits <img src="sendcached_url">
+    to display them. sendcached_url is returned by put_cache or get_url.
+
+    IMPORTANT: use some non-guessable key derived from your source content.
+
+    TODO:
+    * add secret to wikiconfig
+    * add error handling
+    * maybe use page local caching, not global:
+      + smaller directories
+      - but harder to clean
+      - harder to backup data_dir
+    * move file-like code to caching module
+    * add auto-key generation?
+
+    @copyright: 2008 MoinMoin:ThomasWaldmann
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import hmac, sha
+
+from MoinMoin import log
+logging = log.getLogger(__name__)
+
+# keep both imports below as they are, order is important:
+from MoinMoin import wikiutil
+import mimetypes
+
+from MoinMoin import config, caching
+from MoinMoin.util import filesys
+from MoinMoin.action import AttachFile
+
+action_name = 'sendcached'
+
+# Do NOT get this directly from request.form or user would be able to read any cache!
+sendcached_arena = action_name
+sendcached_scope = 'wiki'
+do_locking = False
+
+def cache_key(request, wikiname=None, itemname=None, attachname=None, content=None, secret=None):
+    """
+    Calculate a (hard-to-guess) cache key.
+
+    If content is supplied, we will calculate and return a hMAC of the content.
+
+    If wikiname, itemname, attachname is given, we don't touch the content (nor do
+    we read it ourselves from the attachment file), but we just calculate a key
+    from the given metadata values and some metadata we get from the filesystem.
+
+    @param request: the request object
+    @param wikiname: the name of the wiki (if not given, will be read from cfg)
+    @param itemname: the name of the page
+    @param attachname: the filename of the attachment
+    @param content: content data as unicode object (e.g. for page content or
+                    parser section content)
+    """
+    secret = secret or 'nobodyexpectedsuchasecret'
+    if content:
+        hmac_data = content
+    elif itemname is not None and attachname is not None:
+        wikiname = wikiname or request.cfg.interwikiname or request.cfg.siteid
+        fuid = filesys.fuid(AttachFile.getFilename(request, itemname, attachname))
+        hmac_data = u''.join([wikiname, itemname, attachname, repr(fuid)])
+    else:
+        raise AssertionError('cache_key called with unsupported parameters')
+
+    hmac_data = hmac_data.encode('utf-8')
+    key = hmac.new(secret, hmac_data, sha).hexdigest()
+    return key
+
+
+def put_cache(request, key, data,
+              filename=None,
+              content_type=None,
+              content_disposition=None,
+              content_length=None,
+              last_modified=None,
+              bufsize=8192):
+    """
+    Cache an object to send with sendcached action later.
+
+    @param request: the request object
+    @param key: non-guessable key into sendcached cache (str)
+    @param data: content data (str or open file-like obj)
+    @param filename: filename for content-disposition header and for autodetecting
+                     content_type (unicode, default: None)
+    @param content_disposition: type for content-disposition header (str, default: None)
+    @param content_type: content-type header value (str, default: autodetect from filename)
+    @param last_modified: last modified timestamp (int, default: autodetect)
+    @param content_length: data length for content-length header (int, default: autodetect)
+    @return: URL of cached object
+    """
+    import os.path
+    from MoinMoin.util import timefuncs
+
+    if filename:
+        # make sure we just have a simple filename (without path)
+        filename = os.path.basename(filename)
+
+        if content_type is None:
+            # try autodetect
+            mt, enc = mimetypes.guess_type(filename)
+            if mt:
+                content_type = mt
+
+    if content_type is None:
+        content_type = 'application/octet-stream'
+
+    data_cache = caching.CacheEntry(request, sendcached_arena, key+'.data',
+                                    sendcached_scope, do_locking=do_locking)
+    data_cache_fname = data_cache._filename()
+
+    if hasattr(data, 'read'):
+        import shutil
+        data_cache_file = open(data_cache_fname, 'wb')
+        shutil.copyfileobj(data, data_cache_file)
+        data_cache_file.close()
+    else:
+        data_cache.update(data)
+
+    content_length = content_length or os.path.getsize(data_cache_fname)
+    last_modified = last_modified or os.path.getmtime(data_cache_fname)
+
+    last_modified = timefuncs.formathttpdate(int(last_modified))
+    headers = ['Content-Type: %s' % content_type,
+               'Last-Modified: %s' % last_modified,
+               'Content-Length: %s' % content_length,
+              ]
+    if content_disposition and filename:
+        # TODO: fix the encoding here, plain 8 bit is not allowed according to the RFCs
+        # There is no solution that is compatible to IE except stripping non-ascii chars
+        filename = filename.encode(config.charset)
+
+        headers.append(
+               'Content-Disposition: %s; filename="%s"' % (content_disposition, filename)
+        )
+
+    meta_cache = caching.CacheEntry(request, sendcached_arena, key+'.meta',
+                                    sendcached_scope, do_locking=do_locking, use_pickle=True)
+    meta_cache.update((last_modified, headers))
+
+    return get_url(request, key)
+
+
+def is_cached(request, key, strict=False):
+    """
+    Check if we have already cached an object for this key.
+
+    @param request: the request object
+    @param key: non-guessable key into sendcached cache (str)
+    @param strict: if True, also check the data cache, not only meta (bool, default: False)
+    @return: is object cached? (bool)
+    """
+    if strict:
+        data_cache = caching.CacheEntry(request, sendcached_arena, key+'.data',
+                                        sendcached_scope, do_locking=do_locking)
+        data_cached = data_cache.exists()
+    else:
+        data_cached = True  # we assume data will be there if meta is there
+
+    meta_cache = caching.CacheEntry(request, sendcached_arena, key+'.meta',
+                                    sendcached_scope, do_locking=do_locking, use_pickle=True)
+    meta_cached = meta_cache.exists()
+
+    return meta_cached and data_cached
+
+
+def get_url(request, key):
+    """ get URL for the object cached for key """
+    return "%s/?%s" % (
+        request.getScriptname(),
+        wikiutil.makeQueryString(dict(action=action_name, key=key), want_unicode=False))
+
+
+def get_cache_headers(request, key):
+    """ get last_modified and headers cached for key """
+    meta_cache = caching.CacheEntry(request, sendcached_arena, key+'.meta',
+                                    sendcached_scope, do_locking=do_locking, use_pickle=True)
+    last_modified, headers = meta_cache.content()
+    return last_modified, headers
+
+
+def get_cache_datafile(request, key):
+    """ get an open data file for the data cached for key """
+    data_cache = caching.CacheEntry(request, sendcached_arena, key+'.data',
+                                    sendcached_scope, do_locking=do_locking)
+    data_file = open(data_cache._filename(), 'rb')
+    return data_file
+
+
+def send_cached(request, key):
+    """ send a complete http response with headers/data cached for key """
+    last_modified, headers = get_cache_headers(request, key)
+    if request.if_modified_since == last_modified:
+        request.emit_http_headers(["Status: 304 Not modified"])
+    else:
+        request.emit_http_headers(headers)
+        request.send_file(get_cache_datafile(request, key))
+
+
+def execute(pagename, request):
+    key = request.form.get('key', [None])[0]
+    send_cached(request, key)
+
--- a/MoinMoin/action/sendcached.py	Mon Jul 14 15:00:52 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,210 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - Send a raw object from the caching system
-
-    This can be used e.g. for all image generating extensions:
-    E.g. a thumbnail generating extension just uses sendcached.put_cache to
-    write the thumbnails into the cache and emits <img src="sendcached_url">
-    to display them. sendcached_url is returned by put_cache or get_url.
-
-    IMPORTANT: use some non-guessable key derived from your source content.
-
-    TODO:
-    * add secret to wikiconfig
-    * add error handling
-    * maybe use page local caching, not global:
-      + smaller directories
-      - but harder to clean
-      - harder to backup data_dir
-    * move file-like code to caching module
-    * add auto-key generation?
-
-    @copyright: 2008 MoinMoin:ThomasWaldmann
-    @license: GNU GPL, see COPYING for details.
-"""
-
-import hmac, sha
-
-from MoinMoin import log
-logging = log.getLogger(__name__)
-
-# keep both imports below as they are, order is important:
-from MoinMoin import wikiutil
-import mimetypes
-
-from MoinMoin import config, caching
-from MoinMoin.util import filesys
-from MoinMoin.action import AttachFile
-
-action_name = 'sendcached'
-
-# Do NOT get this directly from request.form or user would be able to read any cache!
-sendcached_arena = action_name
-sendcached_scope = 'wiki'
-do_locking = False
-
-def cache_key(request, wikiname=None, itemname=None, attachname=None, content=None, secret=None):
-    """
-    Calculate a (hard-to-guess) cache key.
-
-    If content is supplied, we will calculate and return a hMAC of the content.
-
-    If wikiname, itemname, attachname is given, we don't touch the content (nor do
-    we read it ourselves from the attachment file), but we just calculate a key
-    from the given metadata values and some metadata we get from the filesystem.
-
-    @param request: the request object
-    @param wikiname: the name of the wiki (if not given, will be read from cfg)
-    @param itemname: the name of the page
-    @param attachname: the filename of the attachment
-    @param content: content data as unicode object (e.g. for page content or
-                    parser section content)
-    """
-    secret = secret or 'nobodyexpectedsuchasecret'
-    if content:
-        hmac_data = content
-    elif itemname is not None and attachname is not None:
-        wikiname = wikiname or request.cfg.interwikiname or request.cfg.siteid
-        fuid = filesys.fuid(AttachFile.getFilename(request, itemname, attachname))
-        hmac_data = u''.join([wikiname, itemname, attachname, repr(fuid)])
-    else:
-        raise AssertionError('cache_key called with unsupported parameters')
-
-    hmac_data = hmac_data.encode('utf-8')
-    key = hmac.new(secret, hmac_data, sha).hexdigest()
-    return key
-
-
-def put_cache(request, key, data,
-              filename=None,
-              content_type=None,
-              content_disposition=None,
-              content_length=None,
-              last_modified=None,
-              bufsize=8192):
-    """
-    Cache an object to send with sendcached action later.
-
-    @param request: the request object
-    @param key: non-guessable key into sendcached cache (str)
-    @param data: content data (str or open file-like obj)
-    @param filename: filename for content-disposition header and for autodetecting
-                     content_type (unicode, default: None)
-    @param content_disposition: type for content-disposition header (str, default: None)
-    @param content_type: content-type header value (str, default: autodetect from filename)
-    @param last_modified: last modified timestamp (int, default: autodetect)
-    @param content_length: data length for content-length header (int, default: autodetect)
-    @return: URL of cached object
-    """
-    import os.path
-    from MoinMoin.util import timefuncs
-
-    if filename:
-        # make sure we just have a simple filename (without path)
-        filename = os.path.basename(filename)
-
-        if content_type is None:
-            # try autodetect
-            mt, enc = mimetypes.guess_type(filename)
-            if mt:
-                content_type = mt
-
-    if content_type is None:
-        content_type = 'application/octet-stream'
-
-    data_cache = caching.CacheEntry(request, sendcached_arena, key+'.data',
-                                    sendcached_scope, do_locking=do_locking)
-    data_cache_fname = data_cache._filename()
-
-    if hasattr(data, 'read'):
-        import shutil
-        data_cache_file = open(data_cache_fname, 'wb')
-        shutil.copyfileobj(data, data_cache_file)
-        data_cache_file.close()
-    else:
-        data_cache.update(data)
-
-    content_length = content_length or os.path.getsize(data_cache_fname)
-    last_modified = last_modified or os.path.getmtime(data_cache_fname)
-
-    last_modified = timefuncs.formathttpdate(int(last_modified))
-    headers = ['Content-Type: %s' % content_type,
-               'Last-Modified: %s' % last_modified,
-               'Content-Length: %s' % content_length,
-              ]
-    if content_disposition and filename:
-        # TODO: fix the encoding here, plain 8 bit is not allowed according to the RFCs
-        # There is no solution that is compatible to IE except stripping non-ascii chars
-        filename = filename.encode(config.charset)
-
-        headers.append(
-               'Content-Disposition: %s; filename="%s"' % (content_disposition, filename)
-        )
-
-    meta_cache = caching.CacheEntry(request, sendcached_arena, key+'.meta',
-                                    sendcached_scope, do_locking=do_locking, use_pickle=True)
-    meta_cache.update((last_modified, headers))
-
-    return get_url(request, key)
-
-
-def is_cached(request, key, strict=False):
-    """
-    Check if we have already cached an object for this key.
-
-    @param request: the request object
-    @param key: non-guessable key into sendcached cache (str)
-    @param strict: if True, also check the data cache, not only meta (bool, default: False)
-    @return: is object cached? (bool)
-    """
-    if strict:
-        data_cache = caching.CacheEntry(request, sendcached_arena, key+'.data',
-                                        sendcached_scope, do_locking=do_locking)
-        data_cached = data_cache.exists()
-    else:
-        data_cached = True  # we assume data will be there if meta is there
-
-    meta_cache = caching.CacheEntry(request, sendcached_arena, key+'.meta',
-                                    sendcached_scope, do_locking=do_locking, use_pickle=True)
-    meta_cached = meta_cache.exists()
-
-    return meta_cached and data_cached
-
-
-def get_url(request, key):
-    """ get URL for the object cached for key """
-    return "%s/?%s" % (
-        request.getScriptname(),
-        wikiutil.makeQueryString(dict(action=action_name, key=key), want_unicode=False))
-
-
-def get_cache_headers(request, key):
-    """ get last_modified and headers cached for key """
-    meta_cache = caching.CacheEntry(request, sendcached_arena, key+'.meta',
-                                    sendcached_scope, do_locking=do_locking, use_pickle=True)
-    last_modified, headers = meta_cache.content()
-    return last_modified, headers
-
-
-def get_cache_datafile(request, key):
-    """ get an open data file for the data cached for key """
-    data_cache = caching.CacheEntry(request, sendcached_arena, key+'.data',
-                                    sendcached_scope, do_locking=do_locking)
-    data_file = open(data_cache._filename(), 'rb')
-    return data_file
-
-
-def send_cached(request, key):
-    """ send a complete http response with headers/data cached for key """
-    last_modified, headers = get_cache_headers(request, key)
-    if request.if_modified_since == last_modified:
-        request.emit_http_headers(["Status: 304 Not modified"])
-    else:
-        request.emit_http_headers(headers)
-        request.send_file(get_cache_datafile(request, key))
-
-
-def execute(pagename, request):
-    key = request.form.get('key', [None])[0]
-    send_cached(request, key)
-