Skip to content

Commit

Permalink
Improves heuristics and adds testing
Browse files Browse the repository at this point in the history
  • Loading branch information
b-m-f committed Jan 24, 2019
1 parent c162982 commit 8e15a44
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 9 deletions.
36 changes: 27 additions & 9 deletions canonicalwebteam/http/heuristics.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
import calendar
import locale
from datetime import datetime, timedelta

from cachecontrol.heuristics import BaseHeuristic
from datetime import timedelta, datetime
from email.utils import formatdate


def expire_after(delta, date=None):
date = date or datetime.utcnow()
return date + delta


def datetime_to_header(dt):
return formatdate(calendar.timegm(dt.timetuple()))
def datetime_to_HTTP_date(date_and_time):
"""
Returns a HTTP-date as defined in rfc7234 section 5.3
for a datetime object"""
locale.setlocale(locale.LC_ALL, "en_GB.utf8")

return datetime.astimezone(date_and_time).strftime(
"%a, %d %b %Y %H:%M:%S %Z"
)


def cache_control_in_response_headers(headers):
def cache_directives_in_headers(headers):
"""
Checks if CacheControl is set in response headers
Checks if cache controls are set in response headers
"""
cache_control = "cache-control" in headers
pragma = "pragma" in headers and "no-cache" in headers["pragma"]
expires = "expires" in headers

return expires or pragma or cache_control


class ExpiresAfterIfNoCacheControl(BaseHeuristic):
"""
Expand All @@ -31,21 +40,30 @@ def __init__(self, **kw):
self.delta = timedelta(**kw)

def update_headers(self, response):
if cache_directives_in_headers(reponse.headers):
"""
If no caching controls are present, a default expires header will be set
"""
if cache_directives_in_headers(response.headers):
return

expires = expire_after(self.delta)

return {
"expires": datetime_to_header(expires),
"expires": datetime_to_HTTP_date(expires),
"cache-control": "public",
}

def warning(self):
"""
Adds a warning to the response as defined in rfc7234 section 5.5
"""
template = "110 - Automatically cached for %s. Response might be stale"
return template % self.delta

def apply(self, response):
"""
Applies the heuristic to the response
"""
updated_headers = self.update_headers(response)

if updated_headers:
Expand Down
42 changes: 42 additions & 0 deletions tests/test_heuristics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import locale
import unittest
from datetime import datetime, timedelta

from canonicalwebteam.http import heuristics


class TestHeuristics(unittest.TestCase):
def test_custom_heuristic(self):
today = datetime.utcnow()
one_day_delta = timedelta(days=1)
tomorrow = today + one_day_delta

self.assertEqual(
tomorrow, heuristics.expire_after(one_day_delta, today)
)

def test_datetime_to_header_string(self):
locale.setlocale(locale.LC_ALL, "en_GB.utf8")
date_string = "Thu, 01 Dec 1994 16:00:00 GMT"
date = datetime.strptime(date_string, "%a, %d %b %Y %H:%M:%S %Z")

self.assertEqual(date_string, heuristics.datetime_to_HTTP_date(date))

def test_cache_directives_in_headers(self):
headers = {}

self.assertEqual(
heuristics.cache_directives_in_headers(headers), False
)

headers = {"expires": "1"}

self.assertEqual(heuristics.cache_directives_in_headers(headers), True)

headers = {"pragma": "no-cache"}

self.assertEqual(heuristics.cache_directives_in_headers(headers), True)

headers = {"cache-control": "yeah"}

self.assertEqual(heuristics.cache_directives_in_headers(headers), True)

0 comments on commit 8e15a44

Please sign in to comment.