Get StorageAccess API features working on SQLite database implementation (195422)
https://bugs.webkit.org/show_bug.cgi?id=195422
<rdar://problem/54213519>

Patch by Kate Cheney <katherine_cheney@apple.com> on 2019-10-11
Reviewed by Brent Fulgham.

Source/WebKit:

This patch migrates the http/tests/storageAccess/ Layout tests to
use the ITP database and uncovered 3 bugs in the process.

1. It was previously blocking cookies to a third party domain which
was not marked as prevalent. Now it ensures that the user is prompted
using the storage acess API regarding that third party domain.

2. It was not requesting storage access if cookies had previously been
blocked. Now it will only return early from
ResourceLoadStatisticsDatabaseStore::requestStorageAccessUnderOpener
if cookie access is allowed, and request storage access otherwise.

3. hasUserGrantedStorageAccessThroughPrompt was returning true even
if the result was not previously granted storage access.

All of these fixes match behavior in
ResourceLoadStatisticsMemoryStore.

* NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp:
(WebKit::ResourceLoadStatisticsDatabaseStore::requestStorageAccess):
(WebKit::ResourceLoadStatisticsDatabaseStore::requestStorageAccessUnderOpener):
(WebKit::ResourceLoadStatisticsDatabaseStore::hasUserGrantedStorageAccessThroughPrompt):

LayoutTests:

This patch migrates tests in http/tests/storageAccess to use the ITP
SQLite Database to ensure the storageAccess API features are working.
Additionally, the Safari UI flow was manually tested for the database
using tlstestwebkit.org (no automated tests exist for this).

It also updates the test expectations for two tests that consistently
timeout on the flakiness dashboard and will be looked into in a
separate radar.

Most storageAccess tests are skipped on ios because of incompatibility
with recognizing user interaction.

* http/tests/storageAccess/deny-storage-access-under-opener-database-expected.txt: Added.
* http/tests/storageAccess/deny-storage-access-under-opener-database.html: Added.
* http/tests/storageAccess/deny-storage-access-under-opener-if-auto-dismiss-database-expected.txt: Added.
* http/tests/storageAccess/deny-storage-access-under-opener-if-auto-dismiss-database.html: Added.
* http/tests/storageAccess/deny-with-prompt-does-not-preserve-gesture-database-expected.txt: Added.
* http/tests/storageAccess/deny-with-prompt-does-not-preserve-gesture-database.html: Added.
* http/tests/storageAccess/deny-without-prompt-preserves-gesture-database-expected.txt: Added.
* http/tests/storageAccess/deny-without-prompt-preserves-gesture-database.html: Added.
* http/tests/storageAccess/grant-storage-access-under-opener-at-popup-user-gesture-database-expected.txt: Added.
* http/tests/storageAccess/grant-storage-access-under-opener-at-popup-user-gesture-database.html: Added.
* http/tests/storageAccess/grant-with-prompt-preserves-gesture-database-expected.txt: Added.
* http/tests/storageAccess/grant-with-prompt-preserves-gesture-database.html: Added.
* http/tests/storageAccess/has-storage-access-crash-database-expected.txt: Added.
* http/tests/storageAccess/has-storage-access-crash-database.html: Added.
* http/tests/storageAccess/has-storage-access-false-by-default-database-expected.txt: Added.
* http/tests/storageAccess/has-storage-access-false-by-default-database.html: Added.
* http/tests/storageAccess/has-storage-access-false-by-default-ephemeral-database-expected.txt: Added.
* http/tests/storageAccess/has-storage-access-false-by-default-ephemeral-database.html: Added.
* http/tests/storageAccess/has-storage-access-from-prevalent-domain-with-user-interaction-database-expected.txt: Added.
* http/tests/storageAccess/has-storage-access-from-prevalent-domain-with-user-interaction-database.html: Added.
* http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-database-expected.txt: Added.
* http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-database.html: Added.
* http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-ephemeral-database-expected.txt: Added.
* http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-ephemeral-database.html: Added.
* http/tests/storageAccess/remove-requesting-iframe-database-expected.txt: Added.
* http/tests/storageAccess/remove-requesting-iframe-database.html: Added.
* http/tests/storageAccess/request-and-grant-access-cross-origin-non-sandboxed-iframe-database-expected.txt: Added.
* http/tests/storageAccess/request-and-grant-access-cross-origin-non-sandboxed-iframe-database.html: Added.
* http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-database-expected.txt: Added.
* http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-database.html: Added.
* http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-and-access-from-right-frame-database-expected.txt: Added.
* http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-and-access-from-right-frame-database.html: Added.
* http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-but-access-from-wrong-frame-database-expected.txt: Added.
* http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-but-access-from-wrong-frame-database.html: Added.
* http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-database-expected.txt: Added.
* http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-database.html: Added.
* http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-without-user-interaction-database-expected.txt: Added.
* http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-without-user-interaction-database.html: Added.
* http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-nested-iframe-database-expected.txt: Added.
* http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-nested-iframe-database.html: Added.
* http/tests/storageAccess/request-and-grant-access-then-detach-should-not-have-access-database-expected.txt: Added.
* http/tests/storageAccess/request-and-grant-access-then-detach-should-not-have-access-database.html: Added.
* http/tests/storageAccess/request-and-grant-access-then-navigate-cross-site-should-not-have-access-database-expected.txt: Added.
* http/tests/storageAccess/request-and-grant-access-then-navigate-cross-site-should-not-have-access-database.html: Added.
* http/tests/storageAccess/request-and-grant-access-then-navigate-same-site-should-have-access-database-expected.txt: Added.
* http/tests/storageAccess/request-and-grant-access-then-navigate-same-site-should-have-access-database.html: Added.
* http/tests/storageAccess/request-storage-access-crash-database-expected.txt: Added.
* http/tests/storageAccess/request-storage-access-crash-database.html: Added.
* http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-with-unique-origin-database-expected.txt: Added.
* http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-with-unique-origin-database.html: Added.
* http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-allow-token-database-expected.txt: Added.
* http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-allow-token-database.html: Added.
* http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-user-gesture-database-expected.txt: Added.
* http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-user-gesture-database.html: Added.
* http/tests/storageAccess/request-storage-access-same-origin-iframe-database-expected.txt: Added.
* http/tests/storageAccess/request-storage-access-same-origin-iframe-database.html: Added.
* http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-database-expected.txt: Added.
* http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-database.html: Added.
* http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-without-allow-token-database-expected.txt: Added.
* http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-without-allow-token-database.html: Added.
* http/tests/storageAccess/request-storage-access-top-frame-database-expected.txt: Added.
* http/tests/storageAccess/request-storage-access-top-frame-database.html: Added.
* platform/ios/TestExpectations:
* platform/mac-wk2/TestExpectations:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@251016 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index f507fd3..ba47bef 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,88 @@
+2019-10-11  Kate Cheney  <katherine_cheney@apple.com>
+
+        Get StorageAccess API features working on SQLite database implementation (195422)
+        https://bugs.webkit.org/show_bug.cgi?id=195422
+        <rdar://problem/54213519>
+
+        Reviewed by Brent Fulgham.
+
+        This patch migrates tests in http/tests/storageAccess to use the ITP
+        SQLite Database to ensure the storageAccess API features are working.
+        Additionally, the Safari UI flow was manually tested for the database
+        using tlstestwebkit.org (no automated tests exist for this).
+
+        It also updates the test expectations for two tests that consistently
+        timeout on the flakiness dashboard and will be looked into in a
+        separate radar.
+
+        Most storageAccess tests are skipped on ios because of incompatibility
+        with recognizing user interaction.
+
+        * http/tests/storageAccess/deny-storage-access-under-opener-database-expected.txt: Added.
+        * http/tests/storageAccess/deny-storage-access-under-opener-database.html: Added.
+        * http/tests/storageAccess/deny-storage-access-under-opener-if-auto-dismiss-database-expected.txt: Added.
+        * http/tests/storageAccess/deny-storage-access-under-opener-if-auto-dismiss-database.html: Added.
+        * http/tests/storageAccess/deny-with-prompt-does-not-preserve-gesture-database-expected.txt: Added.
+        * http/tests/storageAccess/deny-with-prompt-does-not-preserve-gesture-database.html: Added.
+        * http/tests/storageAccess/deny-without-prompt-preserves-gesture-database-expected.txt: Added.
+        * http/tests/storageAccess/deny-without-prompt-preserves-gesture-database.html: Added.
+        * http/tests/storageAccess/grant-storage-access-under-opener-at-popup-user-gesture-database-expected.txt: Added.
+        * http/tests/storageAccess/grant-storage-access-under-opener-at-popup-user-gesture-database.html: Added.
+        * http/tests/storageAccess/grant-with-prompt-preserves-gesture-database-expected.txt: Added.
+        * http/tests/storageAccess/grant-with-prompt-preserves-gesture-database.html: Added.
+        * http/tests/storageAccess/has-storage-access-crash-database-expected.txt: Added.
+        * http/tests/storageAccess/has-storage-access-crash-database.html: Added.
+        * http/tests/storageAccess/has-storage-access-false-by-default-database-expected.txt: Added.
+        * http/tests/storageAccess/has-storage-access-false-by-default-database.html: Added.
+        * http/tests/storageAccess/has-storage-access-false-by-default-ephemeral-database-expected.txt: Added.
+        * http/tests/storageAccess/has-storage-access-false-by-default-ephemeral-database.html: Added.
+        * http/tests/storageAccess/has-storage-access-from-prevalent-domain-with-user-interaction-database-expected.txt: Added.
+        * http/tests/storageAccess/has-storage-access-from-prevalent-domain-with-user-interaction-database.html: Added.
+        * http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-database-expected.txt: Added.
+        * http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-database.html: Added.
+        * http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-ephemeral-database-expected.txt: Added.
+        * http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-ephemeral-database.html: Added.
+        * http/tests/storageAccess/remove-requesting-iframe-database-expected.txt: Added.
+        * http/tests/storageAccess/remove-requesting-iframe-database.html: Added.
+        * http/tests/storageAccess/request-and-grant-access-cross-origin-non-sandboxed-iframe-database-expected.txt: Added.
+        * http/tests/storageAccess/request-and-grant-access-cross-origin-non-sandboxed-iframe-database.html: Added.
+        * http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-database-expected.txt: Added.
+        * http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-database.html: Added.
+        * http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-and-access-from-right-frame-database-expected.txt: Added.
+        * http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-and-access-from-right-frame-database.html: Added.
+        * http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-but-access-from-wrong-frame-database-expected.txt: Added.
+        * http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-but-access-from-wrong-frame-database.html: Added.
+        * http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-database-expected.txt: Added.
+        * http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-database.html: Added.
+        * http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-without-user-interaction-database-expected.txt: Added.
+        * http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-without-user-interaction-database.html: Added.
+        * http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-nested-iframe-database-expected.txt: Added.
+        * http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-nested-iframe-database.html: Added.
+        * http/tests/storageAccess/request-and-grant-access-then-detach-should-not-have-access-database-expected.txt: Added.
+        * http/tests/storageAccess/request-and-grant-access-then-detach-should-not-have-access-database.html: Added.
+        * http/tests/storageAccess/request-and-grant-access-then-navigate-cross-site-should-not-have-access-database-expected.txt: Added.
+        * http/tests/storageAccess/request-and-grant-access-then-navigate-cross-site-should-not-have-access-database.html: Added.
+        * http/tests/storageAccess/request-and-grant-access-then-navigate-same-site-should-have-access-database-expected.txt: Added.
+        * http/tests/storageAccess/request-and-grant-access-then-navigate-same-site-should-have-access-database.html: Added.
+        * http/tests/storageAccess/request-storage-access-crash-database-expected.txt: Added.
+        * http/tests/storageAccess/request-storage-access-crash-database.html: Added.
+        * http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-with-unique-origin-database-expected.txt: Added.
+        * http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-with-unique-origin-database.html: Added.
+        * http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-allow-token-database-expected.txt: Added.
+        * http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-allow-token-database.html: Added.
+        * http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-user-gesture-database-expected.txt: Added.
+        * http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-user-gesture-database.html: Added.
+        * http/tests/storageAccess/request-storage-access-same-origin-iframe-database-expected.txt: Added.
+        * http/tests/storageAccess/request-storage-access-same-origin-iframe-database.html: Added.
+        * http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-database-expected.txt: Added.
+        * http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-database.html: Added.
+        * http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-without-allow-token-database-expected.txt: Added.
+        * http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-without-allow-token-database.html: Added.
+        * http/tests/storageAccess/request-storage-access-top-frame-database-expected.txt: Added.
+        * http/tests/storageAccess/request-storage-access-top-frame-database.html: Added.
+        * platform/ios/TestExpectations:
+        * platform/mac-wk2/TestExpectations:
+
 2019-10-11  Antti Koivisto  <antti@apple.com>
 
         Position::upstream/downstream should not need to call ensureLineBoxes
diff --git a/LayoutTests/http/tests/storageAccess/deny-storage-access-under-opener-database-expected.txt b/LayoutTests/http/tests/storageAccess/deny-storage-access-under-opener-database-expected.txt
new file mode 100644
index 0000000..365fd68
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/deny-storage-access-under-opener-database-expected.txt
@@ -0,0 +1,17 @@
+Tests that a cross-origin window from a prevalent domain without user interaction is denied storage access under its opener.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Cookie created.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
+
+--------
+Frame: '<!--frame1-->'
+--------
+Should not receive first-party cookie.
+Did not receive cookie named 'firstPartyCookie'.
+Client-side document.cookie:
diff --git a/LayoutTests/http/tests/storageAccess/deny-storage-access-under-opener-database.html b/LayoutTests/http/tests/storageAccess/deny-storage-access-under-opener-database.html
new file mode 100644
index 0000000..20992dd
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/deny-storage-access-under-opener-database.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that a cross-origin window from a prevalent domain without user interaction is denied storage access under its opener.");
+        jsTestIsAsync = true;
+        testRunner.setUseITPDatabase(true);
+        window.addEventListener("message", receiveMessage, false);
+
+        function finishTest() {
+            setEnableFeature(false, finishJSTest);
+        }
+
+        function openIframe(url, onLoadHandler) {
+            const element = document.createElement("iframe");
+            element.src = url;
+            if (onLoadHandler) {
+                element.onload = onLoadHandler;
+            }
+            document.body.appendChild(element);
+        }
+
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("PASS") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data);
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+
+            newWin.close();
+            openIframe(thirdPartyBaseUrl + subPathToGetCookies + "&message=Should not receive first-party cookie.", finishTest);
+        }
+
+        const thirdPartyOrigin = "http://localhost:8000";
+        const resourcePath = "/storageAccess/resources";
+        const thirdPartyBaseUrl = thirdPartyOrigin + resourcePath;
+        const firstPartyCookieName = "firstPartyCookie";
+        const subPathToGetCookies = "/get-cookies.php?name1=" + firstPartyCookieName;
+
+        let newWin;
+        setEnableFeature(true, function() {
+            testRunner.setCanOpenWindows();
+
+            testRunner.setStatisticsPrevalentResource(thirdPartyOrigin, true, function() {
+                if (!testRunner.isStatisticsPrevalentResource(thirdPartyOrigin))
+                    testFailed("Host did not get set as prevalent resource.");
+                if (testRunner.isStatisticsHasHadUserInteraction(thirdPartyOrigin))
+                    testFailed("Host logged for user interaction.");
+                testRunner.dumpChildFramesAsText();
+                testRunner.setCloseRemainingWindowsWhenComplete(true);
+
+                testRunner.statisticsUpdateCookieBlocking(function () {
+                    newWin = window.open(thirdPartyOrigin + "/storageAccess/resources/set-cookie-and-report-back.html", "testWindow");
+                });
+            });
+        });
+    </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/deny-storage-access-under-opener-if-auto-dismiss-database-expected.txt b/LayoutTests/http/tests/storageAccess/deny-storage-access-under-opener-if-auto-dismiss-database-expected.txt
new file mode 100644
index 0000000..07d7ea6
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/deny-storage-access-under-opener-if-auto-dismiss-database-expected.txt
@@ -0,0 +1,17 @@
+Tests that a cross-origin window from a prevalent domain with non-recent user interaction doesn't get storage access under its opener if it just loads and auto-dismisses.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Cookie created.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
+
+--------
+Frame: '<!--frame1-->'
+--------
+Should not receive first-party cookie.
+Did not receive cookie named 'firstPartyCookie'.
+Client-side document.cookie:
diff --git a/LayoutTests/http/tests/storageAccess/deny-storage-access-under-opener-if-auto-dismiss-database.html b/LayoutTests/http/tests/storageAccess/deny-storage-access-under-opener-if-auto-dismiss-database.html
new file mode 100644
index 0000000..15625e6
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/deny-storage-access-under-opener-if-auto-dismiss-database.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+</head>
+<body onload="run()">
+<script>
+    description("Tests that a cross-origin window from a prevalent domain with non-recent user interaction doesn't get storage access under its opener if it just loads and auto-dismisses.");
+    jsTestIsAsync = true;
+
+    function finishTest() {
+        setEnableFeature(false, finishJSTest);
+    }
+
+    function openIframe(url, onLoadHandler) {
+        const element = document.createElement("iframe");
+        element.src = url;
+        if (onLoadHandler) {
+            element.onload = onLoadHandler;
+        }
+        document.body.appendChild(element);
+    }
+
+    function receiveMessage(event) {
+        if (event.origin === "http://localhost:8000") {
+            if (event.data.indexOf("PASS") !== -1)
+                testPassed(event.data.replace("PASS ", ""));
+            else
+                testFailed(event.data);
+        } else
+            testFailed("Received a message from an unexpected origin: " + event.origin);
+
+        newWin.close();
+        openIframe(thirdPartyBaseUrl + subPathToGetCookies + "&message=Should not receive first-party cookie.", finishTest);
+    }
+
+    const thirdPartyOrigin = "http://localhost:8000";
+    const resourcePath = "/storageAccess/resources";
+    const thirdPartyBaseUrl = thirdPartyOrigin + resourcePath;
+    const firstPartyCookieName = "firstPartyCookie";
+    const subPathToGetCookies = "/get-cookies.php?name1=" + firstPartyCookieName;
+    var newWin;
+
+    function run() {
+        testRunner.setUseITPDatabase(true);
+        setEnableFeature(true, function() {
+            window.addEventListener("message", receiveMessage, false);
+
+            testRunner.setCanOpenWindows();
+
+            testRunner.setStatisticsPrevalentResource(thirdPartyOrigin, true, function() {
+                if (!testRunner.isStatisticsPrevalentResource(thirdPartyOrigin))
+                    testFailed("Host did not get set as prevalent resource.");
+                testRunner.setStatisticsHasHadUserInteraction(thirdPartyOrigin, true, function() {
+                    if (!testRunner.isStatisticsHasHadUserInteraction(thirdPartyOrigin))
+                        testFailed("Host did not get logged for user interaction.");
+                    testRunner.dumpChildFramesAsText();
+                    testRunner.setCloseRemainingWindowsWhenComplete(true);
+
+                    testRunner.statisticsUpdateCookieBlocking(function () {
+                        newWin = window.open(thirdPartyOrigin + "/storageAccess/resources/set-cookie-and-report-back.html", "testWindow");
+                    });
+                });
+            });
+        });
+    }
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/deny-with-prompt-does-not-preserve-gesture-database-expected.txt b/LayoutTests/http/tests/storageAccess/deny-with-prompt-does-not-preserve-gesture-database-expected.txt
new file mode 100644
index 0000000..7ad2108
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/deny-with-prompt-does-not-preserve-gesture-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that a cross-origin iframe can not open a window if storage access is explicitly denied.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Window was successfully opened with user interaction since the user was never consulted/prompted.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/deny-with-prompt-does-not-preserve-gesture-database.html b/LayoutTests/http/tests/storageAccess/deny-with-prompt-does-not-preserve-gesture-database.html
new file mode 100644
index 0000000..fde0766
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/deny-with-prompt-does-not-preserve-gesture-database.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that a cross-origin iframe can not open a window if storage access is explicitly denied.");
+        jsTestIsAsync = true;
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest + "/temp";
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("PASS ") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data.replace("FAIL ", ""));
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            setEnableFeature(false, finishJSTest);
+        }
+
+        function activateElement(elementId) {
+            var element = document.getElementById(elementId);
+            var centerX = element.offsetLeft + element.offsetWidth / 2;
+            var centerY = element.offsetTop + element.offsetHeight / 2;
+            UIHelper.activateAt(centerX, centerY).then(
+                function () {
+                    if (window.eventSender)
+                        eventSender.keyDown("escape");
+                    else {
+                        testFailed("No eventSender.");
+                        setEnableFeature(false, finishJSTest);
+                    }
+                },
+                function () {
+                    testFailed("Promise rejected.");
+                    setEnableFeature(false, finishJSTest);
+                }
+            );
+        }
+
+        function runTest() {
+            testRunner.setUseITPDatabase(true);
+            setEnableFeature(true, function() {
+                testRunner.setCanOpenWindows(false);
+                testRunner.setPopupBlockingEnabled(true);
+                testRunner.setStatisticsPrevalentResource(statisticsUrl, true, function() {
+                    if (!testRunner.isStatisticsPrevalentResource(statisticsUrl))
+                        testFailed("Host did not get set as prevalent resource.");
+                    testRunner.setStatisticsHasHadUserInteraction(statisticsUrl, true, function() {
+                        if (!testRunner.isStatisticsHasHadUserInteraction(statisticsUrl))
+                            testFailed("Host did not get logged for user interaction.");
+                        testRunner.statisticsUpdateCookieBlocking(function() {
+                            let iframeElement = document.createElement("iframe");
+                            iframeElement.onload = function() {
+                                activateElement("TheIframeThatRequestsStorageAccess");
+                            };
+                            iframeElement.id = "TheIframeThatRequestsStorageAccess";
+                            iframeElement.src = "http://localhost:8000/storageAccess/resources/request-storage-access-iframe-and-pop-window.html#userShouldNotGrantAccess,userShouldBeConsulted,policyShouldNotGrantAccess,isNotSameOriginIframe";
+                            document.body.appendChild(iframeElement);
+                        });
+                    });
+                });
+            });
+        }
+    </script>
+</head>
+<body onload="runTest()">
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/deny-without-prompt-preserves-gesture-database-expected.txt b/LayoutTests/http/tests/storageAccess/deny-without-prompt-preserves-gesture-database-expected.txt
new file mode 100644
index 0000000..44afde3
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/deny-without-prompt-preserves-gesture-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that a cross-origin iframe can open a window if storage access is denied without prompt.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Window was successfully opened with user interaction since the user was never consulted/prompted.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/deny-without-prompt-preserves-gesture-database.html b/LayoutTests/http/tests/storageAccess/deny-without-prompt-preserves-gesture-database.html
new file mode 100644
index 0000000..10c6950
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/deny-without-prompt-preserves-gesture-database.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that a cross-origin iframe can open a window if storage access is denied without prompt.");
+        jsTestIsAsync = true;
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest + "/temp";
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("PASS ") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data.replace("FAIL ", ""));
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            setEnableFeature(false, finishJSTest);
+        }
+
+        function activateElement(elementId) {
+            var element = document.getElementById(elementId);
+            var centerX = element.offsetLeft + element.offsetWidth / 2;
+            var centerY = element.offsetTop + element.offsetHeight / 2;
+            UIHelper.activateAt(centerX, centerY).then(
+                function () {
+                    if (window.eventSender)
+                        eventSender.keyDown("escape");
+                    else {
+                        testFailed("No eventSender.");
+                        setEnableFeature(false, finishJSTest);
+                    }
+                },
+                function () {
+                    testFailed("Promise rejected.");
+                    setEnableFeature(false, finishJSTest);
+                }
+            );
+        }
+
+        function runTest() {
+            testRunner.setUseITPDatabase(true);
+            setEnableFeature(true, function() {
+                testRunner.setCanOpenWindows(false);
+                testRunner.setPopupBlockingEnabled(true);
+                testRunner.setStatisticsPrevalentResource(statisticsUrl, true, function() {
+                    if (!testRunner.isStatisticsPrevalentResource(statisticsUrl))
+                        testFailed("Host did not get set as prevalent resource.");
+                    testRunner.setStatisticsHasHadUserInteraction(statisticsUrl, false, function() {
+                        if (testRunner.isStatisticsHasHadUserInteraction(statisticsUrl))
+                            testFailed("Host did get logged for user interaction.");
+                        testRunner.statisticsUpdateCookieBlocking(function() {
+                            let iframeElement = document.createElement("iframe");
+                            iframeElement.onload = function() {
+                                activateElement("TheIframeThatRequestsStorageAccess");
+                            };
+                            iframeElement.id = "TheIframeThatRequestsStorageAccess";
+                            iframeElement.src = "http://localhost:8000/storageAccess/resources/request-storage-access-iframe-and-pop-window.html#userShouldNotGrantAccess,userShouldNotBeConsulted,policyShouldNotGrantAccess,isNotSameOriginIframe";
+                            document.body.appendChild(iframeElement);
+                        });
+                    });
+                });
+            });
+        }
+    </script>
+</head>
+<body onload="runTest()">
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/grant-storage-access-under-opener-at-popup-user-gesture-database-expected.txt b/LayoutTests/http/tests/storageAccess/grant-storage-access-under-opener-at-popup-user-gesture-database-expected.txt
new file mode 100644
index 0000000..cc62bfc
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/grant-storage-access-under-opener-at-popup-user-gesture-database-expected.txt
@@ -0,0 +1,17 @@
+Tests that a cross-origin window from a prevalent domain with previous user interaction gets storage access under its opener if it gets user interaction.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Cookie created.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
+
+--------
+Frame: '<!--frame1-->'
+--------
+Should receive first-party cookie.
+Received cookie named 'firstPartyCookie'.
+Client-side document.cookie: firstPartyCookie=value
diff --git a/LayoutTests/http/tests/storageAccess/grant-storage-access-under-opener-at-popup-user-gesture-database.html b/LayoutTests/http/tests/storageAccess/grant-storage-access-under-opener-at-popup-user-gesture-database.html
new file mode 100644
index 0000000..43485f5
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/grant-storage-access-under-opener-at-popup-user-gesture-database.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+</head>
+<body onload="run()">
+<script>
+    description("Tests that a cross-origin window from a prevalent domain with previous user interaction gets storage access under its opener if it gets user interaction.");
+    jsTestIsAsync = true;
+
+    function finishTest() {
+        setEnableFeature(false, finishJSTest);
+    }
+
+    function openIframe(url, onLoadHandler) {
+        const element = document.createElement("iframe");
+        element.src = url;
+        if (onLoadHandler) {
+            element.onload = onLoadHandler;
+        }
+        document.body.appendChild(element);
+    }
+
+    function receiveMessage(event) {
+        if (event.origin === "http://localhost:8000") {
+            if (event.data.indexOf("PASS") !== -1)
+                testPassed(event.data.replace("PASS ", ""));
+            else
+                testFailed(event.data);
+        } else
+            testFailed("Received a message from an unexpected origin: " + event.origin);
+
+        newWin.close();
+        openIframe(thirdPartyBaseUrl + subPathToGetCookies + "&message=Should receive first-party cookie.", finishTest);
+    }
+
+    const thirdPartyOrigin = "http://localhost:8000";
+    const resourcePath = "/storageAccess/resources";
+    const thirdPartyBaseUrl = thirdPartyOrigin + resourcePath;
+    const firstPartyCookieName = "firstPartyCookie";
+    const subPathToGetCookies = "/get-cookies.php?name1=" + firstPartyCookieName;
+    var newWin;
+
+    function run() {
+        testRunner.setUseITPDatabase(true);
+        setEnableFeature(true, function() {
+            window.addEventListener("message", receiveMessage, false);
+
+            testRunner.setCanOpenWindows();
+
+            testRunner.setStatisticsPrevalentResource(thirdPartyOrigin, true, function() {
+                if (!testRunner.isStatisticsPrevalentResource(thirdPartyOrigin))
+                    testFailed("Host did not get set as prevalent resource.");
+                testRunner.setStatisticsHasHadUserInteraction(thirdPartyOrigin, true, function() {
+                    if (!testRunner.isStatisticsHasHadUserInteraction(thirdPartyOrigin))
+                        testFailed("Host did not get logged for user interaction.");
+                    testRunner.dumpChildFramesAsText();
+                    testRunner.setCloseRemainingWindowsWhenComplete(true);
+
+                    testRunner.statisticsUpdateCookieBlocking(function () {
+                        newWin = window.open(thirdPartyOrigin + "/storageAccess/resources/produce-user-gesture-set-cookie-and-report-back.html", "testWindow");
+                    });
+                });
+            });
+        });
+    }
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/grant-with-prompt-preserves-gesture-database-expected.txt b/LayoutTests/http/tests/storageAccess/grant-with-prompt-preserves-gesture-database-expected.txt
new file mode 100644
index 0000000..d7ec4cf
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/grant-with-prompt-preserves-gesture-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that cross-origin iframe can display a window if storage access is granted.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Window was successfully opened with user interaction.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/grant-with-prompt-preserves-gesture-database.html b/LayoutTests/http/tests/storageAccess/grant-with-prompt-preserves-gesture-database.html
new file mode 100644
index 0000000..6325186
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/grant-with-prompt-preserves-gesture-database.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that cross-origin iframe can display a window if storage access is granted.");
+        jsTestIsAsync = true;
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest + "/temp";
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("PASS ") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data.replace("FAIL ", ""));
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            setEnableFeature(false, finishJSTest);
+        }
+
+        function activateElement(elementId) {
+            var element = document.getElementById(elementId);
+            var centerX = element.offsetLeft + element.offsetWidth / 2;
+            var centerY = element.offsetTop + element.offsetHeight / 2;
+            UIHelper.activateAt(centerX, centerY).then(
+                function () {
+                    if (window.eventSender)
+                        eventSender.keyDown("escape");
+                    else {
+                        testFailed("No eventSender.");
+                        setEnableFeature(false, finishJSTest);
+                    }
+                },
+                function () {
+                    testFailed("Promise rejected.");
+                    setEnableFeature(false, finishJSTest);
+                }
+            );
+        }
+
+        function runTest() {
+            testRunner.setUseITPDatabase(true);
+            setEnableFeature(true, function() {
+                testRunner.setCanOpenWindows(false);
+                testRunner.setPopupBlockingEnabled(true);
+                testRunner.setStatisticsPrevalentResource(statisticsUrl, true, function() {
+                    if (!testRunner.isStatisticsPrevalentResource(statisticsUrl))
+                        testFailed("Host did not get set as prevalent resource.");
+                    testRunner.setStatisticsHasHadUserInteraction(statisticsUrl, true, function() {
+                        if (!testRunner.isStatisticsHasHadUserInteraction(statisticsUrl))
+                            testFailed("Host did not get logged for user interaction.");
+                        testRunner.statisticsUpdateCookieBlocking(function() {
+                            let iframeElement = document.createElement("iframe");
+                            iframeElement.onload = function() {
+                                activateElement("TheIframeThatRequestsStorageAccess");
+                            };
+                            iframeElement.id = "TheIframeThatRequestsStorageAccess";
+                            iframeElement.src = "http://localhost:8000/storageAccess/resources/request-storage-access-iframe-and-pop-window.html#userShouldGrantAccess,userShouldBeConsulted,policyShouldGrantAccess,isNotSameOriginIframe";
+                            document.body.appendChild(iframeElement);
+                        });
+                    });
+                });
+            });
+        }
+    </script>
+</head>
+<body onload="runTest()">
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/has-storage-access-crash-database-expected.txt b/LayoutTests/http/tests/storageAccess/has-storage-access-crash-database-expected.txt
new file mode 100644
index 0000000..4595baa
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/has-storage-access-crash-database-expected.txt
@@ -0,0 +1,5 @@
+Test that querying storage access API on a detached frame doesn't crash.
+
+[object HTMLDocument]
+SUCCESS: Did not crash.
+
diff --git a/LayoutTests/http/tests/storageAccess/has-storage-access-crash-database.html b/LayoutTests/http/tests/storageAccess/has-storage-access-crash-database.html
new file mode 100644
index 0000000..d0d9e08
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/has-storage-access-crash-database.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script>
+    function debug(str) {
+        var c = document.getElementById("console")
+        c.innerHTML += (str + "<br>")
+    }
+
+    if (window.testRunner) {
+        testRunner.dumpAsText();
+        testRunner.waitUntilDone();
+    }
+
+    function runTest() {
+        testRunner.setUseITPDatabase(true);
+        var testDiv = document.getElementById("test");
+        var testFrame = document.createElement("iframe");
+        testDiv.appendChild(testFrame);
+        var testFrameDocument = testFrame.contentDocument;
+        testFrame.outerHTML = testFrameDocument;
+
+        testFrameDocument.hasStorageAccess();
+
+        debug("SUCCESS: Did not crash.")
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }
+    </script>
+</head>
+<body onload="runTest()">
+    <div id="test">
+        <p>Test that querying storage access API on a detached frame doesn't crash.</p>
+    </div>
+    <pre id="console"></pre>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/has-storage-access-false-by-default-database-expected.txt b/LayoutTests/http/tests/storageAccess/has-storage-access-false-by-default-database-expected.txt
new file mode 100644
index 0000000..289daa8
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/has-storage-access-false-by-default-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that document.hasStorageAccess() returns false for a 3rd-party iframe by default.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS No storage access. document.cookie == , cookies seen server-side == "No cookies"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/has-storage-access-false-by-default-database.html b/LayoutTests/http/tests/storageAccess/has-storage-access-false-by-default-database.html
new file mode 100644
index 0000000..f41cfbb
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/has-storage-access-false-by-default-database.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that document.hasStorageAccess() returns false for a 3rd-party iframe by default.");
+        jsTestIsAsync = true;
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("PASS") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data.replace("FAIL ", ""));
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            setEnableFeature(false, finishJSTest);
+        }
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest + "/temp";
+        function runTest() {
+            testRunner.setUseITPDatabase(true);
+            setEnableFeature(true, function() {
+                let iframeElement = document.createElement("iframe");
+                iframeElement.id = "TheIframeThatRequestsStorageAccess";
+                iframeElement.src = "http://localhost:8000/storageAccess/resources/has-storage-access-iframe.html#policyShouldDenyAccess";
+                document.body.appendChild(iframeElement);
+            });
+        }
+    </script>
+</head>
+<body onload="runTest()">
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/has-storage-access-false-by-default-ephemeral-database-expected.txt b/LayoutTests/http/tests/storageAccess/has-storage-access-false-by-default-ephemeral-database-expected.txt
new file mode 100644
index 0000000..725e814
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/has-storage-access-false-by-default-ephemeral-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that document.hasStorageAccess() returns false for a 3rd-party iframe by default (ephemeral session).
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS No storage access. document.cookie == , cookies seen server-side == "No cookies"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/has-storage-access-false-by-default-ephemeral-database.html b/LayoutTests/http/tests/storageAccess/has-storage-access-false-by-default-ephemeral-database.html
new file mode 100644
index 0000000..65661f1
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/has-storage-access-false-by-default-ephemeral-database.html
@@ -0,0 +1,37 @@
+<!-- webkit-test-runner [ useEphemeralSession=true ] -->
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that document.hasStorageAccess() returns false for a 3rd-party iframe by default (ephemeral session).");
+        jsTestIsAsync = true;
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("PASS") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data.replace("FAIL ", ""));
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            finishJSTest();
+        }
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest + "/temp";
+        function runTest() {
+            testRunner.setUseITPDatabase(true);
+            let iframeElement = document.createElement("iframe");
+            iframeElement.id = "TheIframeThatRequestsStorageAccess";
+            iframeElement.src = "http://localhost:8000/storageAccess/resources/has-storage-access-iframe.html#policyShouldDenyAccess";
+            document.body.appendChild(iframeElement);
+        }
+    </script>
+</head>
+<body onload="runTest()">
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/has-storage-access-from-prevalent-domain-with-user-interaction-database-expected.txt b/LayoutTests/http/tests/storageAccess/has-storage-access-from-prevalent-domain-with-user-interaction-database-expected.txt
new file mode 100644
index 0000000..8398c7bd
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/has-storage-access-from-prevalent-domain-with-user-interaction-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that a cross-origin iframe from a prevalent domain with user interaction does not have storage access.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS No storage access. document.cookie == , cookies seen server-side == "No cookies"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/has-storage-access-from-prevalent-domain-with-user-interaction-database.html b/LayoutTests/http/tests/storageAccess/has-storage-access-from-prevalent-domain-with-user-interaction-database.html
new file mode 100644
index 0000000..c31dd1e
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/has-storage-access-from-prevalent-domain-with-user-interaction-database.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that a cross-origin iframe from a prevalent domain with user interaction does not have storage access.");
+        jsTestIsAsync = true;
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("PASS") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data);
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            setEnableFeature(false, finishJSTest);
+        }
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest + "/temp";
+        function runTest() {
+            testRunner.setUseITPDatabase(true);
+            setEnableFeature(true, function() {
+                testRunner.setStatisticsPrevalentResource(statisticsUrl, true, function() {
+                    if (!testRunner.isStatisticsPrevalentResource(statisticsUrl))
+                        testFailed("Host did not get set as prevalent resource.");
+                    testRunner.setStatisticsHasHadUserInteraction(statisticsUrl, true, function() {
+                        if (!testRunner.isStatisticsHasHadUserInteraction(statisticsUrl))
+                            testFailed("Host did not get logged for user interaction.");
+                        let iframeElement = document.createElement("iframe");
+                        iframeElement.setAttribute("sandbox", "allow-storage-access-by-user-activation allow-scripts allow-same-origin allow-modals");
+                        iframeElement.id = "TheIframeThatRequestsStorageAccess";
+                        iframeElement.src = "http://localhost:8000/storageAccess/resources/has-storage-access-iframe.html#policyShouldNotGrantAccess";
+                        document.body.appendChild(iframeElement);
+                    });
+                });
+
+            });
+        }
+    </script>
+</head>
+<body onload="runTest()">
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-database-expected.txt b/LayoutTests/http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-database-expected.txt
new file mode 100644
index 0000000..ee54049
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that document.hasStorageAccess() returns true for a 3rd-party iframe if the 3rd-party has cookies set.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Has storage access. document.cookie == firstPartyCookie=value, cookies seen server-side == {"firstPartyCookie":"value"}
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-database.html b/LayoutTests/http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-database.html
new file mode 100644
index 0000000..4c86689
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-database.html
@@ -0,0 +1,43 @@
+<!-- webkit-test-runner [ useEphemeralSession=true ] -->
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that document.hasStorageAccess() returns true for a 3rd-party iframe if the 3rd-party has cookies set.");
+        jsTestIsAsync = true;
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("PASS") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data.replace("FAIL ", ""));
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            setEnableFeature(false, finishJSTest);
+        }
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest;
+        function runTest() {
+            if (document.location.hash !== "#firstPartyCookieSet") {
+                setEnableFeature(false, function() {
+                    testRunner.setUseITPDatabase(true);
+                    document.location.href = statisticsUrl + "/storageAccess/resources/set-cookie.php?name=firstPartyCookie&value=value#http://127.0.0.1:8000/storageAccess/has-storage-access-true-if-third-party-has-cookies.html#firstPartyCookieSet";
+                });
+            } else {
+                let iframeElement = document.createElement("iframe");
+                iframeElement.id = "TheIframeThatRequestsStorageAccess";
+                iframeElement.src = "http://localhost:8000/storageAccess/resources/has-storage-access-iframe.html#policyShouldGrantAccess";
+                document.body.appendChild(iframeElement);
+            }
+        }
+    </script>
+</head>
+<body onload="runTest()">
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-ephemeral-database-expected.txt b/LayoutTests/http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-ephemeral-database-expected.txt
new file mode 100644
index 0000000..ee54049
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-ephemeral-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that document.hasStorageAccess() returns true for a 3rd-party iframe if the 3rd-party has cookies set.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Has storage access. document.cookie == firstPartyCookie=value, cookies seen server-side == {"firstPartyCookie":"value"}
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-ephemeral-database.html b/LayoutTests/http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-ephemeral-database.html
new file mode 100644
index 0000000..92fcb79
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-ephemeral-database.html
@@ -0,0 +1,41 @@
+<!-- webkit-test-runner [ useEphemeralSession=true ] -->
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that document.hasStorageAccess() returns true for a 3rd-party iframe if the 3rd-party has cookies set (ephemeral session).");
+        jsTestIsAsync = true;
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("PASS") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data.replace("FAIL ", ""));
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            finishJSTest();
+        }
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest;
+        function runTest() {
+            testRunner.setUseITPDatabase(true);
+            if (document.location.hash !== "#firstPartyCookieSet") {
+                document.location.href = statisticsUrl + "/storageAccess/resources/set-cookie.php?name=firstPartyCookie&value=value#http://127.0.0.1:8000/storageAccess/has-storage-access-true-if-third-party-has-cookies.html#firstPartyCookieSet";
+            } else {
+                let iframeElement = document.createElement("iframe");
+                iframeElement.id = "TheIframeThatRequestsStorageAccess";
+                iframeElement.src = "http://localhost:8000/storageAccess/resources/has-storage-access-iframe.html#policyShouldGrantAccess";
+                document.body.appendChild(iframeElement);
+            }
+        }
+    </script>
+</head>
+<body onload="runTest()">
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/remove-requesting-iframe-database-expected.txt b/LayoutTests/http/tests/storageAccess/remove-requesting-iframe-database-expected.txt
new file mode 100644
index 0000000..70546d2
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/remove-requesting-iframe-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that Storage Access API calls work well for removed frames.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS iframe removed.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/remove-requesting-iframe-database.html b/LayoutTests/http/tests/storageAccess/remove-requesting-iframe-database.html
new file mode 100644
index 0000000..226174b
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/remove-requesting-iframe-database.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+<html>
+<head>
+    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+</head>
+<body onload="runTest()">
+<script>
+    description("Tests that Storage Access API calls work well for removed frames.");
+    jsTestIsAsync = true;
+    testRunner.setUseITPDatabase(true);
+    
+    function finishTest() {
+        setEnableFeature(false, finishJSTest);
+    }
+
+    function receiveMessage() {
+        requestingiframe.remove();
+        testPassed("iframe removed.");
+        setTimeout(finishTest, 0.5);
+    }
+
+    window.addEventListener("message", receiveMessage, false);
+
+    function activateElement(elementId) {
+        var element = document.getElementById(elementId);
+        var centerX = element.offsetLeft + element.offsetWidth / 2;
+        var centerY = element.offsetTop + element.offsetHeight / 2;
+        UIHelper.activateAt(centerX, centerY).then(
+            function () {
+                if (window.eventSender)
+                    eventSender.keyDown("escape");
+                else {
+                    testFailed("No eventSender.");
+                    finishTest();
+                }
+            },
+            function () {
+                testFailed("Promise rejected.");
+                finishTest();
+            }
+        );
+    }
+
+    const iframeID = "requestingiframe";
+    const iframeSource = "http://localhost:8000/storageAccess/resources/request-storage-access-and-immediately-postmessage-iframe.html";
+
+    function runTest() {
+        let iframeElement = document.createElement("iframe");
+        iframeElement.onload = function() {
+            testRunner.statisticsUpdateCookieBlocking(function() {
+                activateElement(iframeID);
+            });
+        };
+        iframeElement.id = iframeID;
+        iframeElement.src = iframeSource;
+        document.body.appendChild(iframeElement);
+    }
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-non-sandboxed-iframe-database-expected.txt b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-non-sandboxed-iframe-database-expected.txt
new file mode 100644
index 0000000..9df537b
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-non-sandboxed-iframe-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that cross-origin iframe storage access is granted if the iframe is not sandboxed and the user accepts.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Storage access was granted. document.cookie == , cookies seen server-side == "No cookies"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-non-sandboxed-iframe-database.html b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-non-sandboxed-iframe-database.html
new file mode 100644
index 0000000..e2e99ba
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-non-sandboxed-iframe-database.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that cross-origin iframe storage access is granted if the iframe is not sandboxed and the user accepts.");
+        jsTestIsAsync = true;
+        testRunner.setUseITPDatabase(true);
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest + "/temp";
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("PASS ") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data);
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            setEnableFeature(false, finishJSTest);
+        }
+
+        function activateElement(elementId) {
+            var element = document.getElementById(elementId);
+            var centerX = element.offsetLeft + element.offsetWidth / 2;
+            var centerY = element.offsetTop + element.offsetHeight / 2;
+            UIHelper.activateAt(centerX, centerY).then(
+                function () {
+                    if (window.eventSender)
+                        eventSender.keyDown("escape");
+                    else {
+                        testFailed("No eventSender.");
+                        setEnableFeature(false, finishJSTest);
+                    }
+                },
+                function () {
+                    testFailed("Promise rejected.");
+                    setEnableFeature(false, finishJSTest);
+                }
+            );
+        }
+
+        function runTest() {
+            setEnableFeature(true, function() {
+                testRunner.setStatisticsPrevalentResource(statisticsUrl, true, function() {
+                    if (!testRunner.isStatisticsPrevalentResource(statisticsUrl))
+                        testFailed("Host did not get set as prevalent resource.");
+                    testRunner.setStatisticsHasHadUserInteraction(statisticsUrl, true, function() {
+                        if (!testRunner.isStatisticsHasHadUserInteraction(statisticsUrl))
+                            testFailed("Host did not get logged for user interaction.");
+                        testRunner.statisticsUpdateCookieBlocking(function() {
+                            activateElement("TheIframeThatRequestsStorageAccess");
+                        });
+                    });
+                });
+            });
+        }
+    </script>
+</head>
+<body>
+    <iframe onload="runTest()" id="TheIframeThatRequestsStorageAccess" src="http://localhost:8000/storageAccess/resources/request-storage-access-iframe.html#userShouldGrantAccess,userShouldBeConsulted,policyShouldGrantAccess,isNotSameOriginIframe"></iframe>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-database-expected.txt b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-database-expected.txt
new file mode 100644
index 0000000..6c75e67
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that cross-origin iframe storage access is granted if the iframe is sandboxed, has the allow token, and the user opts in.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Storage access was granted. document.cookie == , cookies seen server-side == "No cookies"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-database.html b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-database.html
new file mode 100644
index 0000000..2cfe9ab6
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-database.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that cross-origin iframe storage access is granted if the iframe is sandboxed, has the allow token, and the user opts in.");
+        jsTestIsAsync = true;
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("PASS") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data);
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            setEnableFeature(false, finishJSTest);
+        }
+
+        function activateElement(elementId) {
+            var element = document.getElementById(elementId);
+            var centerX = element.offsetLeft + element.offsetWidth / 2;
+            var centerY = element.offsetTop + element.offsetHeight / 2;
+            UIHelper.activateAt(centerX, centerY).then(
+                function () {
+                    if (window.eventSender)
+                        eventSender.keyDown("escape");
+                    else {
+                        testFailed("No eventSender.");
+                        setEnableFeature(false, finishJSTest);
+                    }
+                },
+                function () {
+                    testFailed("Promise rejected.");
+                    setEnableFeature(false, finishJSTest);
+                }
+            );
+        }
+
+        function runTest() {
+            testRunner.setUseITPDatabase(true);
+            setEnableFeature(true, function() {
+                activateElement("TheIframeThatRequestsStorageAccess");
+            });
+        }
+    </script>
+</head>
+<body>
+    <iframe sandbox="allow-storage-access-by-user-activation allow-scripts allow-same-origin allow-modals" onload="runTest()" id="TheIframeThatRequestsStorageAccess" src="http://localhost:8000/storageAccess/resources/request-storage-access-iframe.html#userShouldGrantAccess,userShouldBeConsulted,policyShouldGrantAccess,isNotSameOriginIframe"></iframe>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-and-access-from-right-frame-database-expected.txt b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-and-access-from-right-frame-database-expected.txt
new file mode 100644
index 0000000..0a84e7f
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-and-access-from-right-frame-database-expected.txt
@@ -0,0 +1,50 @@
+Tests that cross-origin iframe storage access is granted if the iframe is sandboxed, has the allow token, the iframe origin is a prevalent resource, the iframe origin has had user interaction, the user opts in, and the frame is the one with access.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Storage access was granted. document.cookie == firstPartyCookie=value, cookies seen server-side == {"firstPartyCookie":"value"}
+Did navigate iframe same-site and will now check that it still has storage access.
+PASS document.cookie == firstPartyCookie=value, cookies seen server-side == {"firstPartyCookie":"value"}
+PASS successfullyParsed is true
+
+TEST COMPLETE
+  
+
+--------
+Frame: '<!--frame1-->'
+--------
+Should receive first-party cookie.
+Received cookie named 'firstPartyCookie'.
+Did not receive cookie named 'partitionedCookie'.
+Client-side document.cookie: firstPartyCookie=value
+
+--------
+Frame: '<!--frame2-->'
+--------
+Should not receive cookies.
+Did not receive cookie named 'firstPartyCookie'.
+Did not receive cookie named 'partitionedCookie'.
+Client-side document.cookie:
+
+--------
+Frame: '<!--frame3-->'
+--------
+
+
+
+--------
+Frame: '<!--frame4-->'
+--------
+Should not receive cookies.
+Did not receive cookie named 'firstPartyCookie'.
+Did not receive cookie named 'partitionedCookie'.
+Client-side document.cookie:
+
+--------
+Frame: '<!--frame5-->'
+--------
+After the top frame navigates the sub frame cross-site and back, the sub frame should no longer have access to cookies.
+Did not receive cookie named 'firstPartyCookie'.
+Did not receive cookie named 'partitionedCookie'.
+Client-side document.cookie:
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-and-access-from-right-frame-database.html b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-and-access-from-right-frame-database.html
new file mode 100644
index 0000000..46985d4
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-and-access-from-right-frame-database.html
@@ -0,0 +1,166 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+</head>
+<body>
+    <script>
+        description("Tests that cross-origin iframe storage access is granted if the iframe is sandboxed, has the allow token, the iframe origin is a prevalent resource, the iframe origin has had user interaction, the user opts in, and the frame is the one with access.");
+        jsTestIsAsync = true;
+        testRunner.setUseITPDatabase(true);
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest + "/temp";
+
+        const partitionHost = "127.0.0.1:8000";
+        const thirdPartyOrigin = "http://localhost:8000";
+        const resourcePath = "/storageAccess/resources";
+        const thirdPartyBaseUrl = thirdPartyOrigin + resourcePath;
+        const firstPartyCookieName = "firstPartyCookie";
+        const subPathToSetFirstPartyCookie = "/set-cookie.php?name=" + firstPartyCookieName + "&value=value";
+        const partitionedCookieName = "partitionedCookie";
+        const subPathToSetPartitionedCookie = "/set-cookie.php?name=" + partitionedCookieName + "&value=value";
+        const returnUrl = "http://" + partitionHost + "/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-and-access-from-right-frame-database.html";
+        const subPathToGetCookies = "/get-cookies.php?name1=" + firstPartyCookieName + "&name2=" + partitionedCookieName;
+
+        function openIframe(url, onLoadHandler) {
+            const element = document.createElement("iframe");
+            element.src = url;
+            if (onLoadHandler) {
+                element.onload = onLoadHandler;
+            }
+            document.body.appendChild(element);
+        }
+
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("PASS") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data);
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            runTest();
+        }
+
+        function activateElement(elementId) {
+            var element = document.getElementById(elementId);
+            var centerX = element.offsetLeft + element.offsetWidth / 2;
+            var centerY = element.offsetTop + element.offsetHeight / 2;
+            UIHelper.activateAt(centerX, centerY).then(
+                function () {
+                    if (window.eventSender)
+                        eventSender.keyDown("escape");
+                    else {
+                        testFailed("No eventSender.");
+                        setEnableFeature(false, finishJSTest);
+                    }
+                },
+                function () {
+                    testFailed("Promise rejected.");
+                    setEnableFeature(false, finishJSTest);
+                }
+            );
+        }
+
+        function runTest() {
+            switch (document.location.hash) {
+                case "#step1":
+                    if (testRunner.isStatisticsPrevalentResource(statisticsUrl))
+                        testFailed("Host prematurely set as prevalent resource.");
+                    // Set first-party cookie for localhost.
+                    document.location.href = thirdPartyBaseUrl + subPathToSetFirstPartyCookie + "#" + returnUrl + "#step2";
+                    break;
+                case "#step2":
+                    document.location.hash = "step3";
+                    // Check that the first-party cookie does get sent for localhost under 127.0.0.1.
+                    openIframe(thirdPartyBaseUrl + subPathToGetCookies + "&message=Should receive first-party cookie.", runTest);
+                    break;
+                case "#step3":
+                    document.location.hash = "step4";
+                    // Set localhost as prevalent with user interaction.
+                    testRunner.setStatisticsHasHadUserInteraction(statisticsUrl, true, function() {
+                        if (!testRunner.isStatisticsHasHadUserInteraction(statisticsUrl))
+                            testFailed("Host did not get logged for user interaction.");
+                        testRunner.setStatisticsPrevalentResource(statisticsUrl, true, function() {
+                            if (!testRunner.isStatisticsPrevalentResource(statisticsUrl))
+                                testFailed("Host did not get set as prevalent resource.");
+                            testRunner.statisticsUpdateCookieBlocking(function() {
+                                // Check that the first-party cookie does not get sent for localhost under 127.0.0.1.
+                                openIframe(thirdPartyBaseUrl + subPathToGetCookies + "&message=Should not receive cookies.", runTest);
+                            });
+                        });
+                    });
+                    break;
+                case "#step4":
+                    document.location.hash = "step5";
+                    // Try to set a cookie for localhost.
+                    openIframe(thirdPartyBaseUrl + subPathToSetPartitionedCookie, runTest);
+                    break;
+                case "#step5":
+                    document.location.hash = "step6";
+                    // Check that no cookie gets sent for localhost under 127.0.0.1.
+                    openIframe(thirdPartyBaseUrl + subPathToGetCookies + "&message=Should not receive cookies.", runTest);
+                    break;
+                case "#step6":
+                    document.location.hash = "step7";
+                    // Create iframe that will request storage access.
+                    let iframeElement = document.createElement("iframe");
+                    iframeElement.setAttribute("sandbox", "allow-storage-access-by-user-activation allow-scripts allow-same-origin allow-modals");
+                    iframeElement.onload = function() {
+                        testRunner.statisticsUpdateCookieBlocking(function() {
+                            activateElement("TheIframeThatRequestsStorageAccess");
+                        });
+                    };
+                    iframeElement.id = "TheIframeThatRequestsStorageAccess";
+                    iframeElement.src = "http://localhost:8000/storageAccess/resources/request-storage-access-iframe.html?bogus#userShouldGrantAccess,userShouldBeConsulted,policyShouldGrantAccess,isNotSameOriginIframe";
+                    document.body.appendChild(iframeElement);
+                    break;
+                case "#step7":
+                    document.location.hash = "step8";
+                    // Navigate the frame same-site.
+                    let existingIframe1 = document.getElementById("TheIframeThatRequestsStorageAccess");
+                    existingIframe1.onload = function () {
+                        debug("Did navigate iframe same-site and will now check that it still has storage access.");
+                        let iframe = document.getElementById("TheIframeThatRequestsStorageAccess");
+                        iframe.contentWindow.postMessage("reportBackCookies", "http://localhost:8000");
+                    };
+                    existingIframe1.src = thirdPartyBaseUrl + subPathToGetCookies;
+                    break;
+                case "#step8":
+                    document.location.hash = "step9";
+                    // Navigate the frame cross-site. This should clear out storage access.
+                    let existingIframe2 = document.getElementById("TheIframeThatRequestsStorageAccess");
+                    existingIframe2.onload = runTest;
+                    existingIframe2.src = "http://" + partitionHost;
+                    break;
+                case "#step9":
+                    document.location.hash = "step10";
+                    // Again open localhost in the existing frame and check that no cookie gets sent for localhost under 127.0.0.1 since it has been navigated cross-site.
+                    let existingIframe3 = document.getElementById("TheIframeThatRequestsStorageAccess");
+                    existingIframe3.onload = runTest;
+                    existingIframe3.src = thirdPartyBaseUrl + subPathToGetCookies + "&message=After the top frame navigates the sub frame cross-site and back, the sub frame should no longer have access to cookies.";
+                    break;
+                case "#step10":
+                    setEnableFeature(false, finishJSTest);
+                    break;
+            }
+        }
+
+        if (document.location.hash === "") {
+            setEnableFeature(true, function() {
+                if (testRunner.isStatisticsPrevalentResource(thirdPartyBaseUrl))
+                    testFailed("Localhost was classified as prevalent resource before the test starts.");
+                testRunner.dumpChildFramesAsText();
+                document.location.hash = "step1";
+            });
+        }
+
+        window.addEventListener("message", receiveMessage, false);
+
+        runTest();
+    </script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-but-access-from-wrong-frame-database-expected.txt b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-but-access-from-wrong-frame-database-expected.txt
new file mode 100644
index 0000000..5b3263e
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-but-access-from-wrong-frame-database-expected.txt
@@ -0,0 +1,53 @@
+Tests that cross-origin iframe storage access is denied if the iframe is sandboxed, has the allow token, the iframe origin is a prevalent resource, the iframe origin has had user interaction, the user opts in, but the frame is not the one with access.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Storage access was granted. document.cookie == firstPartyCookie=value, cookies seen server-side == {"firstPartyCookie":"value"}
+PASS successfullyParsed is true
+
+TEST COMPLETE
+  
+
+--------
+Frame: '<!--frame1-->'
+--------
+Should receive first-party cookie.
+Received cookie named 'firstPartyCookie'.
+Did not receive cookie named 'partitionedCookie'.
+Client-side document.cookie: firstPartyCookie=value
+
+--------
+Frame: '<!--frame2-->'
+--------
+Should not receive cookies.
+Did not receive cookie named 'firstPartyCookie'.
+Did not receive cookie named 'partitionedCookie'.
+Client-side document.cookie:
+
+--------
+Frame: '<!--frame3-->'
+--------
+
+
+
+--------
+Frame: '<!--frame4-->'
+--------
+Should not receive cookies.
+Did not receive cookie named 'firstPartyCookie'.
+Did not receive cookie named 'partitionedCookie'.
+Client-side document.cookie:
+
+--------
+Frame: '<!--frame5-->'
+--------
+
+
+--------
+Frame: '<!--frame6-->'
+--------
+Should not receive cookies.
+Did not receive cookie named 'firstPartyCookie'.
+Did not receive cookie named 'partitionedCookie'.
+Client-side document.cookie:
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-but-access-from-wrong-frame-database.html b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-but-access-from-wrong-frame-database.html
new file mode 100644
index 0000000..c554869
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-but-access-from-wrong-frame-database.html
@@ -0,0 +1,145 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+</head>
+<body>
+    <script>
+        description("Tests that cross-origin iframe storage access is denied if the iframe is sandboxed, has the allow token, the iframe origin is a prevalent resource, the iframe origin has had user interaction, the user opts in, but the frame is not the one with access.");
+        jsTestIsAsync = true;
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest + "/temp";
+
+        const partitionHost = "127.0.0.1:8000";
+        const thirdPartyOrigin = "http://localhost:8000";
+        const resourcePath = "/storageAccess/resources";
+        const thirdPartyBaseUrl = thirdPartyOrigin + resourcePath;
+        const firstPartyCookieName = "firstPartyCookie";
+        const subPathToSetFirstPartyCookie = "/set-cookie.php?name=" + firstPartyCookieName + "&value=value";
+        const partitionedCookieName = "partitionedCookie";
+        const subPathToSetPartitionedCookie = "/set-cookie.php?name=" + partitionedCookieName + "&value=value";
+        const returnUrl = "http://" + partitionHost + "/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-but-access-from-wrong-frame-database.html";
+        const subPathToGetCookies = "/get-cookies.php?name1=" + firstPartyCookieName + "&name2=" + partitionedCookieName;
+
+        function openIframe(url, onLoadHandler) {
+            const element = document.createElement("iframe");
+            element.src = url;
+            if (onLoadHandler) {
+                element.onload = onLoadHandler;
+            }
+            document.body.appendChild(element);
+        }
+
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("PASS") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data);
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            runTest();
+        }
+
+        function activateElement(elementId) {
+            var element = document.getElementById(elementId);
+            var centerX = element.offsetLeft + element.offsetWidth / 2;
+            var centerY = element.offsetTop + element.offsetHeight / 2;
+            UIHelper.activateAt(centerX, centerY).then(
+                function () {
+                    if (window.eventSender)
+                        eventSender.keyDown("escape");
+                    else {
+                        testFailed("No eventSender.");
+                        setEnableFeature(false, finishJSTest);
+                    }
+                },
+                function () {
+                    testFailed("Promise rejected.");
+                    setEnableFeature(false, finishJSTest);
+                }
+            );
+        }
+
+        function runTest() {
+            switch (document.location.hash) {
+                case "#step1":
+                    if (testRunner.isStatisticsPrevalentResource(statisticsUrl))
+                        testFailed("Host prematurely set as prevalent resource.");
+                    // Set first-party cookie for localhost.
+                    document.location.href = thirdPartyBaseUrl + subPathToSetFirstPartyCookie + "#" + returnUrl + "#step2";
+                    break;
+                case "#step2":
+                    document.location.hash = "step3";
+                    // Check that the first-party cookie does get sent for localhost under 127.0.0.1.
+                    openIframe(thirdPartyBaseUrl + subPathToGetCookies + "&message=Should receive first-party cookie.", runTest);
+                    break;
+                case "#step3":
+                    document.location.hash = "step4";
+                    // Set localhost as prevalent.
+                    testRunner.setStatisticsPrevalentResource(statisticsUrl, true, function() {
+                        if (!testRunner.isStatisticsPrevalentResource(statisticsUrl))
+                            testFailed("Host did not get set as prevalent resource.");
+                        testRunner.setStatisticsHasHadUserInteraction(statisticsUrl, true, function() {
+                            if (!testRunner.isStatisticsHasHadUserInteraction(statisticsUrl))
+                                testFailed("Host did not get logged for user interaction.");
+                            testRunner.statisticsUpdateCookieBlocking(function() {
+                                // Check that the first-party cookie does not get sent for localhost under 127.0.0.1.
+                                openIframe(thirdPartyBaseUrl + subPathToGetCookies + "&message=Should not receive cookies.", runTest);
+                            });
+                        });
+                    });
+                    break;
+                case "#step4":
+                    document.location.hash = "step5";
+                    // Try to set cookie for localhost.
+                    openIframe(thirdPartyBaseUrl + subPathToSetPartitionedCookie, runTest);
+                    break;
+                case "#step5":
+                    document.location.hash = "step6";
+                    // Check that no cookie gets sent for localhost under 127.0.0.1.
+                    openIframe(thirdPartyBaseUrl + subPathToGetCookies + "&message=Should not receive cookies.", runTest);
+                    break;
+                case "#step6":
+                    document.location.hash = "step7";
+                    let iframeElement = document.createElement("iframe");
+                    iframeElement.setAttribute("sandbox", "allow-storage-access-by-user-activation allow-scripts allow-same-origin allow-modals");
+                    iframeElement.onload = function() {
+                        testRunner.statisticsUpdateCookieBlocking(function() {
+                            activateElement("TheIframeThatRequestsStorageAccess");
+                        });
+                    };
+                    iframeElement.id = "TheIframeThatRequestsStorageAccess";
+                    iframeElement.src = "http://localhost:8000/storageAccess/resources/request-storage-access-iframe.html#userShouldGrantAccess,userShouldBeConsulted,policyShouldGrantAccess,isNotSameOriginIframe";
+                    document.body.appendChild(iframeElement);
+                    break;
+                case "#step7":
+                    document.location.hash = "step8";
+                    // Check that no cookie gets sent for localhost under 127.0.0.1 since we're opening a new frame.
+                    openIframe(thirdPartyBaseUrl + subPathToGetCookies + "&message=Should not receive cookies.", runTest);
+                    break;
+                case "#step8":
+                    setEnableFeature(false, finishJSTest);
+                    break;
+            }
+        }
+
+        if (document.location.hash === "") {
+            testRunner.setUseITPDatabase(true);
+            setEnableFeature(true, function() {
+                if (testRunner.isStatisticsPrevalentResource(thirdPartyBaseUrl))
+                    testFailed("Localhost was classified as prevalent resource before the test starts.");
+                testRunner.dumpChildFramesAsText();
+                document.location.hash = "step1";
+            });
+        }
+
+        window.addEventListener("message", receiveMessage, false);
+
+        runTest();
+    </script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-database-expected.txt b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-database-expected.txt
new file mode 100644
index 0000000..80f024a
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that cross-origin iframe storage access is granted if the iframe is sandboxed, has the allow token, the iframe origin is a prevalent resource, the iframe origin has had recent user interaction, and the user opts in.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Storage access was granted. document.cookie == , cookies seen server-side == "No cookies"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-database.html b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-database.html
new file mode 100644
index 0000000..4311419
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-database.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that cross-origin iframe storage access is granted if the iframe is sandboxed, has the allow token, the iframe origin is a prevalent resource, the iframe origin has had recent user interaction, and the user opts in.");
+        jsTestIsAsync = true;
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("PASS") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data);
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            setEnableFeature(false, finishJSTest);
+        }
+
+        function activateElement(elementId) {
+            var element = document.getElementById(elementId);
+            var centerX = element.offsetLeft + element.offsetWidth / 2;
+            var centerY = element.offsetTop + element.offsetHeight / 2;
+            UIHelper.activateAt(centerX, centerY).then(
+                function () {
+                    if (window.eventSender)
+                        eventSender.keyDown("escape");
+                    else {
+                        testFailed("No eventSender.");
+                        setEnableFeature(false, finishJSTest);
+                    }
+                },
+                function () {
+                    testFailed("Promise rejected.");
+                    setEnableFeature(false, finishJSTest);
+                }
+            );
+        }
+
+        function runTest() {
+            activateElement("TheIframeThatRequestsStorageAccess");
+        }
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest + "/temp";
+        testRunner.setUseITPDatabase(true);
+        setEnableFeature(true, function() {
+            testRunner.setStatisticsPrevalentResource(statisticsUrl, true, function() {
+                if (!testRunner.isStatisticsPrevalentResource(statisticsUrl))
+                    testFailed("Host did not get set as prevalent resource.");
+                testRunner.setStatisticsHasHadUserInteraction(statisticsUrl, true, function() {
+                    if (!testRunner.isStatisticsHasHadUserInteraction(statisticsUrl))
+                        testFailed("Host did not get logged for user interaction.");
+                    let iframeElement = document.createElement("iframe");
+                    iframeElement.setAttribute("sandbox", "allow-storage-access-by-user-activation allow-scripts allow-same-origin allow-modals");
+                    iframeElement.onload = runTest;
+                    iframeElement.id = "TheIframeThatRequestsStorageAccess";
+                    iframeElement.src = "http://localhost:8000/storageAccess/resources/request-storage-access-iframe.html#userShouldGrantAccess,userShouldBeConsulted,policyShouldGrantAccess,isNotSameOriginIframe";
+                    document.body.appendChild(iframeElement);
+                });
+            });
+        });
+    </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-without-user-interaction-database-expected.txt b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-without-user-interaction-database-expected.txt
new file mode 100644
index 0000000..640f6c8
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-without-user-interaction-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that cross-origin iframe storage access is denied if the iframe is sandboxed, has the allow token, the iframe origin is a prevalent resource, the iframe origin has not had user interaction, and the user opts in.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Storage access was denied. document.cookie == , cookies seen server-side == "No cookies"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-without-user-interaction-database.html b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-without-user-interaction-database.html
new file mode 100644
index 0000000..9dcaa3a
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-without-user-interaction-database.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that cross-origin iframe storage access is denied if the iframe is sandboxed, has the allow token, the iframe origin is a prevalent resource, the iframe origin has not had user interaction, and the user opts in.");
+        jsTestIsAsync = true;
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("PASS") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data);
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            setEnableFeature(false, finishJSTest);
+        }
+
+        function activateElement(elementId) {
+            var element = document.getElementById(elementId);
+            var centerX = element.offsetLeft + element.offsetWidth / 2;
+            var centerY = element.offsetTop + element.offsetHeight / 2;
+            UIHelper.activateAt(centerX, centerY).then(
+                function () {
+                    if (window.eventSender)
+                        eventSender.keyDown("escape");
+                    else {
+                        testFailed("No eventSender.");
+                        setEnableFeature(false, finishJSTest);
+                    }
+                },
+                function () {
+                    testFailed("Promise rejected.");
+                    setEnableFeature(false, finishJSTest);
+                }
+            );
+        }
+
+        function runTest() {
+            activateElement("TheIframeThatRequestsStorageAccess");
+        }
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest + "/temp";
+        testRunner.setUseITPDatabase(true);
+        setEnableFeature(true, function() {
+            testRunner.setStatisticsPrevalentResource(statisticsUrl, true, function() {
+                if (!testRunner.isStatisticsPrevalentResource(statisticsUrl))
+                    testFailed("Host did not get set as prevalent resource.");
+                let iframeElement = document.createElement("iframe");
+                iframeElement.setAttribute("sandbox", "allow-storage-access-by-user-activation allow-scripts allow-same-origin allow-modals");
+                iframeElement.onload = runTest;
+                iframeElement.id = "TheIframeThatRequestsStorageAccess";
+                iframeElement.src = "http://localhost:8000/storageAccess/resources/request-storage-access-iframe.html#userShouldGrantAccess,userShouldBeConsulted,policyShouldNotGrantAccess,isNotSameOriginIframe";
+                document.body.appendChild(iframeElement);
+            });
+        });
+    </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-nested-iframe-database-expected.txt b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-nested-iframe-database-expected.txt
new file mode 100644
index 0000000..3e5de6d
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-nested-iframe-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that cross-origin iframe storage access is denied if the iframe is sandboxed, has the allow token, but is nested.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Storage access was denied. document.cookie == , cookies seen server-side == "No cookies"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-nested-iframe-database.html b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-nested-iframe-database.html
new file mode 100644
index 0000000..a74c3f0
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-nested-iframe-database.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that cross-origin iframe storage access is denied if the iframe is sandboxed, has the allow token, but is nested.");
+        jsTestIsAsync = true;
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest + "/temp";
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("PASS") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data.replace("FAIL ", ""));
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            setEnableFeature(false, finishJSTest);
+        }
+
+        function activateElement(elementId) {
+            var element = document.getElementById(elementId);
+            var centerX = element.offsetLeft + element.offsetWidth / 2;
+            var centerY = element.offsetTop + element.offsetHeight / 2;
+            UIHelper.activateAt(centerX, centerY).then(
+                function () {
+                    if (window.eventSender)
+                        eventSender.keyDown("escape");
+                    else {
+                        testFailed("No eventSender.");
+                        setEnableFeature(false, finishJSTest);
+                    }
+                },
+                function () {
+                    testFailed("Promise rejected.");
+                    setEnableFeature(false, finishJSTest);
+                }
+            );
+        }
+
+        function runTest() {
+            testRunner.setUseITPDatabase(true);
+            setEnableFeature(true, function() {
+                testRunner.setStatisticsPrevalentResource(statisticsUrl, true, function() {
+                    if (!testRunner.isStatisticsPrevalentResource(statisticsUrl))
+                        testFailed("Host did not get set as prevalent resource.");
+                    testRunner.setStatisticsHasHadUserInteraction(statisticsUrl, true, function() {
+                        if (!testRunner.isStatisticsHasHadUserInteraction(statisticsUrl))
+                            testFailed("Host did not get logged for user interaction.");
+                        testRunner.statisticsUpdateCookieBlocking(function() {
+                            let iframeElement = document.createElement("iframe");
+                            iframeElement.setAttribute("sandbox", "allow-storage-access-by-user-activation allow-scripts allow-same-origin allow-modals");
+                            iframeElement.onload = function() {
+                                activateElement("TheIframeThatRequestsStorageAccess");
+                            };
+                            iframeElement.id = "TheIframeThatRequestsStorageAccess";
+                            iframeElement.src = "resources/nesting-iframe.html";
+                            document.body.appendChild(iframeElement);
+
+                        });
+                    });
+                });
+            });
+        }
+    </script>
+</head>
+<body onload="runTest()">
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-then-detach-should-not-have-access-database-expected.txt b/LayoutTests/http/tests/storageAccess/request-and-grant-access-then-detach-should-not-have-access-database-expected.txt
new file mode 100644
index 0000000..9131069
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-then-detach-should-not-have-access-database-expected.txt
@@ -0,0 +1,12 @@
+Tests that a cross-origin iframe from a prevalent domain that is granted storage access and then is detached from the DOM does not have storage access.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Storage access was granted. document.cookie == firstPartyCookie=value, cookies seen server-side == {"firstPartyCookie":"value"}
+PASS There is a storage access entry for localhost.
+PASS There is no storage access entry for localhost after iframe detach.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-then-detach-should-not-have-access-database.html b/LayoutTests/http/tests/storageAccess/request-and-grant-access-then-detach-should-not-have-access-database.html
new file mode 100644
index 0000000..043713e
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-then-detach-should-not-have-access-database.html
@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that a cross-origin iframe from a prevalent domain that is granted storage access and then is detached from the DOM does not have storage access.");
+        jsTestIsAsync = true;
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function finishTest() {
+            setEnableFeature(false, finishJSTest);
+        }
+
+        const iframeID = "TheIframeThatRequestsStorageAccess";
+        function askIfIframeStillHasStorageAccess() {
+            testRunner.getAllStorageAccessEntries(function (arrayOfDomains) {
+                var passed = true;
+                for (var i = 0; i < arrayOfDomains.length; ++i) {
+                    if (arrayOfDomains[i] === "localhost") {
+                        passed = false;
+                        break;
+                    }
+                }
+                if (passed)
+                    testPassed("There is no storage access entry for localhost after iframe detach.");
+                else
+                    testFailed("There is still a storage access entry for localhost after iframe detach.");
+                finishTest();
+            });
+        }
+
+        function detachIframeAndCheckWhetherItStillHasStorageAccess() {
+            testRunner.getAllStorageAccessEntries(function (arrayOfDomains) {
+                var passed = false;
+                for (var i = 0; i < arrayOfDomains.length; ++i) {
+                    if (arrayOfDomains[i] === "localhost") {
+                        passed = true;
+                        break;
+                    }
+                }
+                if (passed)
+                    testPassed("There is a storage access entry for localhost.");
+                else
+                    testFailed("There is no storage access entry for localhost.");
+                var theIframe = document.getElementById(iframeID);
+                theIframe.onload = askIfIframeStillHasStorageAccess;
+                document.getElementsByTagName('body')[0].appendChild(theIframe);
+            });
+        }
+
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("PASS") !== -1) {
+                    testPassed(event.data.replace("PASS ", ""));
+                    detachIframeAndCheckWhetherItStillHasStorageAccess();
+                } else {
+                    testFailed(event.data);
+                    finishTest();
+                }
+            } else {
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+                finishTest();
+            }
+        }
+
+        function activateElement(elementId) {
+            var element = document.getElementById(elementId);
+            var centerX = element.offsetLeft + element.offsetWidth / 2;
+            var centerY = element.offsetTop + element.offsetHeight / 2;
+            UIHelper.activateAt(centerX, centerY).then(
+                function () { },
+                function () {
+                    testFailed("Promise rejected.");
+                    finishTest();
+                }
+            );
+        }
+
+        function runTest() {
+            if (document.location.hash !== "#elementActivated") {
+                document.location.hash = "elementActivated";
+                activateElement(iframeID);
+            }
+        }
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest;
+        testRunner.setUseITPDatabase(true);
+        if (document.location.hash !== "#firstPartyCookieSet" && document.location.hash !== "#elementActivated") {
+            setEnableFeature(true, function() {
+                document.location.href = statisticsUrl + "/storageAccess/resources/set-cookie.php?name=firstPartyCookie&value=value#http://127.0.0.1:8000/storageAccess/request-and-grant-access-then-detach-should-not-have-access.html#firstPartyCookieSet";
+            });
+        } else {
+            testRunner.setStatisticsPrevalentResource(statisticsUrl, true, function() {
+                if (!testRunner.isStatisticsPrevalentResource(statisticsUrl))
+                    testFailed("Host did not get set as prevalent resource.");
+                testRunner.setStatisticsHasHadUserInteraction(statisticsUrl, true, function() {
+                    if (!testRunner.isStatisticsHasHadUserInteraction(statisticsUrl))
+                        testFailed("Host did not get logged for user interaction.");
+                    testRunner.statisticsUpdateCookieBlocking(function() {
+                        let iframeElement = document.createElement("iframe");
+                        iframeElement.setAttribute("sandbox", "allow-storage-access-by-user-activation allow-scripts allow-same-origin allow-modals");
+                        iframeElement.onload = runTest;
+                        iframeElement.id = "TheIframeThatRequestsStorageAccess";
+                        iframeElement.src = "http://localhost:8000/storageAccess/resources/request-storage-access-iframe.html#userShouldGrantAccess,userShouldBeConsulted,policyShouldGrantAccess";
+                        document.body.appendChild(iframeElement);
+                    });
+                });
+            });
+        }
+    </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-then-navigate-cross-site-should-not-have-access-database-expected.txt b/LayoutTests/http/tests/storageAccess/request-and-grant-access-then-navigate-cross-site-should-not-have-access-database-expected.txt
new file mode 100644
index 0000000..890f4d9
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-then-navigate-cross-site-should-not-have-access-database-expected.txt
@@ -0,0 +1,13 @@
+Tests that a cross-origin iframe from a prevalent domain that is granted storage access and then navigates itself cross-site does not have storage access.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS document.cookie == 
+PASS Storage access was granted.
+PASS document.cookie == cookieSetClientSideAfterGrantedStorageAccess=value; firstPartyCookie=value
+PASS No storage access. document.cookie == , cookies seen server-side == "No cookies"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-then-navigate-cross-site-should-not-have-access-database.html b/LayoutTests/http/tests/storageAccess/request-and-grant-access-then-navigate-cross-site-should-not-have-access-database.html
new file mode 100644
index 0000000..961c132
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-then-navigate-cross-site-should-not-have-access-database.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that a cross-origin iframe from a prevalent domain that is granted storage access and then navigates itself cross-site does not have storage access.");
+        jsTestIsAsync = true;
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function finishTest() {
+            setEnableFeature(false, finishJSTest);
+        }
+
+        const expectedPassMessages = 2;
+        var passMessagesReceived = 0;
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("document.cookie") === 0) {
+                    testPassed(event.data);
+                } else if (event.data.indexOf("PASS") !== -1) {
+                    testPassed(event.data.replace("PASS ", ""));
+                    passMessagesReceived++;
+                    if (passMessagesReceived >= expectedPassMessages)
+                        finishTest();
+                } else {
+                    testFailed(event.data);
+                    finishTest();
+                }
+            } else {
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+                finishTest();
+            }
+        }
+
+        function activateElement(elementId) {
+            var element = document.getElementById(elementId);
+            var centerX = element.offsetLeft + element.offsetWidth / 2;
+            var centerY = element.offsetTop + element.offsetHeight / 2;
+            UIHelper.activateAt(centerX, centerY).then(
+                function () {
+                    if (window.eventSender)
+                        eventSender.keyDown("escape");
+                    else {
+                        testFailed("No eventSender.");
+                        finishTest();
+                    }
+                },
+                function () {
+                    testFailed("Promise rejected.");
+                    finishTest();
+                }
+            );
+        }
+
+        function runTest() {
+            activateElement("TheIframeThatRequestsStorageAccess");
+        }
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest;
+        testRunner.setUseITPDatabase(true);
+        if (document.location.hash !== "#firstPartyCookieSet") {
+            setEnableFeature(true, function() {
+                document.location.href = statisticsUrl + "/storageAccess/resources/set-cookie.php?name=firstPartyCookie&value=value#http://127.0.0.1:8000/storageAccess/request-and-grant-access-then-navigate-cross-site-should-not-have-access.html#firstPartyCookieSet";
+            });
+        } else {
+            testRunner.setStatisticsPrevalentResource(statisticsUrl, true, function() {
+                if (!testRunner.isStatisticsPrevalentResource(statisticsUrl))
+                    testFailed("Host did not get set as prevalent resource.");
+                testRunner.setStatisticsHasHadUserInteraction(statisticsUrl, true, function() {
+                    if (!testRunner.isStatisticsHasHadUserInteraction(statisticsUrl))
+                        testFailed("Host did not get logged for user interaction.");
+                    testRunner.statisticsUpdateCookieBlocking(function() {
+                        let iframeElement = document.createElement("iframe");
+                        iframeElement.setAttribute("sandbox", "allow-storage-access-by-user-activation allow-scripts allow-same-origin allow-modals");
+                        iframeElement.onload = runTest;
+                        iframeElement.id = "TheIframeThatRequestsStorageAccess";
+                        iframeElement.src = "http://localhost:8000/storageAccess/resources/self-navigating-frame-after-granted-access.html#userShouldGrantAccess,userShouldBeConsulted,policyShouldGrantAccess,crossSiteNavigation";
+                        document.body.appendChild(iframeElement);
+                    });
+                });
+            });
+        }
+    </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-then-navigate-same-site-should-have-access-database-expected.txt b/LayoutTests/http/tests/storageAccess/request-and-grant-access-then-navigate-same-site-should-have-access-database-expected.txt
new file mode 100644
index 0000000..2745db5
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-then-navigate-same-site-should-have-access-database-expected.txt
@@ -0,0 +1,13 @@
+Tests that a cross-origin iframe from a prevalent domain that is granted storage access and then navigates itself same-site still has storage access.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS document.cookie == 
+PASS Storage access was granted.
+PASS document.cookie == cookieSetClientSideAfterGrantedStorageAccess=value; firstPartyCookie=value
+PASS Has storage access. document.cookie == cookieSetClientSideAfterGrantedStorageAccess=value; firstPartyCookie=value, cookies seen server-side == {"cookieSetClientSideAfterGrantedStorageAccess":"value","firstPartyCookie":"value"}
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/request-and-grant-access-then-navigate-same-site-should-have-access-database.html b/LayoutTests/http/tests/storageAccess/request-and-grant-access-then-navigate-same-site-should-have-access-database.html
new file mode 100644
index 0000000..9cc51e9
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-and-grant-access-then-navigate-same-site-should-have-access-database.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that a cross-origin iframe from a prevalent domain that is granted storage access and then navigates itself same-site still has storage access.");
+        jsTestIsAsync = true;
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function finishTest() {
+            setEnableFeature(false, finishJSTest);
+        }
+
+        const expectedPassMessages = 2;
+        var passMessagesReceived = 0;
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("document.cookie") === 0) {
+                    testPassed(event.data);
+                } else if (event.data.indexOf("PASS") !== -1) {
+                    testPassed(event.data.replace("PASS ", ""));
+                    passMessagesReceived++;
+                    if (passMessagesReceived >= expectedPassMessages)
+                        finishTest();
+                } else {
+                    testFailed(event.data);
+                    finishTest();
+                }
+            } else {
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+                finishTest();
+            }
+        }
+
+        function activateElement(elementId) {
+            var element = document.getElementById(elementId);
+            var centerX = element.offsetLeft + element.offsetWidth / 2;
+            var centerY = element.offsetTop + element.offsetHeight / 2;
+            UIHelper.activateAt(centerX, centerY).then(
+                function () {
+                    if (window.eventSender)
+                        eventSender.keyDown("escape");
+                    else {
+                        testFailed("No eventSender.");
+                        finishTest();
+                    }
+                },
+                function () {
+                    testFailed("Promise rejected.");
+                    finishTest();
+                }
+            );
+        }
+
+        function runTest() {
+            activateElement("TheIframeThatRequestsStorageAccess");
+        }
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest;
+        testRunner.setUseITPDatabase(true);
+        if (document.location.hash !== "#firstPartyCookieSet") {
+            setEnableFeature(true, function() {
+                document.location.href = statisticsUrl + "/storageAccess/resources/set-cookie.php?name=firstPartyCookie&value=value#http://127.0.0.1:8000/storageAccess/request-and-grant-access-then-navigate-same-site-should-have-access.html#firstPartyCookieSet";
+            });
+        } else {
+            testRunner.setStatisticsPrevalentResource(statisticsUrl, true, function() {
+                if (!testRunner.isStatisticsPrevalentResource(statisticsUrl))
+                    testFailed("Host did not get set as prevalent resource.");
+                testRunner.setStatisticsHasHadUserInteraction(statisticsUrl, true, function() {
+                    if (!testRunner.isStatisticsHasHadUserInteraction(statisticsUrl))
+                        testFailed("Host did not get logged for user interaction.");
+                    testRunner.statisticsUpdateCookieBlocking(function() {
+                        let iframeElement = document.createElement("iframe");
+                        iframeElement.setAttribute("sandbox", "allow-storage-access-by-user-activation allow-scripts allow-same-origin allow-modals");
+                        iframeElement.onload = runTest;
+                        iframeElement.id = "TheIframeThatRequestsStorageAccess";
+                        iframeElement.src = "http://localhost:8000/storageAccess/resources/self-navigating-frame-after-granted-access.html#userShouldGrantAccess,userShouldBeConsulted,policyShouldGrantAccess,sameSiteNavigation";
+                        document.body.appendChild(iframeElement);
+                    });
+                });
+            });
+        }
+    </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/request-storage-access-crash-database-expected.txt b/LayoutTests/http/tests/storageAccess/request-storage-access-crash-database-expected.txt
new file mode 100644
index 0000000..b7d9903
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-storage-access-crash-database-expected.txt
@@ -0,0 +1,5 @@
+Test that requesting storage access API on a detached frame doesn't crash.
+
+[object HTMLDocument]
+SUCCESS: Did not crash.
+
diff --git a/LayoutTests/http/tests/storageAccess/request-storage-access-crash-database.html b/LayoutTests/http/tests/storageAccess/request-storage-access-crash-database.html
new file mode 100644
index 0000000..8f703ef
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-storage-access-crash-database.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script>
+    function debug(str) {
+        var c = document.getElementById("console")
+        c.innerHTML += (str + "<br>")
+    }
+
+    if (window.testRunner) {
+        testRunner.dumpAsText();
+        testRunner.waitUntilDone();
+    }
+
+    function runTest() {
+        testRunner.setUseITPDatabase(true);
+        var testDiv = document.getElementById("test");
+        var testFrame = document.createElement("iframe");
+        testDiv.appendChild(testFrame);
+        var testFrameDocument = testFrame.contentDocument;
+        testFrame.outerHTML = testFrameDocument;
+
+        testFrameDocument.requestStorageAccess();
+
+        debug("SUCCESS: Did not crash.")
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }
+    </script>
+</head>
+<body onload="runTest()">
+    <div id="test">
+        <p>Test that requesting storage access API on a detached frame doesn't crash.</p>
+    </div>
+    <pre id="console"></pre>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-with-unique-origin-database-expected.txt b/LayoutTests/http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-with-unique-origin-database-expected.txt
new file mode 100644
index 0000000..4197646
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-with-unique-origin-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that cross-origin iframe storage access is denied if the iframe is sandboxed and has the unique origin because it lacks the allow-same-origin token.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Storage access was denied for origin null.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-with-unique-origin-database.html b/LayoutTests/http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-with-unique-origin-database.html
new file mode 100644
index 0000000..93013a6
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-with-unique-origin-database.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that cross-origin iframe storage access is denied if the iframe is sandboxed and has the unique origin because it lacks the allow-same-origin token.");
+        jsTestIsAsync = true;
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function receiveMessage(event) {
+            if (event.origin === "null") {
+                if (event.data.indexOf("PASS") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data.replace("FAIL ", ""));
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            setEnableFeature(false, finishJSTest);
+        }
+
+        function activateElement(elementId) {
+            var element = document.getElementById(elementId);
+            var centerX = element.offsetLeft + element.offsetWidth / 2;
+            var centerY = element.offsetTop + element.offsetHeight / 2;
+            UIHelper.activateAt(centerX, centerY).then(
+                function () {
+                    if (window.eventSender)
+                        eventSender.keyDown("escape");
+                    else {
+                        testFailed("No eventSender.");
+                        setEnableFeature(false, finishJSTest);
+                    }
+                },
+                function () {
+                    testFailed("Promise rejected.");
+                    setEnableFeature(false, finishJSTest);
+                }
+            );
+        }
+
+        function runTest() {
+            testRunner.setUseITPDatabase(true);
+            setEnableFeature(true, function() {
+                activateElement("TheIframeThatRequestsStorageAccess");
+            });
+        }
+    </script>
+</head>
+<body>
+    <iframe sandbox="allow-storage-access-by-user-activation allow-scripts allow-modals" onload="runTest()" id="TheIframeThatRequestsStorageAccess" src="http://localhost:8000/storageAccess/resources/request-storage-access-iframe.html#userShouldGrantAccess,userShouldNotBeConsulted,policyShouldDenyAccess,isNotSameOriginIframe,originIsNull"></iframe>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-allow-token-database-expected.txt b/LayoutTests/http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-allow-token-database-expected.txt
new file mode 100644
index 0000000..c519c7e
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-allow-token-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that cross-origin iframe storage access is denied if the iframe is sandboxed and doesn't have the allow token.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Storage access was denied. document.cookie == , cookies seen server-side == "No cookies"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-allow-token-database.html b/LayoutTests/http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-allow-token-database.html
new file mode 100644
index 0000000..b9c7fd0
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-allow-token-database.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that cross-origin iframe storage access is denied if the iframe is sandboxed and doesn't have the allow token.");
+        jsTestIsAsync = true;
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest + "/temp";
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("PASS") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data.replace("FAIL ", ""));
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            setEnableFeature(false, finishJSTest);
+        }
+
+        function activateElement(elementId) {
+            var element = document.getElementById(elementId);
+            var centerX = element.offsetLeft + element.offsetWidth / 2;
+            var centerY = element.offsetTop + element.offsetHeight / 2;
+            UIHelper.activateAt(centerX, centerY).then(
+                function () {
+                    if (window.eventSender)
+                        eventSender.keyDown("escape");
+                    else {
+                        testFailed("No eventSender.");
+                        setEnableFeature(false, finishJSTest);
+                    }
+                },
+                function () {
+                    testFailed("Promise rejected.");
+                    setEnableFeature(false, finishJSTest);
+                }
+            );
+        }
+
+        function runTest() {
+            testRunner.setUseITPDatabase(true);
+            setEnableFeature(true, function() {
+                testRunner.setStatisticsPrevalentResource(statisticsUrl, true, function() {
+                    if (!testRunner.isStatisticsPrevalentResource(statisticsUrl))
+                        testFailed("Host did not get set as prevalent resource.");
+                    testRunner.setStatisticsHasHadUserInteraction(statisticsUrl, true, function() {
+                        if (!testRunner.isStatisticsHasHadUserInteraction(statisticsUrl))
+                            testFailed("Host did not get logged for user interaction.");
+                        testRunner.statisticsUpdateCookieBlocking(function() {
+                            let iframeElement = document.createElement("iframe");
+                            iframeElement.setAttribute("sandbox", "allow-scripts allow-same-origin allow-modals");
+                            iframeElement.onload = function() {
+                                activateElement("TheIframeThatRequestsStorageAccess");
+                            };
+                            iframeElement.id = "TheIframeThatRequestsStorageAccess";
+                            iframeElement.src = "http://localhost:8000/storageAccess/resources/request-storage-access-iframe.html#userShouldGrantAccess,userShouldNotBeConsulted,policyShouldDenyAccess,isNotSameOriginIframe";
+                            document.body.appendChild(iframeElement);
+                        });
+                    });
+                });
+            });
+        }
+    </script>
+</head>
+<body onload="runTest()">
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-user-gesture-database-expected.txt b/LayoutTests/http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-user-gesture-database-expected.txt
new file mode 100644
index 0000000..36c524a
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-user-gesture-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that cross-origin iframe storage access is denied if the iframe is sandboxed, has the allow token, but calls the API without a user gesture being processed.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Storage access was denied.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-user-gesture-database.html b/LayoutTests/http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-user-gesture-database.html
new file mode 100644
index 0000000..3c30fe2
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-user-gesture-database.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that cross-origin iframe storage access is denied if the iframe is sandboxed, has the allow token, but calls the API without a user gesture being processed.");
+        jsTestIsAsync = true;
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest + "/temp";
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function receiveMessage(event) {
+            if (event.origin === "http://localhost:8000") {
+                if (event.data.indexOf("PASS") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data.replace("FAIL ", ""));
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            setEnableFeature(false, finishJSTest);
+        }
+
+        function runTest() {
+            testRunner.setUseITPDatabase(true);
+            setEnableFeature(true, function() {
+                testRunner.setStatisticsPrevalentResource(statisticsUrl, true, function() {
+                    if (!testRunner.isStatisticsPrevalentResource(statisticsUrl))
+                        testFailed("Host did not get set as prevalent resource.");
+                    testRunner.setStatisticsHasHadUserInteraction(statisticsUrl, true, function() {
+                        if (!testRunner.isStatisticsHasHadUserInteraction(statisticsUrl))
+                            testFailed("Host did not get logged for user interaction.");
+                        testRunner.statisticsUpdateCookieBlocking(function() {
+                            let iframeElement = document.createElement("iframe");
+                            iframeElement.setAttribute("sandbox", "allow-storage-access-by-user-activation allow-scripts allow-same-origin allow-modals");
+                            iframeElement.id = "TheIframeThatRequestsStorageAccess";
+                            iframeElement.src = "http://localhost:8000/storageAccess/resources/request-storage-access-without-user-gesture-iframe.html#userShouldGrantAccess,userShouldNotBeConsulted,policyShouldNotGrantAccess,isNotSameOriginIframe";
+                            document.body.appendChild(iframeElement);
+                        });
+                    });
+                });
+            });
+        }
+    </script>
+</head>
+<body onload="runTest()">
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/request-storage-access-same-origin-iframe-database-expected.txt b/LayoutTests/http/tests/storageAccess/request-storage-access-same-origin-iframe-database-expected.txt
new file mode 100644
index 0000000..de4da86
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-storage-access-same-origin-iframe-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that same-origin iframe storage access is granted if the iframe is not sandboxed.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Storage access was granted. document.cookie == , cookies seen server-side == "No cookies"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/request-storage-access-same-origin-iframe-database.html b/LayoutTests/http/tests/storageAccess/request-storage-access-same-origin-iframe-database.html
new file mode 100644
index 0000000..5880b5c
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-storage-access-same-origin-iframe-database.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that same-origin iframe storage access is granted if the iframe is not sandboxed.");
+        jsTestIsAsync = true;
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function receiveMessage(event) {
+            if (event.origin === "http://127.0.0.1:8000") {
+                if (event.data.indexOf("PASS") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data.replace("FAIL ", ""));
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            setEnableFeature(false, finishJSTest);
+        }
+
+        function activateElement(elementId) {
+            var element = document.getElementById(elementId);
+            var centerX = element.offsetLeft + element.offsetWidth / 2;
+            var centerY = element.offsetTop + element.offsetHeight / 2;
+            UIHelper.activateAt(centerX, centerY).then(
+                function () {
+                    if (window.eventSender)
+                        eventSender.keyDown("escape");
+                    else {
+                        testFailed("No eventSender.");
+                        setEnableFeature(false, finishJSTest);
+                    }
+                },
+                function () {
+                    testFailed("Promise rejected.");
+                    setEnableFeature(false, finishJSTest);
+                }
+            );
+        }
+
+        function runTest() {
+            testRunner.setUseITPDatabase(true);
+            setEnableFeature(true, function() {
+                activateElement("TheIframeThatRequestsStorageAccess");
+            });
+        }
+    </script>
+</head>
+<body>
+    <iframe onload="runTest()" id="TheIframeThatRequestsStorageAccess" src="http://127.0.0.1:8000/storageAccess/resources/request-storage-access-iframe.html#userShouldDenyAccess,userShouldNotBeConsulted,policyShouldGrantAccess,isSameOriginIframe"></iframe>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-database-expected.txt b/LayoutTests/http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-database-expected.txt
new file mode 100644
index 0000000..c5b0850
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that same-origin iframe storage access is granted if the iframe is sandboxed and has the allow token.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Storage access was granted. document.cookie == , cookies seen server-side == "No cookies"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-database.html b/LayoutTests/http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-database.html
new file mode 100644
index 0000000..62b1715
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-database.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that same-origin iframe storage access is granted if the iframe is sandboxed and has the allow token.");
+        jsTestIsAsync = true;
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function receiveMessage(event) {
+            if (event.origin === "http://127.0.0.1:8000") {
+                if (event.data.indexOf("PASS") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data.replace("FAIL ", ""));
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            setEnableFeature(false, finishJSTest);
+        }
+
+        function activateElement(elementId) {
+            var element = document.getElementById(elementId);
+            var centerX = element.offsetLeft + element.offsetWidth / 2;
+            var centerY = element.offsetTop + element.offsetHeight / 2;
+            UIHelper.activateAt(centerX, centerY).then(
+                function () {
+                    if (window.eventSender)
+                        eventSender.keyDown("escape");
+                    else {
+                        testFailed("No eventSender.");
+                        setEnableFeature(false, finishJSTest);
+                    }
+                },
+                function () {
+                    testFailed("Promise rejected.");
+                    setEnableFeature(false, finishJSTest);
+                }
+            );
+        }
+
+        function runTest() {
+            testRunner.setUseITPDatabase(true);
+            setEnableFeature(true, function() {
+                activateElement("TheIframeThatRequestsStorageAccess");
+            });
+        }
+    </script>
+</head>
+<body>
+    <iframe sandbox="allow-storage-access-by-user-activation allow-scripts allow-same-origin allow-modals" onload="runTest()" id="TheIframeThatRequestsStorageAccess" src="http://127.0.0.1:8000/storageAccess/resources/request-storage-access-iframe.html#userShouldDenyAccess,userShouldNotBeConsulted,policyShouldGrantAccess,isSameOriginIframe"></iframe>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-without-allow-token-database-expected.txt b/LayoutTests/http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-without-allow-token-database-expected.txt
new file mode 100644
index 0000000..c1f10e2
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-without-allow-token-database-expected.txt
@@ -0,0 +1,10 @@
+Tests that same-origin iframe storage access is granted if the iframe is sandboxed but doesn't have the allow token.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Storage access was granted. document.cookie == , cookies seen server-side == "No cookies"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-without-allow-token-database.html b/LayoutTests/http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-without-allow-token-database.html
new file mode 100644
index 0000000..af693ed
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-without-allow-token-database.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/js-test-resources/js-test.js"></script>
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="/resourceLoadStatistics/resources/util.js"></script>
+    <script>
+        description("Tests that same-origin iframe storage access is granted if the iframe is sandboxed but doesn't have the allow token.");
+        jsTestIsAsync = true;
+
+        const hostUnderTest = "localhost:8000";
+        const statisticsUrl = "http://" + hostUnderTest + "/temp";
+
+        window.addEventListener("message", receiveMessage, false);
+
+        function receiveMessage(event) {
+            if (event.origin === "http://127.0.0.1:8000") {
+                if (event.data.indexOf("PASS") !== -1)
+                    testPassed(event.data.replace("PASS ", ""));
+                else
+                    testFailed(event.data.replace("FAIL ", ""));
+            } else
+                testFailed("Received a message from an unexpected origin: " + event.origin);
+            setEnableFeature(false, finishJSTest);
+        }
+
+        function activateElement(elementId) {
+            var element = document.getElementById(elementId);
+            var centerX = element.offsetLeft + element.offsetWidth / 2;
+            var centerY = element.offsetTop + element.offsetHeight / 2;
+            UIHelper.activateAt(centerX, centerY).then(
+                function () {
+                    if (window.eventSender)
+                        eventSender.keyDown("escape");
+                    else {
+                        testFailed("No eventSender.");
+                        setEnableFeature(false, finishJSTest);
+                    }
+                },
+                function () {
+                    testFailed("Promise rejected.");
+                    setEnableFeature(false, finishJSTest);
+                }
+            );
+        }
+
+        function runTest() {
+            testRunner.setUseITPDatabase(true);
+            setEnableFeature(true, function() {
+                testRunner.setStatisticsPrevalentResource(statisticsUrl, true, function() {
+                    if (!testRunner.isStatisticsPrevalentResource(statisticsUrl))
+                        testFailed("Host did not get set as prevalent resource.");
+                    testRunner.setStatisticsHasHadUserInteraction(statisticsUrl, true, function() {
+                        if (!testRunner.isStatisticsHasHadUserInteraction(statisticsUrl))
+                            testFailed("Host did not get logged for user interaction.");
+                        testRunner.statisticsUpdateCookieBlocking(function() {
+                            let iframeElement = document.createElement("iframe");
+                            iframeElement.setAttribute("sandbox", "allow-scripts allow-same-origin allow-modals");
+                            iframeElement.onload = function() {
+                                activateElement("TheIframeThatRequestsStorageAccess");
+                            };
+                            iframeElement.id = "TheIframeThatRequestsStorageAccess";
+                            iframeElement.src = "http://127.0.0.1:8000/storageAccess/resources/request-storage-access-iframe.html#userShouldDenyAccess,userShouldNotBeConsulted,policyShouldGrantAccess,isSameOriginIframe";
+                            document.body.appendChild(iframeElement);
+                        });
+                    });
+                });
+            });
+        }
+    </script>
+</head>
+<body onload="runTest()">
+</body>
+</html>
diff --git a/LayoutTests/http/tests/storageAccess/request-storage-access-top-frame-database-expected.txt b/LayoutTests/http/tests/storageAccess/request-storage-access-top-frame-database-expected.txt
new file mode 100644
index 0000000..f25a591
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-storage-access-top-frame-database-expected.txt
@@ -0,0 +1,11 @@
+Tests that top frame storage access is always granted in case the page requests it.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS requestStorageAccessResolved is true
+PASS hasStorageAccess is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Request Access
diff --git a/LayoutTests/http/tests/storageAccess/request-storage-access-top-frame-database.html b/LayoutTests/http/tests/storageAccess/request-storage-access-top-frame-database.html
new file mode 100644
index 0000000..6318767
--- /dev/null
+++ b/LayoutTests/http/tests/storageAccess/request-storage-access-top-frame-database.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+<body onload="runTest()">
+<script src="/js-test-resources/js-test.js"></script>
+<script src="/js-test-resources/ui-helper.js"></script>
+<script src="/resourceLoadStatistics/resources/util.js"></script>
+<script>
+    description("Tests that top frame storage access is always granted in case the page requests it.");
+    jsTestIsAsync = true;
+
+    function activateElement(elementId) {
+        var element = document.getElementById(elementId);
+        var centerX = element.offsetLeft + element.offsetWidth / 2;
+        var centerY = element.offsetTop + element.offsetHeight / 2;
+        UIHelper.activateAt(centerX, centerY).then(
+            function () {
+            },
+            function () {
+                testFailed("Promise rejected.");
+                setEnableFeature(false, finishJSTest);
+            }
+        );
+    }
+
+    var hasStorageAccess;
+    var requestStorageAccessResolved;
+
+    function makeRequestWithUserGesture() {
+        setEnableFeature(true, function() {
+            var promise = document.requestStorageAccess();
+            promise.then(
+                function () {
+                    requestStorageAccessResolved = true;
+                    continueAfterRequestWithUserGesture();
+                },
+                function () {
+                    requestStorageAccessResolved = false;
+                    continueAfterRequestWithUserGesture();
+                }
+            );
+        });
+    }
+
+    function continueAfterRequestWithUserGesture() {
+        var promise = document.hasStorageAccess();
+        promise.then(
+            function (hasAccess) {
+                hasStorageAccess = hasAccess;
+                shouldBe("requestStorageAccessResolved", "true");
+                shouldBe("hasStorageAccess", "true");
+                setEnableFeature(false, finishJSTest);
+            },
+            function (reason) {
+                testFailed("document.hasStorageAccess() was rejected. Reason: " + reason);
+                setEnableFeature(false, finishJSTest);
+            }
+        );
+    }
+
+    function runTest() {
+        testRunner.setUseITPDatabase(true);
+        activateElement("theButton");
+    }
+</script>
+<button id="theButton" onclick="makeRequestWithUserGesture()">Request Access</button>
+</body>
+</html>
diff --git a/LayoutTests/platform/ios/TestExpectations b/LayoutTests/platform/ios/TestExpectations
index 148609f..630c30b 100644
--- a/LayoutTests/platform/ios/TestExpectations
+++ b/LayoutTests/platform/ios/TestExpectations
@@ -2798,8 +2798,14 @@
 http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource.html [ Pass ]
 http/tests/storageAccess/has-storage-access-false-by-default.html [ Pass ]
 http/tests/storageAccess/has-storage-access-false-by-default-ephemeral.html [ Pass ]
-http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-ephemeral.html [ Pass ]
-http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies.html [ Pass ]
+http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-ephemeral.html [ Pass Timeout ]
+http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies.html [ Pass Timeout ]
+http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-ephemeral-database.html [ Pass Timeout ]
+http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-database.html [ Pass Timeout ]
+http/tests/storageAccess/deny-storage-access-under-opener-database.html [ Pass ]
+http/tests/storageAccess/deny-storage-access-under-opener-if-auto-dismiss-database.html [ Pass ]
+http/tests/storageAccess/has-storage-access-false-by-default-database.html [ Pass ]
+http/tests/storageAccess/has-storage-access-false-by-default-ephemeral-database.html [ Pass ]
 
 # Skipped in general expectations since they only work on iOS and Mac, WK2.
 http/tests/security/strip-referrer-to-origin-for-third-party-redirects-in-private-mode.html [ Pass ]
@@ -2934,6 +2940,7 @@
 webkit.org/b/177397 compositing/masks/compositing-clip-path-change-no-repaint.html [ Pass Failure ]
 
 webkit.org/b/177617 http/tests/storageAccess/request-storage-access-top-frame.html [ Pass Timeout ]
+http/tests/storageAccess/request-storage-access-top-frame-database.html [ Pass Timeout ]
 
 webkit.org/b/177547 imported/w3c/web-platform-tests/fetch/security/dangling-markup-mitigation-data-url.tentative.sub.html [ Pass Failure ]
 
diff --git a/LayoutTests/platform/mac-wk2/TestExpectations b/LayoutTests/platform/mac-wk2/TestExpectations
index 3828dbc..3961db1 100644
--- a/LayoutTests/platform/mac-wk2/TestExpectations
+++ b/LayoutTests/platform/mac-wk2/TestExpectations
@@ -686,36 +686,11 @@
 # Touch events are not available on open source bots, thus only tested on Mac.
 http/tests/resourceLoadStatistics/user-interaction-in-cross-origin-sub-frame.html [ Pass ]
 http/tests/resourceLoadStatistics/user-interaction-reported-after-website-data-removal.html [ Pass ]
-
-[ HighSierra+ ] http/tests/storageAccess/has-storage-access-crash.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/request-and-grant-access-cross-origin-non-sandboxed-iframe.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/request-storage-access-crash.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-with-unique-origin.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-allow-token.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/request-storage-access-same-origin-iframe.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe-without-allow-token.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/request-storage-access-same-origin-sandboxed-iframe.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-nested-iframe.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-and-access-from-right-frame.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-but-access-from-wrong-frame.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-without-user-interaction.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/request-storage-access-top-frame.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/request-storage-access-cross-origin-sandboxed-iframe-without-user-gesture.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/has-storage-access-from-prevalent-domain-with-user-interaction.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/request-and-grant-access-then-detach-should-not-have-access.html [ Pass ]
+[ HighSierra+ ] http/tests/storageAccess/ [ Pass ]
 webkit.org/b/198670 [ HighSierra+ ] http/tests/storageAccess/request-and-grant-access-then-navigate-cross-site-should-not-have-access.html [ Pass Timeout ]
-[ HighSierra+ ] http/tests/storageAccess/request-and-grant-access-then-navigate-same-site-should-have-access.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/deny-storage-access-under-opener.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/deny-storage-access-under-opener-if-auto-dismiss.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/grant-with-prompt-preserves-gesture.html [ Pass ]
+[ HighSierra+ ] http/tests/storageAccess/request-and-grant-access-then-navigate-cross-site-should-not-have-access-database.html [ Pass Timeout ]
 [ HighSierra+ ] http/tests/storageAccess/deny-with-prompt-does-not-preserve-gesture.html [ Skip ]
-[ HighSierra+ ] http/tests/storageAccess/deny-without-prompt-preserves-gesture.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/has-storage-access-false-by-default.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/has-storage-access-false-by-default-ephemeral.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies-ephemeral.html [ Pass ]
-[ HighSierra+ ] http/tests/storageAccess/has-storage-access-true-if-third-party-has-cookies.html [ Pass ]
+[ HighSierra+ ] http/tests/storageAccess/deny-with-prompt-does-not-preserve-gesture-database.html [ Skip ]
 
 # As of https://trac.webkit.org/changeset/227762 the timestampResolution is just 5 seconds which makes this test flaky
 http/tests/resourceLoadStatistics/user-interaction-only-reported-once-within-short-period-of-time.html [ Skip ]
@@ -915,6 +890,7 @@
 webkit.org/b/187391 accessibility/mac/async-increment-decrement-action.html [ Skip ]
 
 webkit.org/b/194164 http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-but-access-from-wrong-frame.html [ Pass Timeout ]
+http/tests/storageAccess/request-and-grant-access-cross-origin-sandboxed-iframe-from-prevalent-domain-with-user-interaction-but-access-from-wrong-frame-database.html [ Pass Timeout ]
 
 webkit.org/b/197068 [ Debug ] fast/selectors/matches-backtracking.html [ Pass Timeout ]
 
diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog
index 31466cd..67075dc 100644
--- a/Source/WebKit/ChangeLog
+++ b/Source/WebKit/ChangeLog
@@ -1,3 +1,34 @@
+2019-10-11  Kate Cheney  <katherine_cheney@apple.com>
+
+        Get StorageAccess API features working on SQLite database implementation (195422)
+        https://bugs.webkit.org/show_bug.cgi?id=195422
+        <rdar://problem/54213519>
+
+        Reviewed by Brent Fulgham.
+
+        This patch migrates the http/tests/storageAccess/ Layout tests to
+        use the ITP database and uncovered 3 bugs in the process.
+
+        1. It was previously blocking cookies to a third party domain which
+        was not marked as prevalent. Now it ensures that the user is prompted
+        using the storage acess API regarding that third party domain.
+
+        2. It was not requesting storage access if cookies had previously been
+        blocked. Now it will only return early from
+        ResourceLoadStatisticsDatabaseStore::requestStorageAccessUnderOpener
+        if cookie access is allowed, and request storage access otherwise.
+
+        3. hasUserGrantedStorageAccessThroughPrompt was returning true even
+        if the result was not previously granted storage access.
+
+        All of these fixes match behavior in
+        ResourceLoadStatisticsMemoryStore.
+
+        * NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp:
+        (WebKit::ResourceLoadStatisticsDatabaseStore::requestStorageAccess):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::requestStorageAccessUnderOpener):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::hasUserGrantedStorageAccessThroughPrompt):
+
 2019-10-11  Dean Jackson  <dino@apple.com>
 
         REGRESSION: fast/events/touch/ios/long-press-on-image.html is failing
diff --git a/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp b/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp
index 61695c8..1db541e 100644
--- a/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp
+++ b/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp
@@ -1153,22 +1153,19 @@
     ASSERT(!RunLoop::isMain());
 
     auto subFrameStatus = ensureResourceStatisticsForRegistrableDomain(subFrameDomain);
-
-    switch (cookieTreatmentForOrigin(subFrameDomain)) {
-    case CookieTreatmentResult::BlockAndPurge: {
+    auto cookieTreatmentResult = cookieTreatmentForOrigin(subFrameDomain);
+    
+    if (cookieTreatmentResult == CookieTreatmentResult::BlockAndPurge) {
         RELEASE_LOG_INFO_IF(debugLoggingEnabled(), ITPDebug, "Cannot grant storage access to %{private}s since its cookies are blocked in third-party contexts and it has not received user interaction as first-party.", subFrameDomain.string().utf8().data());
         completionHandler(StorageAccessStatus::CannotRequestAccess);
-        }
         return;
-    case CookieTreatmentResult::BlockAndKeep: {
+    }
+    
+    if (cookieTreatmentResult != CookieTreatmentResult::BlockAndKeep) {
         RELEASE_LOG_INFO_IF(debugLoggingEnabled(), ITPDebug, "No need to grant storage access to %{private}s since its cookies are not blocked in third-party contexts.", subFrameDomain.string().utf8().data());
         completionHandler(StorageAccessStatus::HasAccess);
-        }
         return;
-    case CookieTreatmentResult::Allow:
-        // Do nothing
-        break;
-    };
+    }
 
     auto userWasPromptedEarlier = hasUserGrantedStorageAccessThroughPrompt(subFrameStatus.second, topFrameDomain);
     if (userWasPromptedEarlier == StorageAccessPromptWasShown::No) {
@@ -1203,8 +1200,7 @@
         return;
 
     ensureResourceStatisticsForRegistrableDomain(domainInNeedOfStorageAccess);
-
-    if (cookieTreatmentForOrigin(domainInNeedOfStorageAccess) != CookieTreatmentResult::Allow)
+    if (cookieTreatmentForOrigin(domainInNeedOfStorageAccess) == CookieTreatmentResult::Allow)
         return;
 
     RELEASE_LOG_INFO_IF(debugLoggingEnabled(), ITPDebug, "[Temporary combatibility fix] Storage access was granted for %{private}s under opener page from %{private}s, with user interaction in the opened window.", domainInNeedOfStorageAccess.string().utf8().data(), openerDomain.string().utf8().data());
@@ -1723,7 +1719,7 @@
         || statement.step() != SQLITE_ROW)
         return StorageAccessPromptWasShown::No;
 
-    return !statement.getColumnInt(0) ? StorageAccessPromptWasShown::Yes : StorageAccessPromptWasShown::No;
+    return !!statement.getColumnInt(0) ? StorageAccessPromptWasShown::Yes : StorageAccessPromptWasShown::No;
 }
 
 Vector<RegistrableDomain> ResourceLoadStatisticsDatabaseStore::domainsToBlockAndDeleteCookiesFor() const