Mercurial > moin > 1.9
changeset 3833:712e5938ec59
sendcached action: new function cache_key to calculate hard-to-guess cache keys from either content (parser sections) or wiki/page/file name and some metadata from filesystem (attachments)
author | Thomas Waldmann <tw AT waldmann-edv DOT de> |
---|---|
date | Sat, 12 Jul 2008 15:53:01 +0200 |
parents | 682fd34b9422 |
children | 27ddf6dfa7bd |
files | MoinMoin/action/_tests/test_sendcached.py MoinMoin/action/sendcached.py |
diffstat | 2 files changed, 78 insertions(+), 3 deletions(-) [+] |
line wrap: on
line diff
--- a/MoinMoin/action/_tests/test_sendcached.py Fri Jul 11 16:26:28 2008 +0200 +++ b/MoinMoin/action/_tests/test_sendcached.py Sat Jul 12 15:53:01 2008 +0200 @@ -9,7 +9,7 @@ import os, StringIO from MoinMoin import caching -from MoinMoin.action import sendcached +from MoinMoin.action import AttachFile, sendcached from MoinMoin._tests import become_trusted, create_page, nuke_page @@ -17,6 +17,44 @@ """ testing action sendcached """ pagename = u"AutoCreatedSillyPageToTestAttachments" + def test_cache_key_content(self): + request = self.request + result1 = sendcached.cache_key(request, content='foo', secret='bar') + result2 = sendcached.cache_key(request, content='foo', secret='baz') + assert result1 # not empty + assert result1 != result2 # different for different secret + result3 = sendcached.cache_key(request, content='foofoo', secret='baz') + assert result3 != result2 # different for different content + result4 = sendcached.cache_key(request, content='foo'*1000, secret='baz') + assert len(result4) == len(result3) # same length of key for different input lengths + + def test_cache_key_attachment(self): + request = self.request + pagename = self.pagename + attachname = 'foo.txt' + + become_trusted(request) + create_page(request, pagename, u"Foo!") + + AttachFile.add_attachment(request, pagename, attachname, "Test content1", True) + + result1 = sendcached.cache_key(request, itemname=pagename, attachname=attachname, secret='bar') + result2 = sendcached.cache_key(request, itemname=pagename, attachname=attachname, secret='baz') + assert result1 # not empty + assert result1 != result2 # different for different secret + + # test below does not work, because mtime is often same, inode can be same due to how add_attachment + # works, file size is same, attachment name is same, wikiname/pagename is same. + # In practice, this should rather rarely cause problems: + #AttachFile.add_attachment(request, pagename, attachname, "Test content2", True) + #result3 = sendcached.cache_key(request, itemname=pagename, attachname=attachname, secret='baz') + #assert result3 != result2 # different for different content + + AttachFile.add_attachment(request, pagename, attachname, "Test content33333", True) + result4 = sendcached.cache_key(request, itemname=pagename, attachname=attachname, secret='baz') + assert len(result4) == len(result2) # same length of key for different input lengths + nuke_page(request, pagename) + def test_put_cache_minimal(self): """Test if put_cache() works""" request = self.request
--- a/MoinMoin/action/sendcached.py Fri Jul 11 16:26:28 2008 +0200 +++ b/MoinMoin/action/sendcached.py Sat Jul 12 15:53:01 2008 +0200 @@ -10,6 +10,7 @@ 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 @@ -22,15 +23,19 @@ @license: GNU GPL, see COPYING for details. """ +import hmac, sha + from MoinMoin import log logging = log.getLogger(__name__) -from MoinMoin import config, caching - # 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! @@ -38,6 +43,38 @@ 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,