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