blob: c006e09d438cc29d3c6b46821692d5586f6834d2 [file] [log] [blame]
<!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="resources/test-helpers.sub.js"></script>
<script src="/common/get-host-info.sub.js"></script>
<body>
The 3p iframe's postMessage:
<p id="iframe_response">No message received</p>
<script>
// The resolve function for the current pending event listener's promise.
// It is nulled once the promise is resolved.
var message_event_promise_resolve = null;
function messageEventHandler(evt) {
if (message_event_promise_resolve) {
local_resolve = message_event_promise_resolve;
message_event_promise_resolve = null;
local_resolve(evt.data);
}
}
function makeMessagePromise() {
if (message_event_promise_resolve != null) {
// Do not create a new promise until the previous is settled.
return;
}
return new Promise(resolve => {
message_event_promise_resolve = resolve;
});
}
// Loads a url for the frame type and then returns a promise for
// the data that was postMessage'd from the loaded frame.
function loadAndReturnSwData(t, url, frame_type) {
if (frame_type !== 'iframe' && frame_type !== 'window') {
return;
}
const message_promise = makeMessagePromise();
// Create the iframe or window and then return the promise for data.
if ( frame_type === 'iframe' ) {
const frame = with_iframe(url, false);
t.add_cleanup(async () => {
const f = await frame;
f.remove();
});
}
else {
// 'window' case.
const w = window.open(url);
t.add_cleanup(() => w.close());
}
return message_promise;
}
promise_test(async t => {
const script = './resources/partitioned-storage-sw.js'
const scope = './resources/partitioned-'
// Add service worker to this 1P context.
const reg = await service_worker_unregister_and_register(t, script, scope);
t.add_cleanup(() => reg.unregister());
await wait_for_state(t, reg.installing, 'activated');
// Register the message listener.
self.addEventListener('message', messageEventHandler);
t.add_cleanup(() =>{
self.removeEventListener('message', messageEventHandler, false);
});
// Open an iframe that will create a promise within the SW.
// The query param is there to track which request the service worker is
// handling.
const wait_frame_url = new URL(
'./resources/partitioned-waitUntilResolved.fakehtml?From1pFrame',
self.location);
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_url = new URL(
'./resources/partitioned-service-worker-third-party-window.html',
get_host_info().HTTPS_NOTSAMESITE_ORIGIN + self.location.pathname);
// Create the 3p window (which will in turn create the iframe with the SW)
// and await on its data.
const frame_3p_data = await loadAndReturnSwData(t, third_party_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.
const resolve_frame_url = new URL(
'./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 partitioning is working correctly then only the 1p iframe should see
// (and resolve) its SW's promise. Additionally the two frames should see
// different IDs.
assert_true(frame_1p_data.has_pending,
'The 1p iframe saw a pending promise in the service worker.');
assert_false(frame_3p_data.has_pending,
'The 3p iframe saw a pending promise in the service worker.');
assert_not_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 partitioned.');
</script>
</body>