| <!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> |