Walk FrameTrees to register origins in all frames.
In addition to doing a global walk of the session history to find
existing instances of an origin that is opting in to isolation (see
https://chromium-review.googlesource.com/c/chromium/src/+/2018252), we
must also look for that origin in the FrameTreeNodes. This looks at
committed origins as well as navigations that are pending commit.
The FrameTree walk is necessary since some frames may be missing
FrameNavigationEntries, and also since pending navigations will contain
information not yet in the session history.
Bug: 1042415, 1062719
Change-Id: I802c1f391037471a698e7eb7795a367bd0604f5b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2136703
Reviewed-by: Charlie Reis <[email protected]>
Reviewed-by: Alex Moshchuk <[email protected]>
Commit-Queue: James MacLean <[email protected]>
Cr-Commit-Position: refs/heads/master@{#764730}
diff --git a/content/browser/frame_host/frame_tree.cc b/content/browser/frame_host/frame_tree.cc
index c822829..e2f68c5 100644
--- a/content/browser/frame_host/frame_tree.cc
+++ b/content/browser/frame_host/frame_tree.cc
@@ -490,4 +490,47 @@
}
}
+void FrameTree::RegisterExistingOriginToPreventOptInIsolation(
+ const url::Origin& previously_visited_origin,
+ NavigationRequest* navigation_request_to_exclude) {
+ std::unordered_set<SiteInstance*> matching_site_instances;
+
+ // Be sure to visit all RenderFrameHosts associated with this frame that might
+ // have an origin that could script other frames. We skip RenderFrameHosts
+ // that are in the bfcache, assuming there's no way for a frame to join the
+ // BrowsingInstance of a bfcache RFH while it's in the cache.
+ for (auto* frame_tree_node : SubtreeNodes(root())) {
+ auto* frame_host = frame_tree_node->current_frame_host();
+
+ if (previously_visited_origin == frame_host->GetLastCommittedOrigin())
+ matching_site_instances.insert(frame_host->GetSiteInstance());
+
+ if (frame_host->HasCommittingNavigationRequestForOrigin(
+ previously_visited_origin, navigation_request_to_exclude)) {
+ matching_site_instances.insert(frame_host->GetSiteInstance());
+ }
+
+ auto* spec_frame_host =
+ frame_tree_node->render_manager()->speculative_frame_host();
+ if (spec_frame_host &&
+ spec_frame_host->HasCommittingNavigationRequestForOrigin(
+ previously_visited_origin, navigation_request_to_exclude)) {
+ matching_site_instances.insert(spec_frame_host->GetSiteInstance());
+ }
+
+ auto* navigation_request = frame_tree_node->navigation_request();
+ if (navigation_request &&
+ navigation_request != navigation_request_to_exclude &&
+ navigation_request->HasCommittingOrigin(previously_visited_origin)) {
+ matching_site_instances.insert(frame_host->GetSiteInstance());
+ }
+ }
+
+ // Update any SiteInstances found to contain |origin|.
+ for (auto* site_instance : matching_site_instances) {
+ static_cast<SiteInstanceImpl*>(site_instance)
+ ->PreventOptInOriginIsolation(previously_visited_origin);
+ }
+}
+
} // namespace content
diff --git a/content/browser/frame_host/frame_tree.h b/content/browser/frame_host/frame_tree.h
index 1058b11d..b459715 100644
--- a/content/browser/frame_host/frame_tree.h
+++ b/content/browser/frame_host/frame_tree.h
@@ -267,6 +267,14 @@
// identified by |instance|.
void SetPageFocus(SiteInstance* instance, bool is_focused);
+ // Walks the current frame tree and registers any origins matching |origin|,
+ // either the last committed origin of a RenderFrameHost or the origin
+ // associated with a NavigationRequest that has been assigned to a
+ // SiteInstance, as not-opted-in for origin isolation.
+ void RegisterExistingOriginToPreventOptInIsolation(
+ const url::Origin& previously_visited_origin,
+ NavigationRequest* navigation_request_to_exclude);
+
private:
friend class FrameTreeTest;
FRIEND_TEST_ALL_PREFIXES(RenderFrameHostImplBrowserTest, RemoveFocusedFrame);
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index cfcf53b..571c327 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -1730,12 +1730,31 @@
// map the global-walk call onto NavigatorDelegate to get it into
// WebContents. We definitely need to do the global walk prior to deciding
// on the render_frame_host_ to commit to.
+ // We must exclude ourselves from the global walk otherwise we may mark our
+ // origin as non-opt-in before it gets the change to register itself as
+ // opted-in.
frame_tree_node_->navigator()
->GetDelegate()
- ->RegisterExistingOriginToPreventOptInIsolation(origin);
+ ->RegisterExistingOriginToPreventOptInIsolation(
+ origin, this /* navigation_request_to_exclude */);
}
}
+bool NavigationRequest::HasCommittingOrigin(const url::Origin& origin) {
+ // We are only interested in checking requests that have been assigned a
+ // SiteInstance.
+ if (state() < WILL_PROCESS_RESPONSE)
+ return false;
+
+ // This origin conversion won't be correct for about:blank, but origin
+ // isolation shouldn't need to care about that case because a previous
+ // instance of the origin would already have determined its isolation status
+ // in that BrowsingInstance.
+ // TODO(https://crbug.com/888079): Use the computed origin here just to be
+ // safe.
+ return origin == url::Origin::Create(GetURL());
+}
+
bool NavigationRequest::IsOptInIsolationRequested() {
if (!response())
return false;
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h
index 8a33ad3..b59638d3 100644
--- a/content/browser/frame_host/navigation_request.h
+++ b/content/browser/frame_host/navigation_request.h
@@ -202,6 +202,9 @@
~NavigationRequest() override;
+ // Returns true if this request's URL matches |origin| and the request state
+ // is at (or past) WILL_PROCESS_RESPONSE.
+ bool HasCommittingOrigin(const url::Origin& origin);
// Returns true if this navigation request is requesting opt-in
// origin-isolation, via Origin Policy or headers.
bool IsOptInIsolationRequested();
diff --git a/content/browser/frame_host/navigator_delegate.h b/content/browser/frame_host/navigator_delegate.h
index 4c412b47..b425752e 100644
--- a/content/browser/frame_host/navigator_delegate.h
+++ b/content/browser/frame_host/navigator_delegate.h
@@ -26,6 +26,7 @@
class FrameTreeNode;
class NavigationHandle;
+class NavigationRequest;
class RenderFrameHostImpl;
struct LoadCommittedDetails;
struct OpenURLParams;
@@ -135,10 +136,14 @@
const GURL& scope,
AllowServiceWorkerResult allowed) {}
- // Does a global walk of the session history, and registers origins that
- // match |origin| to their respective BrowsingInstances.
+ // Does a global walk of the session history and all committed/pending-commit
+ // origins, and registers origins that match |origin| to their respective
+ // BrowsingInstances. |navigation_request_to_exclude| allows the
+ // NavigationRequest that initiates this process to avoid marking itself as
+ // non-opted-in before it gets the chance to opt-in.
virtual void RegisterExistingOriginToPreventOptInIsolation(
- const url::Origin& origin) {}
+ const url::Origin& origin,
+ NavigationRequest* navigation_request_to_exclude) {}
};
} // namespace content
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index d5f0ba8..237a39c 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -3361,6 +3361,28 @@
std::move(callback));
}
+bool RenderFrameHostImpl::HasCommittingNavigationRequestForOrigin(
+ const url::Origin& origin,
+ NavigationRequest* navigation_request_to_exclude) {
+ if (navigation_request_ &&
+ navigation_request_.get() != navigation_request_to_exclude &&
+ navigation_request_->HasCommittingOrigin(origin)) {
+ return true;
+ }
+
+ for (const auto& it : navigation_requests_) {
+ NavigationRequest* request = it.first;
+ if (request != navigation_request_to_exclude &&
+ request->HasCommittingOrigin(origin)) {
+ return true;
+ }
+ }
+
+ // Note: this function excludes |same_document_navigation_request_|, which
+ // should be ok since these cannot change the origin.
+ return false;
+}
+
void RenderFrameHostImpl::SendInterventionReport(const std::string& id,
const std::string& message) {
GetAssociatedLocalFrame()->SendInterventionReport(id, message);
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 0855e9ac..d9288fe 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -1531,6 +1531,16 @@
void ReportNoBinderForInterface(const std::string& error);
+ // Returns true if this object has any NavigationRequests matching |origin|.
+ // Since this function is used to find existing committed/committing origins
+ // that have not opted-in to isolation, and since any calls to this function
+ // will be initiated by a NavigationRequest that is itself requesting opt-in
+ // isolation, |navigation_request_to_exclude| allows that request to exclude
+ // itself from consideration.
+ bool HasCommittingNavigationRequestForOrigin(
+ const url::Origin& origin,
+ NavigationRequest* navigation_request_to_exclude);
+
// Force the RenderFrameHost to be left in pending deletion state instead of
// being actually deleted after navigating away:
// - Force waiting for unload handler result regardless of whether an
diff --git a/content/browser/isolated_origin_browsertest.cc b/content/browser/isolated_origin_browsertest.cc
index ee90bfc5..5b2d562 100644
--- a/content/browser/isolated_origin_browsertest.cc
+++ b/content/browser/isolated_origin_browsertest.cc
@@ -14,6 +14,7 @@
#include "components/network_session_configurator/common/network_switches.h"
#include "content/browser/bad_message.h"
#include "content/browser/child_process_security_policy_impl.h"
+#include "content/browser/frame_host/navigator.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/storage_partition_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
@@ -32,6 +33,7 @@
#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/test/content_browser_test_utils_internal.h"
+#include "content/test/did_commit_navigation_interceptor.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "net/dns/mock_host_resolver.h"
@@ -678,6 +680,267 @@
url::Origin::Create(non_isolated_sub_origin)));
}
+// This test creates a scenario where we have a frame without a
+// FrameNavigationEntry, and then we created another frame with the same origin
+// that opts-in to isolation. The opt-in triggers a walk of the session history
+// and the frame tree ... the session history won't pick up the first frame, but
+// the frame-tree walk should.
+IN_PROC_BROWSER_TEST_F(OriginIsolationOptInOriginPolicyTest, FrameTreeTest) {
+ EXPECT_TRUE(NavigateToURL(shell(),
+ https_server()->GetURL("bar.com", "/title1.html")));
+ // Have tab1 call window.open() to create blank tab2.
+ FrameTreeNode* tab1_root = web_contents()->GetFrameTree()->root();
+ ShellAddedObserver new_shell_observer;
+ ASSERT_TRUE(ExecuteScript(tab1_root->current_frame_host(),
+ "window.w = window.open()"));
+ Shell* tab2_shell = new_shell_observer.GetShell();
+
+ // Create iframe in tab2.
+ FrameTreeNode* tab2_root =
+ static_cast<WebContentsImpl*>(tab2_shell->web_contents())
+ ->GetFrameTree()
+ ->root();
+ ASSERT_TRUE(ExecuteScript(tab2_root->current_frame_host(),
+ "var iframe = document.createElement('iframe');"
+ "document.body.appendChild(iframe);"));
+ EXPECT_EQ(1U, tab2_root->child_count());
+ FrameTreeNode* tab2_child = tab2_root->child_at(0);
+ GURL isolated_origin_url(
+ https_server()->GetURL("isolated.foo.com", "/isolate_origin"));
+ // The subframe won't be isolated.
+ EXPECT_TRUE(NavigateFrameToURL(tab2_child, isolated_origin_url));
+
+ // Do a browser-initiated navigation of tab1 to the same origin, but isolate
+ // it this time. This should place the two frames with |isolated_origin_url|
+ // into different BrowsingInstances.
+ SetOriginPolicyManifest(R"({ "ids": ["my-policy"], "isolation": true })");
+ EXPECT_TRUE(NavigateToURL(shell(), isolated_origin_url));
+
+ // Since the same origin exists in two tabs, but one is isolated and the other
+ // isn't, we expect them to be in different BrowsingInstances.
+ using ScopedOriginIsolationOptInRequest =
+ ChildProcessSecurityPolicyImpl::ScopedOriginIsolationOptInRequest;
+
+ EXPECT_NE(tab1_root->current_frame_host()->GetSiteInstance(),
+ tab2_child->current_frame_host()->GetSiteInstance());
+ EXPECT_NE(tab1_root->current_frame_host()
+ ->GetSiteInstance()
+ ->GetIsolationContext()
+ .browsing_instance_id(),
+ tab2_child->current_frame_host()
+ ->GetSiteInstance()
+ ->GetIsolationContext()
+ .browsing_instance_id());
+ auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
+ url::Origin isolated_origin = url::Origin::Create(isolated_origin_url);
+ {
+ // Verify that |isolated origin| is in the non-opt-in list for tab2's
+ // child's BrowsingInstance. We do this by requesting opt-in for the origin,
+ // then verifying that it is denied by DoesOriginRequestOptInIsolation.
+ std::unique_ptr<ScopedOriginIsolationOptInRequest> scoped_request =
+ ScopedOriginIsolationOptInRequest::GetScopedOriginIsolationOptInRequest(
+ isolated_origin);
+
+ EXPECT_FALSE(
+ policy->ShouldOriginGetOptInIsolation(tab2_child->current_frame_host()
+ ->GetSiteInstance()
+ ->GetIsolationContext(),
+ isolated_origin));
+ }
+ // Verify that |isolated_origin| in tab1 is indeed isolated.
+ EXPECT_TRUE(policy->ShouldOriginGetOptInIsolation(
+ tab1_root->current_frame_host()->GetSiteInstance()->GetIsolationContext(),
+ isolated_origin));
+ // Verify that the tab2 child frame has no FrameNavigationEntry.
+ // TODO(wjmaclean): when https://crbug.com/524208 is fixed, this next check
+ // will fail, and it should be removed with the CL that fixes 524208.
+ EXPECT_EQ(
+ nullptr,
+ tab2_shell->web_contents()->GetController().GetLastCommittedEntry());
+
+ // Now, create a second frame in tab2 and navigate it to
+ // |isolated_origin_url|. Even though isolation is requested, it should not
+ // be isolated.
+ ASSERT_TRUE(ExecuteScript(tab2_root->current_frame_host(),
+ "var iframe = document.createElement('iframe');"
+ "document.body.appendChild(iframe);"));
+ EXPECT_EQ(2U, tab2_root->child_count());
+ FrameTreeNode* tab2_child2 = tab2_root->child_at(1);
+ NavigateFrameToURL(tab2_child2, isolated_origin_url);
+ EXPECT_EQ(tab2_child->current_frame_host()->GetSiteInstance(),
+ tab2_child2->current_frame_host()->GetSiteInstance());
+
+ // Check that the two child frames can script each other.
+ EXPECT_TRUE(ExecuteScript(tab2_child2, R"(
+ parent.frames[0].cross_frame_property_test = 'hello from t2c2'; )"));
+ std::string message;
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ tab2_child,
+ "domAutomationController.send(window.cross_frame_property_test);",
+ &message));
+ EXPECT_EQ("hello from t2c2", message);
+}
+
+// Similar to FrameTreeTest, but we stop the navigation that's not requesting
+// isolation at the pending commit state in tab2, then verify that the FrameTree
+// walk has correctly registered the origin as non-isolated in tab2, but
+// isolated in tab1.
+IN_PROC_BROWSER_TEST_F(OriginIsolationOptInOriginPolicyTest,
+ FrameTreeTestPendingCommit) {
+ GURL isolated_origin_url(
+ https_server()->GetURL("isolated.foo.com", "/isolate_origin"));
+ TestNavigationManager non_isolated_delayer(shell()->web_contents(),
+ isolated_origin_url);
+ shell()->web_contents()->GetController().LoadURL(
+ isolated_origin_url, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
+ EXPECT_TRUE(non_isolated_delayer.WaitForResponse());
+
+ Shell* tab2 = CreateBrowser();
+ // Do a browser-initiated navigation of tab2 to the same origin, but isolate
+ // it this time. This should place the two frames with |isolated_origin_url|
+ // into different BrowsingInstances.
+ SetOriginPolicyManifest(R"({ "ids": ["my-policy"], "isolation": true })");
+ EXPECT_TRUE(NavigateToURL(tab2, isolated_origin_url));
+
+ // Now commit the non-isolated navigation.
+ non_isolated_delayer.WaitForNavigationFinished();
+
+ FrameTreeNode* tab1_root = web_contents()->GetFrameTree()->root();
+ SiteInstanceImpl* tab1_site_instance =
+ tab1_root->current_frame_host()->GetSiteInstance();
+ FrameTreeNode* tab2_root = static_cast<WebContentsImpl*>(tab2->web_contents())
+ ->GetFrameTree()
+ ->root();
+ SiteInstanceImpl* tab2_site_instance =
+ tab2_root->current_frame_host()->GetSiteInstance();
+ EXPECT_NE(tab1_site_instance, tab2_site_instance);
+ EXPECT_NE(tab1_site_instance->GetIsolationContext().browsing_instance_id(),
+ tab2_site_instance->GetIsolationContext().browsing_instance_id());
+
+ // Despite the non-isolated navigation only being at pending-commit when we
+ // got the response for the isolated navigation, it should be properly
+ // registered as non-isolated in its browsing instance.
+ using ScopedOriginIsolationOptInRequest =
+ ChildProcessSecurityPolicyImpl::ScopedOriginIsolationOptInRequest;
+ auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
+ url::Origin isolated_origin = url::Origin::Create(isolated_origin_url);
+ {
+ // Verify that |isolated origin| is in the non-opt-in list for tab1's
+ // BrowsingInstance. We do this by requesting opt-in for the origin, then
+ // verifying that it is denied by ShouldOriginGetOptInIsolation.
+ std::unique_ptr<ScopedOriginIsolationOptInRequest> scoped_request =
+ ScopedOriginIsolationOptInRequest::GetScopedOriginIsolationOptInRequest(
+ isolated_origin);
+
+ EXPECT_FALSE(policy->ShouldOriginGetOptInIsolation(
+ tab1_site_instance->GetIsolationContext(), isolated_origin));
+ }
+ // Verify that |isolated_origin| in tab2 is indeed isolated.
+ EXPECT_TRUE(policy->ShouldOriginGetOptInIsolation(
+ tab2_site_instance->GetIsolationContext(), isolated_origin));
+}
+
+// Helper class to navigate a second tab to a specified URL that requests opt-in
+// origin isolation just before the first tab processes the next
+// DidCommitProvisionalLoad message.
+class InjectIsolationRequestingNavigation
+ : public DidCommitNavigationInterceptor {
+ public:
+ InjectIsolationRequestingNavigation(
+ OriginIsolationOptInOriginPolicyTest* test_framework,
+ WebContents* tab1_web_contents,
+ Shell* tab2,
+ const GURL& url)
+ : DidCommitNavigationInterceptor(tab1_web_contents),
+ test_framework_(test_framework),
+ tab2_(tab2),
+ url_(url) {}
+
+ bool was_called() { return was_called_; }
+
+ private:
+ // DidCommitNavigationInterceptor implementation.
+ bool WillProcessDidCommitNavigation(
+ RenderFrameHost* render_frame_host,
+ NavigationRequest* navigation_request,
+ ::FrameHostMsg_DidCommitProvisionalLoad_Params* params,
+ mojom::DidCommitProvisionalLoadInterfaceParamsPtr* interface_params)
+ override {
+ was_called_ = true;
+
+ // Performa a navigation of |tab2_| to |url_|. |url_| should request
+ // isolation.
+ test_framework_->SetOriginPolicyManifest(
+ R"({ "ids": ["my-policy"], "isolation": true })");
+ EXPECT_TRUE(NavigateToURL(tab2_, url_));
+
+ return true;
+ }
+
+ OriginIsolationOptInOriginPolicyTest* test_framework_;
+ Shell* tab2_;
+ const GURL& url_;
+ bool was_called_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(InjectIsolationRequestingNavigation);
+};
+
+// This test is similar to the one above, but exercises the pending navigation
+// when it's at a different stage, namely between the CommitNavigation and
+// DidCommitProvisionalLoad, rather than at WillProcessResponse.
+IN_PROC_BROWSER_TEST_F(OriginIsolationOptInOriginPolicyTest,
+ FrameTreeTestBeforeDidCommit) {
+ GURL isolated_origin_url(
+ https_server()->GetURL("isolated.foo.com", "/isolate_origin"));
+
+ FrameTreeNode* tab1_root = web_contents()->GetFrameTree()->root();
+ // We use the following, slightly more verbose, code instead of
+ // CreateBrowser() in order to avoid issues with NavigateToURL() in
+ // InjectIsolationRequestingNavigation::WillProcessDidCommitNavigation()
+ // getting stuck when it calls for WaitForLoadStop internally.
+ Shell* tab2 =
+ Shell::CreateNewWindow(shell()->web_contents()->GetBrowserContext(),
+ GURL(), nullptr, gfx::Size());
+
+ InjectIsolationRequestingNavigation injector(this, web_contents(), tab2,
+ isolated_origin_url);
+ EXPECT_TRUE(NavigateToURL(shell(), isolated_origin_url));
+ EXPECT_TRUE(injector.was_called());
+
+ SiteInstanceImpl* tab1_site_instance =
+ tab1_root->current_frame_host()->GetSiteInstance();
+ FrameTreeNode* tab2_root = static_cast<WebContentsImpl*>(tab2->web_contents())
+ ->GetFrameTree()
+ ->root();
+ SiteInstanceImpl* tab2_site_instance =
+ tab2_root->current_frame_host()->GetSiteInstance();
+ EXPECT_NE(tab1_site_instance, tab2_site_instance);
+ EXPECT_NE(tab1_site_instance->GetIsolationContext().browsing_instance_id(),
+ tab2_site_instance->GetIsolationContext().browsing_instance_id());
+
+ // Despite the non-isolated navigation only being at pending-commit when we
+ // got the response for the isolated navigation, it should be properly
+ // registered as non-isolated in its browsing instance.
+ using ScopedOriginIsolationOptInRequest =
+ ChildProcessSecurityPolicyImpl::ScopedOriginIsolationOptInRequest;
+ auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
+ url::Origin isolated_origin = url::Origin::Create(isolated_origin_url);
+ {
+ // Verify that |isolated origin| is in the non-opt-in list for tab1's
+ // BrowsingInstance. We do this by requesting opt-in for the origin, then
+ // verifying that it is denied by DoesOriginRequestOptInIsolation.
+ std::unique_ptr<ScopedOriginIsolationOptInRequest> scoped_request =
+ ScopedOriginIsolationOptInRequest::GetScopedOriginIsolationOptInRequest(
+ isolated_origin);
+
+ EXPECT_FALSE(policy->ShouldOriginGetOptInIsolation(
+ tab1_site_instance->GetIsolationContext(), isolated_origin));
+ }
+ // Verify that |isolated_origin| in tab2 is indeed isolated.
+ EXPECT_TRUE(policy->ShouldOriginGetOptInIsolation(
+ tab2_site_instance->GetIsolationContext(), isolated_origin));
+}
+
class StrictOriginIsolationTest : public IsolatedOriginTestBase {
public:
StrictOriginIsolationTest() {}
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 9512a13..9e45d85 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -6194,13 +6194,19 @@
}
void WebContentsImpl::RegisterExistingOriginToPreventOptInIsolation(
- const url::Origin& origin) {
+ const url::Origin& origin,
+ NavigationRequest* navigation_request_to_exclude) {
// Note: This function can be made static if we ever need call it without
// a WebContentsImpl instance, in which case we can use a wrapper to
// implement the override from NavigatorDelegate.
for (WebContentsImpl* web_contents : GetAllWebContents()) {
web_contents->controller_.RegisterExistingOriginToPreventOptInIsolation(
origin);
+ // Walk the frame tree to pick up any frames without FrameNavigationEntries.
+ // * Some frames won't have FrameNavigationEntries (Issues 524208, 608402).
+ // * Some pending navigations won't have NavigationEntries.
+ web_contents->GetFrameTree()->RegisterExistingOriginToPreventOptInIsolation(
+ origin, navigation_request_to_exclude);
}
}
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index aec2d98..f0cd8bd 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -848,7 +848,8 @@
const GURL& scope,
AllowServiceWorkerResult allowed) override;
void RegisterExistingOriginToPreventOptInIsolation(
- const url::Origin& origin) override;
+ const url::Origin& origin,
+ NavigationRequest* navigation_request_to_exclude) override;
// RenderWidgetHostDelegate --------------------------------------------------