Skip to content

Commit 05df1ad

Browse files
committed
Merge branch 'main' into release/2
2 parents 64f8f5c + b26be37 commit 05df1ad

File tree

9 files changed

+73
-12
lines changed

9 files changed

+73
-12
lines changed

azure-pipelines.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ stages:
4949
- script: python -m pip install -r requirements-dev.txt
5050
displayName: 'CR-QC: Install from local repo'
5151

52+
- script: |
53+
cd testproject/
54+
python manage.py makemigrations --check
55+
displayName: 'CR-QC: Check migrations'
56+
5257
- script: pytest ./testproject/
5358
displayName: 'CR-QC: Run unit tests'
5459

docs/releases.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22
Release Notes
33
=============
44

5+
6+
2.1.1
7+
=====
8+
9+
* Fix Django deprecation warnings.
10+
11+
* Previously, the feature to strip cookies was not triggered if the Vary header
12+
contained something other than "Cookie", e.g. ``Vary: Language, Cookie``. This
13+
change properly inspects and rebuilds the Vary header in such cases.
14+
15+
516
2.1.0
617
=====
718

@@ -24,6 +35,14 @@ Google Analytics, Facebook Pixel, HubSpot, etc.
2435
the 1.x series as needed.
2536

2637

38+
1.2.1
39+
=====
40+
41+
* Previously, the feature to strip cookies was not triggered if the Vary header
42+
contained something other than "Cookie", e.g. ``Vary: Language, Cookie``. This
43+
change properly inspects and rebuilds the Vary header in such cases.
44+
45+
2746
1.2.0
2847
=====
2948

setup.cfg

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,3 @@ DJANGO_SETTINGS_MODULE = testproject.settings
1313
junit_family = xunit2
1414
addopts = --cov wagtailcache --cov-report html --cov-report xml --junitxml junit/test-results.xml
1515
python_files = tests.py test_*.py
16-
filterwarnings =
17-
ignore
18-
default:::wagtailcache.*

testproject/home/tests.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,14 @@ def test_client_tracking_cookies_ignore(self):
342342
self.client.cookies["_dataminer"] = "precious data"
343343
self.get_hit(self.page_cachedpage.get_url())
344344

345+
@override_settings(WAGTAIL_CACHE_IGNORE_COOKIES=True)
346+
def test_vary_header_parse(self):
347+
self.get_miss(reverse("vary_view"))
348+
r = self.get_hit(reverse("vary_view"))
349+
# Cookie should have been stripped from the Vary header while preserving
350+
# case and order of the other items.
351+
self.assertEqual(r["Vary"], "A, B, C")
352+
345353
def test_page_restricted(self):
346354
auth_url = "/_util/authenticate_with_password/%d/%d/" % (
347355
self.view_restriction.id,

testproject/home/views.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,9 @@ def cached_view(request):
1010
@nocache_page
1111
def nocached_view(request):
1212
return HttpResponse("Hello, World!")
13+
14+
15+
def vary_view(request):
16+
r = HttpResponse("Variety is the spice of life.")
17+
r.headers["Vary"] = "A, B, Cookie, C"
18+
return r

testproject/testproject/settings.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,6 @@
102102

103103
USE_I18N = True
104104

105-
USE_L10N = True
106-
107105
USE_TZ = True
108106

109107

testproject/testproject/urls.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
path("django-admin/", admin.site.urls),
1313
path("admin/", include(wagtailadmin_urls)),
1414
path("documents/", include(wagtaildocs_urls)),
15-
path("views/cached-view/", views.cached_view, name="cached_view"),
16-
path("views/nocache-view/", views.nocached_view, name="nocached_view"),
15+
path("views/cached/", views.cached_view, name="cached_view"),
16+
path("views/nocache/", views.nocached_view, name="nocached_view"),
17+
path("views/vary/", views.vary_view, name="vary_view"),
1718
# For anything not caught by a more specific rule above, hand over to
1819
# Wagtail's page serving mechanism. This should be the last pattern in
1920
# the list:

wagtailcache/__init__.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
release = ["2", "1", "0"]
1+
release = ["2", "1", "1"]
22
__version__ = "{0}.{1}.{2}".format(release[0], release[1], release[2])
33
__shortversion__ = "{0}.{1}".format(release[0], release[1])
4-
5-
default_app_config = "wagtailcache.apps.WagtailCacheAppConfig"

wagtailcache/cache.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from django.http.response import HttpResponse
1414
from django.template.response import SimpleTemplateResponse
1515
from django.utils.cache import (
16+
cc_delim_re,
1617
get_cache_key,
1718
get_max_age,
1819
has_vary_header,
@@ -45,6 +46,9 @@ class Status(Enum):
4546

4647

4748
def _patch_header(response: HttpResponse, status: Status) -> None:
49+
"""
50+
Adds our Cache Control status to the response headers.
51+
"""
4852
# Patch cache-control with no-cache if it is not already set.
4953
if status == Status.SKIP and not response.get("Cache-Control", None):
5054
response["Cache-Control"] = CacheControl.NOCACHE.value
@@ -53,6 +57,31 @@ def _patch_header(response: HttpResponse, status: Status) -> None:
5357
response[wagtailcache_settings.WAGTAIL_CACHE_HEADER] = status.value
5458

5559

60+
def _delete_vary_cookie(response: HttpResponse) -> None:
61+
"""
62+
Deletes the ``Vary: Cookie`` header while keeping other items of the
63+
Vary header in tact. Inspired by ``django.utils.cache.patch_vary_headers``.
64+
"""
65+
if not response.has_header("Vary"):
66+
return
67+
# Parse the value of Vary header.
68+
vary_headers = cc_delim_re.split(response["Vary"])
69+
# Build a lowercase-keyed dict to preserve the original case.
70+
vhdict = {}
71+
for item in vary_headers:
72+
vhdict.update({item.lower(): item})
73+
# Delete "Cookie".
74+
if "cookie" in vhdict:
75+
del vhdict["cookie"]
76+
# Delete the header if it's now empty.
77+
if not vhdict:
78+
del response["Vary"]
79+
return
80+
# Else patch the header.
81+
vary_headers = [vhdict[k] for k in vhdict]
82+
response["Vary"] = ", ".join(vary_headers)
83+
84+
5685
def _chop_querystring(r: WSGIRequest) -> WSGIRequest:
5786
"""
5887
Given a request object, remove any of our ignored querystrings from it.
@@ -103,15 +132,15 @@ def _chop_response_vary(r: WSGIRequest, s: HttpResponse) -> HttpResponse:
103132
if (
104133
not s.has_header("Set-Cookie")
105134
and s.has_header("Vary")
106-
and s["Vary"].lower() == "cookie"
135+
and has_vary_header(s, "Cookie")
107136
and not (
108137
settings.CSRF_COOKIE_NAME in s.cookies
109138
or settings.CSRF_COOKIE_NAME in r.COOKIES
110139
or settings.SESSION_COOKIE_NAME in s.cookies
111140
or settings.SESSION_COOKIE_NAME in r.COOKIES
112141
)
113142
):
114-
del s["Vary"]
143+
_delete_vary_cookie(s)
115144
return s
116145

117146

0 commit comments

Comments
 (0)