Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/cachecontrol/heuristics.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
| author | shellac |
|---|---|
| date | Sat, 02 May 2020 07:14:21 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:26e78fe6e8c4 |
|---|---|
| 1 import calendar | |
| 2 import time | |
| 3 | |
| 4 from email.utils import formatdate, parsedate, parsedate_tz | |
| 5 | |
| 6 from datetime import datetime, timedelta | |
| 7 | |
| 8 TIME_FMT = "%a, %d %b %Y %H:%M:%S GMT" | |
| 9 | |
| 10 | |
| 11 def expire_after(delta, date=None): | |
| 12 date = date or datetime.now() | |
| 13 return date + delta | |
| 14 | |
| 15 | |
| 16 def datetime_to_header(dt): | |
| 17 return formatdate(calendar.timegm(dt.timetuple())) | |
| 18 | |
| 19 | |
| 20 class BaseHeuristic(object): | |
| 21 | |
| 22 def warning(self, response): | |
| 23 """ | |
| 24 Return a valid 1xx warning header value describing the cache | |
| 25 adjustments. | |
| 26 | |
| 27 The response is provided too allow warnings like 113 | |
| 28 http://tools.ietf.org/html/rfc7234#section-5.5.4 where we need | |
| 29 to explicitly say response is over 24 hours old. | |
| 30 """ | |
| 31 return '110 - "Response is Stale"' | |
| 32 | |
| 33 def update_headers(self, response): | |
| 34 """Update the response headers with any new headers. | |
| 35 | |
| 36 NOTE: This SHOULD always include some Warning header to | |
| 37 signify that the response was cached by the client, not | |
| 38 by way of the provided headers. | |
| 39 """ | |
| 40 return {} | |
| 41 | |
| 42 def apply(self, response): | |
| 43 updated_headers = self.update_headers(response) | |
| 44 | |
| 45 if updated_headers: | |
| 46 response.headers.update(updated_headers) | |
| 47 warning_header_value = self.warning(response) | |
| 48 if warning_header_value is not None: | |
| 49 response.headers.update({'Warning': warning_header_value}) | |
| 50 | |
| 51 return response | |
| 52 | |
| 53 | |
| 54 class OneDayCache(BaseHeuristic): | |
| 55 """ | |
| 56 Cache the response by providing an expires 1 day in the | |
| 57 future. | |
| 58 """ | |
| 59 def update_headers(self, response): | |
| 60 headers = {} | |
| 61 | |
| 62 if 'expires' not in response.headers: | |
| 63 date = parsedate(response.headers['date']) | |
| 64 expires = expire_after(timedelta(days=1), | |
| 65 date=datetime(*date[:6])) | |
| 66 headers['expires'] = datetime_to_header(expires) | |
| 67 headers['cache-control'] = 'public' | |
| 68 return headers | |
| 69 | |
| 70 | |
| 71 class ExpiresAfter(BaseHeuristic): | |
| 72 """ | |
| 73 Cache **all** requests for a defined time period. | |
| 74 """ | |
| 75 | |
| 76 def __init__(self, **kw): | |
| 77 self.delta = timedelta(**kw) | |
| 78 | |
| 79 def update_headers(self, response): | |
| 80 expires = expire_after(self.delta) | |
| 81 return { | |
| 82 'expires': datetime_to_header(expires), | |
| 83 'cache-control': 'public', | |
| 84 } | |
| 85 | |
| 86 def warning(self, response): | |
| 87 tmpl = '110 - Automatically cached for %s. Response might be stale' | |
| 88 return tmpl % self.delta | |
| 89 | |
| 90 | |
| 91 class LastModified(BaseHeuristic): | |
| 92 """ | |
| 93 If there is no Expires header already, fall back on Last-Modified | |
| 94 using the heuristic from | |
| 95 http://tools.ietf.org/html/rfc7234#section-4.2.2 | |
| 96 to calculate a reasonable value. | |
| 97 | |
| 98 Firefox also does something like this per | |
| 99 https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching_FAQ | |
| 100 http://lxr.mozilla.org/mozilla-release/source/netwerk/protocol/http/nsHttpResponseHead.cpp#397 | |
| 101 Unlike mozilla we limit this to 24-hr. | |
| 102 """ | |
| 103 cacheable_by_default_statuses = set([ | |
| 104 200, 203, 204, 206, 300, 301, 404, 405, 410, 414, 501 | |
| 105 ]) | |
| 106 | |
| 107 def update_headers(self, resp): | |
| 108 headers = resp.headers | |
| 109 | |
| 110 if 'expires' in headers: | |
| 111 return {} | |
| 112 | |
| 113 if 'cache-control' in headers and headers['cache-control'] != 'public': | |
| 114 return {} | |
| 115 | |
| 116 if resp.status not in self.cacheable_by_default_statuses: | |
| 117 return {} | |
| 118 | |
| 119 if 'date' not in headers or 'last-modified' not in headers: | |
| 120 return {} | |
| 121 | |
| 122 date = calendar.timegm(parsedate_tz(headers['date'])) | |
| 123 last_modified = parsedate(headers['last-modified']) | |
| 124 if date is None or last_modified is None: | |
| 125 return {} | |
| 126 | |
| 127 now = time.time() | |
| 128 current_age = max(0, now - date) | |
| 129 delta = date - calendar.timegm(last_modified) | |
| 130 freshness_lifetime = max(0, min(delta / 10, 24 * 3600)) | |
| 131 if freshness_lifetime <= current_age: | |
| 132 return {} | |
| 133 | |
| 134 expires = date + freshness_lifetime | |
| 135 return {'expires': time.strftime(TIME_FMT, time.gmtime(expires))} | |
| 136 | |
| 137 def warning(self, resp): | |
| 138 return None |
