From 1315af68a051f83b767d722c9d3270ee3d6512a5 Mon Sep 17 00:00:00 2001 From: Fergal Daly Date: Tue, 9 Aug 2022 02:03:38 -0700 Subject: [PATCH] Adds `unload` to Permissions-Policy. This policy controls whether unload handlers can be set. See https://github.com/w3c/webappsec-permissions-policy/issues/444 Bug: 1324111 Change-Id: Ia7c418e7ca3131f5102fde407011e00048a94182 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3750822 Reviewed-by: Ian Clelland Commit-Queue: Fergal Daly Reviewed-by: Mason Freed Reviewed-by: Andrey Kosyakov Reviewed-by: Dominick Ng Cr-Commit-Position: refs/heads/main@{#1032917} --- .../resources/unload-helper.js | 41 +++++++++++++++++++ ...oad-allowed-by-default.tentative.window.js | 20 +++++++++ ...ad-disallowed-subframe.tentative.window.js | 22 ++++++++++ .../unload-disallowed.tentative.window.js | 22 ++++++++++ 4 files changed, 105 insertions(+) create mode 100644 permissions-policy/experimental-features/resources/unload-helper.js create mode 100644 permissions-policy/experimental-features/unload-allowed-by-default.tentative.window.js create mode 100644 permissions-policy/experimental-features/unload-disallowed-subframe.tentative.window.js create mode 100644 permissions-policy/experimental-features/unload-disallowed.tentative.window.js diff --git a/permissions-policy/experimental-features/resources/unload-helper.js b/permissions-policy/experimental-features/resources/unload-helper.js new file mode 100644 index 00000000000000..9739ead69d6d58 --- /dev/null +++ b/permissions-policy/experimental-features/resources/unload-helper.js @@ -0,0 +1,41 @@ +// Code used by controlling frame of the unload policy tests. + +const MAIN_FRAME = 'main'; +const SUBFRAME = 'sub'; + +async function isUnloadAllowed(remoteContextWrapper) { + return remoteContextWrapper.executeScript(() => { + return document.featurePolicy.allowsFeature('unload'); + }); +} + +// Checks whether a frame runs unload handlers. +// This checks the policy directly and also installs an unload handler and +// navigates the frame checking that the handler ran. +async function assertWindowRunsUnload( + remoteContextWrapper, name, {shouldRunUnload}) { + const maybeNot = shouldRunUnload ? '' : 'not '; + assert_equals( + await isUnloadAllowed(remoteContextWrapper), shouldRunUnload, + `${name}: unload in ${name} should ${maybeNot}be allowed`); + + // Set up recording of whether unload handler ran. + await remoteContextWrapper.executeScript((name) => { + localStorage.setItem(name, 'did not run'); + addEventListener('unload', () => localStorage.setItem(name, 'did run')); + }, [name]); + + // Navigate away and then back. + const second = await remoteContextWrapper.navigateToNew(); + // Navigating back ensures that the unload has completed. + // Also if the navigation is cross-site then we have to return + // to the original origin in order to read the recorded unload. + second.historyBack(); + + // Check that unload handlers ran as expected. + const recordedUnload = await remoteContextWrapper.executeScript( + (name) => localStorage.getItem(name), [name]); + assert_equals( + recordedUnload, `did ${maybeNot}run`, + `${name}: unload should ${maybeNot}have run`); +} diff --git a/permissions-policy/experimental-features/unload-allowed-by-default.tentative.window.js b/permissions-policy/experimental-features/unload-allowed-by-default.tentative.window.js new file mode 100644 index 00000000000000..68ce11befdfc51 --- /dev/null +++ b/permissions-policy/experimental-features/unload-allowed-by-default.tentative.window.js @@ -0,0 +1,20 @@ +// META: title='unload' Policy : allowed by default +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/utils.js +// META: script=/resources/testharness.js +// META: script=/resources/testharnessreport.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=./resources/unload-helper.js + +'use strict'; + +// Check that unload is allowed by policy in main frame and subframe by default. +promise_test(async t => { + const rcHelper = + new RemoteContextHelper({scripts: ['./resources/unload-helper.js']}); + // In the same browsing context group to ensure BFCache is not used. + const main = await rcHelper.addWindow(); + const subframe = await main.addIframe(); + await assertWindowRunsUnload(subframe, 'subframe', {shouldRunUnload: true}); + await assertWindowRunsUnload(main, 'main', {shouldRunUnload: true}); +}); diff --git a/permissions-policy/experimental-features/unload-disallowed-subframe.tentative.window.js b/permissions-policy/experimental-features/unload-disallowed-subframe.tentative.window.js new file mode 100644 index 00000000000000..d7eb3d4d736b4e --- /dev/null +++ b/permissions-policy/experimental-features/unload-disallowed-subframe.tentative.window.js @@ -0,0 +1,22 @@ +// META: title='unload' Policy : allowed in main frame but disallowed in subframe +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/utils.js +// META: script=/resources/testharness.js +// META: script=/resources/testharnessreport.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=./resources/unload-helper.js + +'use strict'; + +// Check that unload is allowed by policy in main but can be disabled in the +// subframe. +promise_test(async t => { + const rcHelper = + new RemoteContextHelper({scripts: ['./resources/unload-helper.js']}); + // In the same browsing context group to ensure BFCache is not used. + const main = await rcHelper.addWindow(); + const subframe = + await main.addIframe({headers: [['Permissions-Policy', 'unload=()']]}); + await assertWindowRunsUnload(subframe, 'subframe', {shouldRunUnload: false}); + await assertWindowRunsUnload(main, 'main', {shouldRunUnload: true}); +}); diff --git a/permissions-policy/experimental-features/unload-disallowed.tentative.window.js b/permissions-policy/experimental-features/unload-disallowed.tentative.window.js new file mode 100644 index 00000000000000..2eb14d4a1e6b63 --- /dev/null +++ b/permissions-policy/experimental-features/unload-disallowed.tentative.window.js @@ -0,0 +1,22 @@ +// META: title='unload' Policy : disallowed when header is () +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/utils.js +// META: script=/resources/testharness.js +// META: script=/resources/testharnessreport.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=./resources/unload-helper.js + +'use strict'; + +// Check that unload can be disabled by policy in main frame and subframe. +promise_test(async t => { + const rcHelper = + new RemoteContextHelper({scripts: ['./resources/unload-helper.js']}); + // In the same browsing context group to ensure BFCache is not used. + const main = await rcHelper.addWindow( + {headers: [['Permissions-Policy', 'unload=()']]}, + ); + const subframe = await main.addIframe(); + await assertWindowRunsUnload(subframe, 'subframe', {shouldRunUnload: false}); + await assertWindowRunsUnload(main, 'main', {shouldRunUnload: false}); +});