Handle detached frames in requestStorageAccess()

The spec indicates such calls should be rejected with a SecurityError.

Bug: 1354256
Change-Id: I65099ae4289f643021f4e2267189026e358f0b21
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3845652
Reviewed-by: Dominic Farolino <dom@chromium.org>
Commit-Queue: Matt Reichhoff <mreichhoff@chromium.org>
Reviewed-by: Brandon Maslen <brandm@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#1038877}
diff --git a/storage-access-api/helpers.js b/storage-access-api/helpers.js
index 9bc2451..4049ff7 100644
--- a/storage-access-api/helpers.js
+++ b/storage-access-api/helpers.js
@@ -34,6 +34,20 @@
     return result;
 }
 
+function RunRequestStorageAccessInDetachedFrame() {
+  let nestedFrame = document.createElement('iframe');
+  document.body.append(nestedFrame);
+  const inner_doc = nestedFrame.contentDocument;
+  nestedFrame.remove();
+  return inner_doc.requestStorageAccess();
+}
+
+function RunRequestStorageAccessViaDomParser() {
+  let parser = new DOMParser();
+  let doc = parser.parseFromString('<html></html>', 'text/html');
+  return doc.requestStorageAccess();
+}
+
 let g_clickID = 0;
 function ClickButtonWithGesture(onClickMethod) {
   // Append some formatting and information so non WebDriver instances can complete this test too.
diff --git a/storage-access-api/requestStorageAccess.sub.window.js b/storage-access-api/requestStorageAccess.sub.window.js
index 1366a1d..432ae1a 100644
--- a/storage-access-api/requestStorageAccess.sub.window.js
+++ b/storage-access-api/requestStorageAccess.sub.window.js
@@ -40,6 +40,22 @@
   // This specific test will run only as a top level test (not as a worker).
   // Specific requestStorageAccess() scenarios will be tested within the context
   // of various iFrames
+  promise_test(async t => {
+    let promise = RunRequestStorageAccessInDetachedFrame();
+    let description = "document.requestStorageAccess() call in a detached frame";
+    return promise.then(t.unreached_func("Should have rejected: " + description)).catch(function (e) {
+
+      assert_equals(e.name, 'SecurityError', description);
+    });
+  }, "[non-fully-active] document.requestStorageAccess() should not resolve when run in a detached frame");
+
+  promise_test(async t => {
+    let promise = RunRequestStorageAccessViaDomParser();
+    let description = "document.requestStorageAccess() in a detached DOMParser result";
+    return promise.then(t.unreached_func("Should have rejected: " + description)).catch(function (e) {
+      assert_equals(e.name, 'SecurityError', description);
+    });
+  }, "[non-fully-active] document.requestStorageAccess() should not resolve when run in a detached DOMParser document");
 
   // Create a test with a single-child same-origin iframe.
   let sameOriginFramePromise = RunTestsInIFrame(
@@ -57,7 +73,7 @@
   // Validate the nested-iframe scenario where the cross-origin frame
   // containing the tests is not the first child.
   let nestedCrossOriginFramePromise = RunTestsInNestedIFrame(
-      'http://{{domains[www]}}:{{ports[http][0]}}/storage-access-api/resources/requestStorageAccess-iframe.html?testCase=nested-cross-origin-frame&rootdocument=false')
+      'http://{{domains[www]}}:{{ports[http][0]}}/storage-access-api/resources/requestStorageAccess-iframe.html?testCase=nested-cross-origin-frame&rootdocument=false');
 
   // Because the iframe tests expect no user activation, and because they
   // load asynchronously, we want to first run those tests before simulating