Skip to content

Commit

Permalink
Add Web-Plaform tests for "Clear-Site-Data: cache" header verifying t…
Browse files Browse the repository at this point in the history
…hat networking cache gets cleared

Differential Revision: https://phabricator.services.mozilla.com/D233525

bugzilla-url: https://bugzilla.mozilla.org/show_bug.cgi?id=1940492
gecko-commit: ded58b208af0a504b5681c1b31545c9604e06a47
gecko-reviewers: bvandersloot
  • Loading branch information
mb authored and moz-wptsync-bot committed Jan 17, 2025
1 parent 58f8456 commit 9183b01
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 0 deletions.
110 changes: 110 additions & 0 deletions clear-site-data/clear-cache.https.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<!DOCTYPE html>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script>

// Here's the set-up for this test:
// Step 1 (main window) Open first window with first url putting some resource
// into the cache and maybe receiving clear-site-data header
// Step 2 (first window) Message first window with uuid
// Step 3 (main window) Open second window with second url
// Step 4 (second window) Message first window with uuid (either cached or non-cached)
// Optional Step 5 (main window) Open third window with third url
// Optional Step 6 (third window) Message first window with uuid (either cached or non-cached)
// Step 7 (main window): Assert first and last uuid not equal due to `clear-site-data: "cache"` header
function test_cache_clear(test, params1, params2, params3) {
let cache_helper = "cache_helper=" + self.crypto.randomUUID() + "&";
let firstUrl = "/clear-site-data/support/clear-site-data-cache.py?" + cache_helper + params1
let secondUrl = "/clear-site-data/support/clear-site-data-cache.py?" + cache_helper + params2;
let thirdUrl = params3 ? "/clear-site-data/support/clear-site-data-cache.py?" + cache_helper + params3 : null;

return new Promise(resolve => {
window.addEventListener("message", test.step_func(e => {
// Result Step 2
let firstUuid = e.data;

window.addEventListener("message", test.step_func(e => {
// Result Step 4
let secondUuid = e.data;

if (thirdUrl === null) {
// Step 7, skipping the optional step 5 and 6
assert_not_equals(firstUuid, secondUuid);
resolve();
} else {
window.addEventListener("message", test.step_func(e => {
// Result Step 6
let thirdUuid = e.data;

// Step 7
assert_not_equals(firstUuid, thirdUuid);
resolve();

}), {once: true});

// Step 5
let third_window = window.open(thirdUrl);
test.add_cleanup(third_window.close);
}

}), {once: true});

// Step 3
let second_window = window.open(secondUrl);
test.add_cleanup(second_window.close);
}), {once: true});

// Step 1
let first_window = window.open(firstUrl);
test.add_cleanup(first_window.close);
// tests are using cookies to differentiate between requests
test.add_cleanup(test_driver.delete_all_cookies)
});
}

promise_test(t => {
return test_cache_clear(t, "response=single_html&cache&clear_first=cache", "response=single_html&cache&clear_first=cache");
}, "clear cache: Document with clear-cache header doesn't get cached");

promise_test(t => {
return test_cache_clear(t, "response=single_html&cache&clear_first=all", "response=single_html&cache&clear_first=all");
}, "clear all: Document with clear-cache header doesn't get cached");

promise_test(t => {
return test_cache_clear(t, "response=html_embed_json&clear=cache", "response=html_embed_json&clear=cache");
}, "clear cache: Fetch on docment with clear-cache header doesn't get cached");

promise_test(t => {
return test_cache_clear(t, "response=html_embed_json&clear=all", "response=html_embed_json&clear=all");
}, "clear all: Fetch on docment with clear-cache header doesn't get cached");

promise_test(t => {
return test_cache_clear(t, "response=html_embed_json", "response=html_embed_json&clear=cache");
}, "clear cache: Previously cached fetch gets cleared");

promise_test(t => {
return test_cache_clear(t, "response=html_embed_json", "response=html_embed_json&clear=all");
}, "clear all: Previously cached fetch gets cleared");

promise_test(t => {
return test_cache_clear(t, "response=html_embed_json", "response=single_html&clear=cache", "response=html_embed_json");
}, "clear cache: Clear fetch on intermediate navigation");

promise_test(t => {
return test_cache_clear(t, "response=html_embed_json", "response=single_html&clear=all", "response=html_embed_json");
}, "clear all: Clear fetch on intermediate navigation");

promise_test(t => {
return test_cache_clear(t, "response=single_html&cache", "response=single_html&clear=cache", "response=single_html&cache");
}, "clear cache: Clear document in intermediate load");

promise_test(t => {
return test_cache_clear(t, "response=single_html&cache", "response=single_html&clear=all", "response=single_html&cache");
}, "clear all: Clear document in intermediate load");

</script>
</body>
</html>
69 changes: 69 additions & 0 deletions clear-site-data/support/clear-site-data-cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""
Loaded in Step 2/4/Optional 6 (/clear-site-data/clear-cache.https.html)
Sending Message for Step 3/5/Optional 7 (/clear-site-data/clear-cache.https.html)
"""
import uuid

def main(request, response):
# type of response:
# - "single_html": Main page html file with a different postMessage uuid on each response
# - "json": Json that always responds with a different uuid in a single-element array
# - "html_embed_json": Main page html that embeds a cachable version of the above json
response_type = request.GET.first(b"response")

cache_helper = request.GET.first(b"cache_helper")

# force enable caching when present or force disable if not
cache = b"cache" in request.GET
clear = None
if b"clear" in request.GET:
clear = request.GET.first(b"clear")
if b"clear_first" in request.GET:
if request.server.stash.take(cache_helper) is None:
clear = request.GET.first(b"clear_first")
request.server.stash.put(cache_helper, ())

headers = []
if response_type == b"json":
headers += [(b"Content-Type", b"application/json")]
else:
headers += [(b"Content-Type", b"text/html")]

if cache:
headers += [(b"cache-control", b"public, max-age=31536000, immutable")]
else:
headers += [(b"cache-control", b"no-store")]

if clear is not None:
if clear == b"all":
headers += [(b"Clear-Site-Data", b'"*"')]
else:
headers += [(b"Clear-Site-Data", b'"' + clear + b'"')]

if response_type == b"single_html":
# send unique UUID. Cache got cleared when uuids don't match.
content = f'''
<script>
window.opener.postMessage("{uuid.uuid4()}" , "*");
</script>
<body>
{request.url}
</body>'''
elif response_type == b"json":
# send unique UUID. helper for below "html_embed_json"
content = f'''["{uuid.uuid4()}"]'''
elif response_type == b"html_embed_json":
url = request.url_parts.path + "?response=json&cache&cache_helper=" + cache_helper.decode()
content = f'''
<script>
fetch("{url}")
.then(response => response.json())
.then(uuid => window.opener.postMessage(uuid[0], "*"));
</script>
<body>
{request.url}<br>
{url}
</body>'''


return 200, headers, content

0 comments on commit 9183b01

Please sign in to comment.