<!DOCTYPE html>
<meta charset="utf-8"/>
<title>Service Worker: Partitioned Service Workers</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
<script src="/common/get-host-info.sub.js"></script>
<script src="./resources/partitioned-utils-with-token.js"></script>
<head>
<!-- The token below was generated via the following command:
tools/origin_trials/generate_token.py https://web-platform.test:8444
DisableThirdPartyStoragePartitioning2 --expire-timestamp=2000000000
Note that this token is only functionally used in the second test:
"Services workers with cross-site ancestors are not partitioned when the deprecation trial is enabled"
The token for the first test, which uses window.open(), can be found in:
./resources/partitioned-service-worker-third-party-window-with-token.html-->
<meta http-equiv="origin-trial" content="A2kO9VXomVHI2qXmDKzOIFbeBynCH0cFHdQsAJV2QjujjYKz5jHlNrcdGvgOrjZbRWHH/VUjmwuLOwBfraaFHg8AAAB2eyJvcmlnaW4iOiAiaHR0cHM6Ly93ZWItcGxhdGZvcm0udGVzdDo4NDQ0IiwgImZlYXR1cmUiOiAiRGlzYWJsZVRoaXJkUGFydHlTdG9yYWdlUGFydGl0aW9uaW5nMiIsICJleHBpcnkiOiAyMDAwMDAwMDAwfQ==">
</head>
<body>
<!-- Debugging text for both test cases -->
The 3p iframe's postMessage:
<p id="iframe_response">No message received</p>
The nested iframe's postMessage:
<p id="nested_iframe_response">No message received</p>
<script>
// NOTE: these tests are based on the external WPTs found at:
// third_party/blink/web_tests/external/wpt/service-workers/service-worker/partitioned.tentative.https.html
// This test changes the assertions to ensure that when the
// deprecation trial is enabled, service workers in third-party contexts
// under the top-level site that registered for the trial are
// unpartitioned.
promise_test(async t => {
const script = '/service-workers/service-worker/resources/partitioned-storage-sw.js'
const scope = '/service-workers/service-worker/resources/partitioned-'
// Add service worker to this 1P context. wait_for_state() and
// service_worker_unregister_and_register() are helper functions
// for creating test ServiceWorkers defined in:
// /service-workers/service-worker/resources/test-helpers.sub.js
const reg = await service_worker_unregister_and_register(t, script, scope);
t.add_cleanup(() => reg.unregister());
await wait_for_state(t, reg.installing, 'activated');
// Registers the message listener with messageEventHandler(), defined in:
// ./resources/partitioned-utils-with-token.js
self.addEventListener('message', messageEventHandler);
// Open an iframe that will create a promise within the SW.
// Defined /service-workers/service-worker/resources/partitioned-storage-sw.js:
// `waitUntilResolved.fakehtml`: URL scope that creates the promise.
// `?From1pFrame`: query param that tracks which request the service worker is
// handling.
const wait_frame_url = new URL(
'/service-workers/service-worker/resources/partitioned-waitUntilResolved.fakehtml?From1pFrame',
self.location);
// Loads a child iframe with wait_frame_url as the content and returns
// a promise for the data messaged from the loaded iframe.
// loadAndReturnSwData() defined in:
// ./resources/partitioned-utils-with-token.js:
const wait_frame_1p_data = await loadAndReturnSwData(t, wait_frame_url,
'iframe');
assert_equals(wait_frame_1p_data.source, 'From1pFrame',
'The data for the 1p frame came from the wrong source');
// Now create a 3p iframe that will try to resolve the SW in a 3p context.
const third_party_iframe_url = new URL(
'/service-workers/service-worker/resources/partitioned-service-worker-third-party-iframe.html',
get_host_info().HTTPS_ORIGIN + self.location.pathname);
// loadAndReturnSwData() creates a HTTPS_NOTSAMESITE_ORIGIN or 3p `window`
// element which embeds an iframe with the ServiceWorker and returns
// a promise of the data messaged from that frame.
const frame_3p_data = await loadAndReturnSwData(t, third_party_iframe_url, 'window');
assert_equals(frame_3p_data.source, 'From3pFrame',
'The data for the 3p frame came from the wrong source');
// Print some debug info to the main frame.
document.getElementById("iframe_response").innerHTML =
"3p iframe's has_pending: " + frame_3p_data.has_pending + " source: " +
frame_3p_data.source + ". ";
// Now do the same for the 1p iframe.
// Defined /service-workers/service-worker/resources/partitioned-storage-sw.js:
// `resolve.fakehtml`: URL scope that resolves the promise.
const resolve_frame_url = new URL(
'/service-workers/service-worker/resources/partitioned-resolve.fakehtml?From1pFrame', self.location);
const frame_1p_data = await loadAndReturnSwData(t, resolve_frame_url,
'iframe');
assert_equals(frame_1p_data.source, 'From1pFrame',
'The data for the 1p frame came from the wrong source');
// Both the 1p frames should have been serviced by the same service worker ID.
// If this isn't the case then that means the SW could have been deactivated
// which invalidates the test.
assert_equals(frame_1p_data.ID, wait_frame_1p_data.ID,
'The 1p frames were serviced by different service workers.');
document.getElementById("iframe_response").innerHTML +=
"1p iframe's has_pending: " + frame_1p_data.has_pending + " source: " +
frame_1p_data.source;
// If the deprecation trial is enabled, then the 3p iframe should see and
// resolve the 1p iframe's promise. The two frames should see
// identical IDs since they are not partitioned.
assert_false(frame_1p_data.has_pending,
'The 1p iframe saw a pending promise in the service worker.');
assert_true(frame_3p_data.has_pending,
'The 3p iframe saw a pending promise in the service worker.');
assert_equals(frame_1p_data.ID, frame_3p_data.ID,
'The frames were serviced by the same service worker thread.');
}, 'Services workers under different top-level sites are not partitioned when the deprecation trial is enabled.');
// Optional Test: Checking for unpartitioned ServiceWorkers in an A->B->A
// (nested-iframes with cross-site ancestor) scenario.
promise_test(async t => {
const script = '/service-workers/service-worker/resources/partitioned-storage-sw.js'
const scope = '/service-workers/service-worker/resources/partitioned-'
// Add service worker to this 1P context. wait_for_state() and
// service_worker_unregister_and_register() are helper functions
// for creating test ServiceWorkers defined in:
// /service-workers/service-worker/resources/test-helpers.sub.js
const reg = await service_worker_unregister_and_register(t, script, scope);
t.add_cleanup(() => reg.unregister());
await wait_for_state(t, reg.installing, 'activated');
// Registers the message listener with messageEventHandler(), defined in:
// ./resources/partitioned-utils-with-token.js
self.addEventListener('message', messageEventHandler);
// Open an iframe that will create a promise within the SW.
// Defined /service-workers/service-worker/resources/partitioned-storage-sw.js:
// `waitUntilResolved.fakehtml`: URL scope that creates the promise.
// `?From1pFrame`: query param that tracks which request the service worker is
// handling.
const wait_frame_url = new URL(
'/service-workers/service-worker/resources/partitioned-waitUntilResolved.fakehtml?From1pFrame',
self.location);
// Load a child iframe with wait_frame_url as the content.
// loadAndReturnSwData() defined in:
// ./resources/partitioned-utils-with-token.js:
const wait_frame_1p_data = await loadAndReturnSwData(t, wait_frame_url,
'iframe');
assert_equals(wait_frame_1p_data.source, 'From1pFrame',
'The data for the 1p frame came from the wrong source');
// Now create a set of nested iframes in the configuration A1->B->A2
// where B is cross-site and A2 is same-site to this top-level
// site (A1). The innermost iframe of the nested iframes (A2) will
// create an additional iframe to finally resolve the ServiceWorker.
const nested_iframe_url = new URL(
'/service-workers/service-worker/resources/partitioned-service-worker-nested-iframe-parent.html',
get_host_info().HTTPS_NOTSAMESITE_ORIGIN + self.location.pathname);
// Create the nested iframes (which will in turn create the iframe
// with the ServiceWorker) and await on receiving its data.
const nested_iframe_data = await loadAndReturnSwData(t, nested_iframe_url, 'iframe');
assert_equals(nested_iframe_data.source, 'FromNestedFrame',
'The data for the nested iframe frame came from the wrong source');
// Print some debug info to the main frame.
document.getElementById("nested_iframe_response").innerHTML =
"Nested iframe's has_pending: " + nested_iframe_data.has_pending + " source: " +
nested_iframe_data.source + ". ";
// Now do the same for the 1p iframe.
// Defined /service-workers/service-worker/resources/partitioned-storage-sw.js:
// `resolve.fakehtml`: URL scope that resolves the promise.
const resolve_frame_url = new URL(
'/service-workers/service-worker/resources/partitioned-resolve.fakehtml?From1pFrame', self.location);
const frame_1p_data = await loadAndReturnSwData(t, resolve_frame_url,
'iframe');
assert_equals(frame_1p_data.source, 'From1pFrame',
'The data for the 1p frame came from the wrong source');
// Both the 1p frames should have been serviced by the same service worker ID.
// If this isn't the case then that means the SW could have been deactivated
// which invalidates the test.
assert_equals(frame_1p_data.ID, wait_frame_1p_data.ID,
'The 1p frames were serviced by different service workers.');
document.getElementById("nested_iframe_response").innerHTML +=
"1p iframe's has_pending: " + frame_1p_data.has_pending + " source: " +
frame_1p_data.source;
// If the deprecation trial is enabled, then the 3p iframe should
// see (and resolve) the 1p frame's SW's promise. Additionally, the
// innermost iframe of the nested iframes (A2 in the configuration
// A1->B->A2) should have an identical service worker ID to the 1p
// (A1) frame since they are not partitioned.
assert_false(frame_1p_data.has_pending,
'The 1p iframe saw a pending promise in the service worker.');
assert_true(nested_iframe_data.has_pending,
'The 3p iframe saw a pending promise in the service worker.');
assert_equals(frame_1p_data.ID, nested_iframe_data.ID,
'The frames were serviced by the same service worker thread.');
}, 'Services workers with cross-site ancestors are not partitioned when the deprecation trial is enabled.');
</script>
</body>