paul@18 | 1 | # -*- coding: iso-8859-1 -*- |
paul@18 | 2 | """ |
paul@18 | 3 | MoinMoin - MoinRemoteSupport library |
paul@18 | 4 | |
paul@52 | 5 | @copyright: 2011, 2012, 2013 by Paul Boddie <paul@boddie.org.uk> |
paul@18 | 6 | @license: GNU GPL (v2 or later), see COPYING.txt for details. |
paul@18 | 7 | """ |
paul@18 | 8 | |
paul@52 | 9 | from ContentTypeSupport import getContentTypeAndEncoding |
paul@18 | 10 | from MoinMoin.action import cache |
paul@18 | 11 | from MoinMoin import caching |
paul@21 | 12 | import urllib2, time |
paul@18 | 13 | |
paul@18 | 14 | def getCachedResource(request, url, arena, scope, max_cache_age): |
paul@18 | 15 | |
paul@18 | 16 | """ |
paul@18 | 17 | Using the given 'request', return the resource data for the given 'url', |
paul@18 | 18 | accessing a cache entry with the given 'arena' and 'scope' where the data |
paul@18 | 19 | has already been downloaded. The 'max_cache_age' indicates the length in |
paul@18 | 20 | seconds that a cache entry remains valid. |
paul@20 | 21 | |
paul@20 | 22 | If the resource cannot be downloaded and cached, None is returned. |
paul@22 | 23 | Otherwise, the form of the data is as follows: |
paul@22 | 24 | |
paul@49 | 25 | url <newline> |
paul@49 | 26 | [ content-type-header ] <newline> |
paul@49 | 27 | [ other-header <newline> ]* |
paul@49 | 28 | <newline> |
paul@49 | 29 | content-body |
paul@18 | 30 | """ |
paul@18 | 31 | |
paul@18 | 32 | # See if the URL is cached. |
paul@18 | 33 | |
paul@18 | 34 | cache_key = cache.key(request, content=url) |
paul@18 | 35 | cache_entry = caching.CacheEntry(request, arena, cache_key, scope=scope) |
paul@18 | 36 | |
paul@18 | 37 | # If no entry exists, or if the entry is older than the specified age, |
paul@18 | 38 | # create one with the response from the URL. |
paul@18 | 39 | |
paul@18 | 40 | now = time.time() |
paul@18 | 41 | mtime = cache_entry.mtime() |
paul@18 | 42 | |
paul@18 | 43 | # NOTE: The URL could be checked and the 'If-Modified-Since' header |
paul@18 | 44 | # NOTE: (see MoinMoin.action.pollsistersites) could be checked. |
paul@18 | 45 | |
paul@18 | 46 | if not cache_entry.exists() or now - mtime >= max_cache_age: |
paul@18 | 47 | |
paul@18 | 48 | # Access the remote data source. |
paul@18 | 49 | |
paul@18 | 50 | cache_entry.open(mode="w") |
paul@18 | 51 | |
paul@18 | 52 | try: |
paul@18 | 53 | f = urllib2.urlopen(url) |
paul@18 | 54 | try: |
paul@18 | 55 | cache_entry.write(url + "\n") |
paul@18 | 56 | cache_entry.write((f.headers.get("content-type") or "") + "\n") |
paul@49 | 57 | for key, value in f.headers.items(): |
paul@49 | 58 | if key.lower() != "content-type": |
paul@49 | 59 | cache_entry.write("%s: %s\n" % (key, value)) |
paul@49 | 60 | cache_entry.write("\n") |
paul@18 | 61 | cache_entry.write(f.read()) |
paul@18 | 62 | finally: |
paul@18 | 63 | cache_entry.close() |
paul@18 | 64 | f.close() |
paul@18 | 65 | |
paul@20 | 66 | # In case of an exception, return None. |
paul@18 | 67 | |
paul@18 | 68 | except IOError: |
paul@18 | 69 | if cache_entry.exists(): |
paul@18 | 70 | cache_entry.remove() |
paul@20 | 71 | return None |
paul@18 | 72 | |
paul@18 | 73 | # Open the cache entry and read it. |
paul@18 | 74 | |
paul@18 | 75 | cache_entry.open() |
paul@18 | 76 | try: |
paul@18 | 77 | return cache_entry.read() |
paul@18 | 78 | finally: |
paul@18 | 79 | cache_entry.close() |
paul@18 | 80 | |
paul@52 | 81 | def getCachedResourceMetadata(f): |
paul@52 | 82 | |
paul@52 | 83 | "Return a metadata dictionary for the given resource file-like object 'f'." |
paul@52 | 84 | |
paul@52 | 85 | url = f.readline() |
paul@52 | 86 | content_type, encoding = getContentTypeAndEncoding(f.readline()) |
paul@52 | 87 | |
paul@52 | 88 | metadata = {} |
paul@52 | 89 | line = f.readline() |
paul@52 | 90 | |
paul@52 | 91 | while line.strip(): |
paul@52 | 92 | key, value = [v.strip() for v in line.split(":", 1)] |
paul@52 | 93 | metadata[key] = value |
paul@52 | 94 | line = f.readline() |
paul@52 | 95 | |
paul@52 | 96 | return url, content_type, encoding, metadata |
paul@52 | 97 | |
paul@18 | 98 | # vim: tabstop=4 expandtab shiftwidth=4 |