blob: 95185ffbbb88585a869c2097ea92e9890df66f4e [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/test/scoped_feature_list.h"
#include "components/network_session_configurator/common/network_switches.h"
#include "content/browser/frame_host/navigation_request.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/test/content_browser_test_utils_internal.h"
#include "net/dns/mock_host_resolver.h"
#include "services/network/public/cpp/cross_origin_opener_policy.h"
#include "services/network/public/cpp/features.h"
namespace content {
namespace {
network::CrossOriginOpenerPolicy CoopSameOrigin() {
network::CrossOriginOpenerPolicy coop;
coop.value = network::mojom::CrossOriginOpenerPolicyValue::kSameOrigin;
return coop;
}
network::CrossOriginOpenerPolicy CoopSameOriginAllowPopups() {
network::CrossOriginOpenerPolicy coop;
coop.value =
network::mojom::CrossOriginOpenerPolicyValue::kSameOriginAllowPopups;
return coop;
}
network::CrossOriginOpenerPolicy CoopUnsafeNone() {
network::CrossOriginOpenerPolicy coop;
// Using the default value.
return coop;
}
class CrossOriginOpenerPolicyBrowserTest : public ContentBrowserTest {
public:
CrossOriginOpenerPolicyBrowserTest()
: https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
std::vector<base::Feature> features;
feature_list_.InitWithFeatures(
{network::features::kCrossOriginOpenerPolicy,
network::features::kCrossOriginEmbedderPolicy},
{});
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kIgnoreCertificateErrors);
}
net::EmbeddedTestServer* https_server() { return &https_server_; }
protected:
void SetUpOnMainThread() override {
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(embedded_test_server()->Start());
https_server()->ServeFilesFromSourceDirectory(GetTestDataFilePath());
SetupCrossSiteRedirector(https_server());
ASSERT_TRUE(https_server()->Start());
}
void SetUpCommandLine(base::CommandLine* command_line) override {
ContentBrowserTest::SetUpCommandLine(command_line);
command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
}
WebContentsImpl* web_contents() const {
return static_cast<WebContentsImpl*>(shell()->web_contents());
}
RenderFrameHostImpl* current_frame_host() {
return web_contents()->GetFrameTree()->root()->current_frame_host();
}
base::test::ScopedFeatureList feature_list_;
net::EmbeddedTestServer https_server_;
};
IN_PROC_BROWSER_TEST_F(CrossOriginOpenerPolicyBrowserTest,
NewPopupCOOP_InheritsSameOrigin) {
GURL starting_page(
https_server()->GetURL("a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), starting_page));
RenderFrameHostImpl* main_frame = current_frame_host();
main_frame->set_cross_origin_opener_policy(CoopSameOrigin());
ShellAddedObserver shell_observer;
RenderFrameHostImpl* iframe = main_frame->child_at(0)->current_frame_host();
EXPECT_TRUE(ExecJs(iframe, "window.open('about:blank')"));
RenderFrameHostImpl* popup_frame =
static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents())
->GetFrameTree()
->root()
->current_frame_host();
EXPECT_EQ(main_frame->cross_origin_opener_policy(), CoopSameOrigin());
EXPECT_EQ(popup_frame->cross_origin_opener_policy(), CoopSameOrigin());
}
IN_PROC_BROWSER_TEST_F(CrossOriginOpenerPolicyBrowserTest,
NewPopupCOOP_InheritsSameOriginAllowPopups) {
GURL starting_page(
https_server()->GetURL("a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), starting_page));
RenderFrameHostImpl* main_frame = current_frame_host();
main_frame->set_cross_origin_opener_policy(CoopSameOriginAllowPopups());
ShellAddedObserver shell_observer;
RenderFrameHostImpl* iframe = main_frame->child_at(0)->current_frame_host();
EXPECT_TRUE(ExecJs(iframe, "window.open('about:blank')"));
RenderFrameHostImpl* popup_frame =
static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents())
->GetFrameTree()
->root()
->current_frame_host();
EXPECT_EQ(main_frame->cross_origin_opener_policy(),
CoopSameOriginAllowPopups());
EXPECT_EQ(popup_frame->cross_origin_opener_policy(),
CoopSameOriginAllowPopups());
}
IN_PROC_BROWSER_TEST_F(CrossOriginOpenerPolicyBrowserTest,
NewPopupCOOP_CrossOriginDoesNotInherit) {
GURL starting_page(
https_server()->GetURL("a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), starting_page));
RenderFrameHostImpl* main_frame = current_frame_host();
main_frame->set_cross_origin_opener_policy(CoopSameOrigin());
ShellAddedObserver shell_observer;
RenderFrameHostImpl* iframe = main_frame->child_at(0)->current_frame_host();
EXPECT_TRUE(ExecJs(iframe, "window.open('about:blank')"));
RenderFrameHostImpl* popup_frame =
static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents())
->GetFrameTree()
->root()
->current_frame_host();
EXPECT_EQ(main_frame->cross_origin_opener_policy(), CoopSameOrigin());
EXPECT_EQ(popup_frame->cross_origin_opener_policy(), CoopUnsafeNone());
}
IN_PROC_BROWSER_TEST_F(
CrossOriginOpenerPolicyBrowserTest,
NewPopupCOOP_SameOriginPolicyAndCrossOriginIframeSetsNoopener) {
GURL starting_page(
https_server()->GetURL("a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), starting_page));
RenderFrameHostImpl* main_frame = current_frame_host();
main_frame->set_cross_origin_opener_policy(CoopSameOrigin());
ShellAddedObserver new_shell_observer;
RenderFrameHostImpl* iframe = main_frame->child_at(0)->current_frame_host();
EXPECT_TRUE(ExecJs(iframe, "window.open('about:blank')"));
Shell* new_shell = new_shell_observer.GetShell();
RenderFrameHostImpl* popup_frame =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetFrameTree()
->root()
->current_frame_host();
scoped_refptr<SiteInstance> main_frame_site_instance(
main_frame->GetSiteInstance());
scoped_refptr<SiteInstance> iframe_site_instance(iframe->GetSiteInstance());
scoped_refptr<SiteInstance> popup_site_instance(
popup_frame->GetSiteInstance());
ASSERT_TRUE(main_frame_site_instance);
ASSERT_TRUE(iframe_site_instance);
ASSERT_TRUE(popup_site_instance);
EXPECT_FALSE(main_frame_site_instance->IsRelatedSiteInstance(
popup_site_instance.get()));
EXPECT_FALSE(
iframe_site_instance->IsRelatedSiteInstance(popup_site_instance.get()));
// Check that `window.opener` is not set.
bool success = false;
EXPECT_TRUE(ExecuteScriptAndExtractBool(
new_shell, "window.domAutomationController.send(window.opener == null);",
&success));
EXPECT_TRUE(success) << "window.opener is set";
}
IN_PROC_BROWSER_TEST_F(CrossOriginOpenerPolicyBrowserTest,
NetworkErrorOnSandboxedPopups) {
GURL starting_page(https_server()->GetURL(
"a.com", "/cross-origin-opener-policy_sandbox_popup.html"));
EXPECT_TRUE(NavigateToURL(shell(), starting_page));
ShellAddedObserver shell_observer;
RenderFrameHostImpl* iframe =
current_frame_host()->child_at(0)->current_frame_host();
EXPECT_TRUE(ExecJs(
iframe, "window.open('/cross-origin-opener-policy_same-origin.html')"));
auto* popup_webcontents =
static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents());
WaitForLoadStop(popup_webcontents);
EXPECT_EQ(
popup_webcontents->GetController().GetLastCommittedEntry()->GetPageType(),
PAGE_TYPE_ERROR);
}
IN_PROC_BROWSER_TEST_F(CrossOriginOpenerPolicyBrowserTest,
NoNetworkErrorOnSandboxedDocuments) {
GURL starting_page(https_server()->GetURL(
"a.com", "/cross-origin-opener-policy_csp_sandboxed.html"));
EXPECT_TRUE(NavigateToURL(shell(), starting_page));
EXPECT_NE(current_frame_host()->active_sandbox_flags(),
network::mojom::WebSandboxFlags::kNone)
<< "Document should be sandboxed.";
GURL next_page(https_server()->GetURL(
"a.com", "/cross-origin-opener-policy_same-origin.html"));
EXPECT_TRUE(NavigateToURL(shell(), next_page));
EXPECT_EQ(
web_contents()->GetController().GetLastCommittedEntry()->GetPageType(),
PAGE_TYPE_NORMAL);
}
class CrossOriginPolicyHeadersObserver : public WebContentsObserver {
public:
explicit CrossOriginPolicyHeadersObserver(
WebContents* web_contents,
network::mojom::CrossOriginEmbedderPolicyValue expected_coep,
network::CrossOriginOpenerPolicy expected_coop)
: WebContentsObserver(web_contents),
expected_coep_(expected_coep),
expected_coop_(expected_coop) {}
~CrossOriginPolicyHeadersObserver() override = default;
void DidRedirectNavigation(NavigationHandle* navigation_handle) override {
// Verify that the COOP/COEP headers were parsed.
NavigationRequest* navigation_request =
static_cast<NavigationRequest*>(navigation_handle);
CHECK(navigation_request->response()
->parsed_headers->cross_origin_embedder_policy.value ==
expected_coep_);
CHECK(navigation_request->response()
->parsed_headers->cross_origin_opener_policy == expected_coop_);
}
void DidFinishNavigation(NavigationHandle* navigation_handle) override {
// Verify that the COOP/COEP headers were parsed.
NavigationRequest* navigation_request =
static_cast<NavigationRequest*>(navigation_handle);
CHECK(navigation_request->response()
->parsed_headers->cross_origin_embedder_policy.value ==
expected_coep_);
CHECK(navigation_request->response()
->parsed_headers->cross_origin_opener_policy == expected_coop_);
}
private:
network::mojom::CrossOriginEmbedderPolicyValue expected_coep_;
network::CrossOriginOpenerPolicy expected_coop_;
};
IN_PROC_BROWSER_TEST_F(CrossOriginOpenerPolicyBrowserTest,
RedirectsParseCoopAndCoepHeaders) {
GURL redirect_initial_page(https_server()->GetURL(
"a.com", "/cross-origin-opener-policy_redirect_initial.html"));
GURL redirect_final_page(https_server()->GetURL(
"a.com", "/cross-origin-opener-policy_redirect_final.html"));
CrossOriginPolicyHeadersObserver obs(
web_contents(),
network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
CoopSameOrigin());
EXPECT_TRUE(
NavigateToURL(shell(), redirect_initial_page, redirect_final_page));
}
IN_PROC_BROWSER_TEST_F(CrossOriginOpenerPolicyBrowserTest,
CoopIsIgnoredOverHttp) {
GURL non_coop_page(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL coop_page(embedded_test_server()->GetURL(
"a.com", "/cross-origin-opener-policy_same-origin.html"));
EXPECT_TRUE(NavigateToURL(shell(), non_coop_page));
scoped_refptr<SiteInstance> initial_site_instance(
current_frame_host()->GetSiteInstance());
EXPECT_TRUE(NavigateToURL(shell(), coop_page));
EXPECT_EQ(current_frame_host()->GetSiteInstance(), initial_site_instance);
EXPECT_EQ(current_frame_host()->cross_origin_opener_policy(),
CoopUnsafeNone());
}
IN_PROC_BROWSER_TEST_F(CrossOriginOpenerPolicyBrowserTest,
CoopIsIgnoredOnIframes) {
GURL starting_page(
https_server()->GetURL("a.com", "/cross_site_iframe_factory.html?a(b)"));
GURL iframe_navigation_url(https_server()->GetURL(
"b.com", "/cross-origin-opener-policy_same-origin.html"));
EXPECT_TRUE(NavigateToURL(shell(), starting_page));
RenderFrameHostImpl* main_rfh = current_frame_host();
FrameTreeNode* iframe_ftn = main_rfh->child_at(0);
RenderFrameHostImpl* iframe_rfh = iframe_ftn->current_frame_host();
SiteInstanceImpl* non_coop_iframe_site_instance =
iframe_rfh->GetSiteInstance();
// Navigate the iframe same-origin to a document with the COOP header. The
// header must be ignored in iframes.
NavigateFrameToURL(iframe_ftn, iframe_navigation_url);
iframe_rfh = iframe_ftn->current_frame_host();
// We expect the navigation to have used the same SiteInstance that was used
// in the first place since they are same origin and COOP is ignored.
EXPECT_EQ(iframe_rfh->GetLastCommittedURL(), iframe_navigation_url);
EXPECT_EQ(iframe_rfh->GetSiteInstance(), non_coop_iframe_site_instance);
// TODO(pmeuleman, ahemery): Don't store COOP on subframes as it will not be
// used anyway.
EXPECT_EQ(iframe_rfh->cross_origin_opener_policy(), CoopSameOrigin());
}
IN_PROC_BROWSER_TEST_F(CrossOriginOpenerPolicyBrowserTest,
NonCoopPageCrashIntoCoop) {
IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
GURL non_coop_page(https_server()->GetURL("a.com", "/title1.html"));
GURL coop_page(https_server()->GetURL(
"a.com", "/cross-origin-opener-policy_same-origin.html"));
// Test a crash before the navigation.
{
// Navigate to a non coop page.
EXPECT_TRUE(NavigateToURL(shell(), non_coop_page));
scoped_refptr<SiteInstance> initial_site_instance(
current_frame_host()->GetSiteInstance());
// Ensure it has a RenderFrameHostProxy for another cross-site page.
GURL non_coop_cross_site_page(
https_server()->GetURL("b.com", "/title1.html"));
OpenPopup(current_frame_host(), non_coop_cross_site_page, "");
EXPECT_EQ(web_contents()
->GetFrameTree()
->root()
->render_manager()
->GetProxyCount(),
1u);
// Simulate the renderer process crashing.
RenderProcessHost* process = initial_site_instance->GetProcess();
ASSERT_TRUE(process);
std::unique_ptr<RenderProcessHostWatcher> crash_observer(
new RenderProcessHostWatcher(
process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT));
process->Shutdown(0);
crash_observer->Wait();
crash_observer.reset();
// Navigate to a COOP page.
EXPECT_TRUE(NavigateToURL(shell(), coop_page));
EXPECT_FALSE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance(
initial_site_instance.get()));
EXPECT_EQ(current_frame_host()->cross_origin_opener_policy(),
CoopSameOrigin());
// The COOP page should no longer have any RenderFrameHostProxies.
EXPECT_EQ(web_contents()
->GetFrameTree()
->root()
->render_manager()
->GetProxyCount(),
0u);
}
// Test a crash during the navigation.
{
// Navigate to a non coop page.
EXPECT_TRUE(NavigateToURL(shell(), non_coop_page));
scoped_refptr<SiteInstance> initial_site_instance(
current_frame_host()->GetSiteInstance());
GURL non_coop_cross_site_page(
https_server()->GetURL("b.com", "/title1.html"));
// Ensure it has a RenderFrameHostProxy for another cross-site page.
OpenPopup(current_frame_host(), non_coop_cross_site_page, "");
EXPECT_EQ(web_contents()
->GetFrameTree()
->root()
->render_manager()
->GetProxyCount(),
1u);
// Start navigating to a COOP page.
TestNavigationManager coop_navigation(web_contents(), coop_page);
shell()->LoadURL(coop_page);
EXPECT_TRUE(coop_navigation.WaitForRequestStart());
// Simulate the renderer process crashing.
RenderProcessHost* process = initial_site_instance->GetProcess();
ASSERT_TRUE(process);
std::unique_ptr<RenderProcessHostWatcher> crash_observer(
new RenderProcessHostWatcher(
process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT));
process->Shutdown(0);
crash_observer->Wait();
crash_observer.reset();
// Finish the navigation to the COOP page.
coop_navigation.WaitForNavigationFinished();
EXPECT_TRUE(coop_navigation.was_successful());
EXPECT_FALSE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance(
initial_site_instance.get()));
EXPECT_EQ(current_frame_host()->cross_origin_opener_policy(),
CoopSameOrigin());
// The COOP page should no longer have any RenderFrameHostProxies.
EXPECT_EQ(web_contents()
->GetFrameTree()
->root()
->render_manager()
->GetProxyCount(),
0u);
}
}
IN_PROC_BROWSER_TEST_F(CrossOriginOpenerPolicyBrowserTest,
CoopPageCrashIntoNonCoop) {
IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
GURL non_coop_page(https_server()->GetURL("a.com", "/title1.html"));
GURL coop_page(https_server()->GetURL(
"a.com", "/cross-origin-opener-policy_same-origin.html"));
// Test a crash before the navigation.
{
// Navigate to a COOP page.
EXPECT_TRUE(NavigateToURL(shell(), coop_page));
scoped_refptr<SiteInstance> initial_site_instance(
current_frame_host()->GetSiteInstance());
// Ensure it has a RenderFrameHostProxy for another cross-site page.
Shell* popup_shell = OpenPopup(current_frame_host(), coop_page, "");
GURL cross_site_iframe(https_server()->GetURL("b.com", "/title1.html"));
TestNavigationManager iframe_navigation(popup_shell->web_contents(),
cross_site_iframe);
EXPECT_TRUE(ExecJs(popup_shell->web_contents(),
"var iframe = document.createElement('iframe');"
"iframe.src = '" +
cross_site_iframe.spec() +
"';"
"document.body.appendChild(iframe);"));
iframe_navigation.WaitForNavigationFinished();
EXPECT_EQ(web_contents()
->GetFrameTree()
->root()
->render_manager()
->GetProxyCount(),
1u);
// Simulate the renderer process crashing.
RenderProcessHost* process = initial_site_instance->GetProcess();
ASSERT_TRUE(process);
std::unique_ptr<RenderProcessHostWatcher> crash_observer(
new RenderProcessHostWatcher(
process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT));
process->Shutdown(0);
crash_observer->Wait();
crash_observer.reset();
// Navigate to a non COOP page.
EXPECT_TRUE(NavigateToURL(shell(), non_coop_page));
EXPECT_FALSE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance(
initial_site_instance.get()));
EXPECT_EQ(current_frame_host()->cross_origin_opener_policy(),
CoopUnsafeNone());
// The non COOP page should no longer have any RenderFrameHostProxies.
EXPECT_EQ(web_contents()
->GetFrameTree()
->root()
->render_manager()
->GetProxyCount(),
0u);
}
// Test a crash during the navigation.
{
// Navigate to a COOP page.
EXPECT_TRUE(NavigateToURL(shell(), coop_page));
scoped_refptr<SiteInstance> initial_site_instance(
current_frame_host()->GetSiteInstance());
// Ensure it has a RenderFrameHostProxy for another cross-site page.
Shell* popup_shell = OpenPopup(current_frame_host(), coop_page, "");
GURL cross_site_iframe(https_server()->GetURL("b.com", "/title1.html"));
TestNavigationManager iframe_navigation(popup_shell->web_contents(),
cross_site_iframe);
EXPECT_TRUE(ExecJs(popup_shell->web_contents(),
"var iframe = document.createElement('iframe');"
"iframe.src = '" +
cross_site_iframe.spec() +
"';"
"document.body.appendChild(iframe);"));
iframe_navigation.WaitForNavigationFinished();
EXPECT_EQ(web_contents()
->GetFrameTree()
->root()
->render_manager()
->GetProxyCount(),
1u);
// Start navigating to a non COOP page.
TestNavigationManager non_coop_navigation(web_contents(), non_coop_page);
shell()->LoadURL(non_coop_page);
EXPECT_TRUE(non_coop_navigation.WaitForRequestStart());
// Simulate the renderer process crashing.
RenderProcessHost* process = initial_site_instance->GetProcess();
ASSERT_TRUE(process);
std::unique_ptr<RenderProcessHostWatcher> crash_observer(
new RenderProcessHostWatcher(
process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT));
process->Shutdown(0);
crash_observer->Wait();
crash_observer.reset();
// Finish the navigation to the non COOP page.
non_coop_navigation.WaitForNavigationFinished();
EXPECT_TRUE(non_coop_navigation.was_successful());
EXPECT_FALSE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance(
initial_site_instance.get()));
EXPECT_EQ(current_frame_host()->cross_origin_opener_policy(),
CoopUnsafeNone());
// The non COOP page should no longer have any RenderFrameHostProxies.
EXPECT_EQ(web_contents()
->GetFrameTree()
->root()
->render_manager()
->GetProxyCount(),
0u);
}
}
IN_PROC_BROWSER_TEST_F(CrossOriginOpenerPolicyBrowserTest,
CoopPageCrashIntoCoop) {
IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
GURL non_coop_page(https_server()->GetURL("a.com", "/title1.html"));
GURL coop_page(https_server()->GetURL(
"a.com", "/cross-origin-opener-policy_same-origin.html"));
// Test a crash before the navigation.
{
// Navigate to a COOP page.
EXPECT_TRUE(NavigateToURL(shell(), coop_page));
scoped_refptr<SiteInstance> initial_site_instance(
current_frame_host()->GetSiteInstance());
// Ensure it has a RenderFrameHostProxy for another cross-site page.
Shell* popup_shell = OpenPopup(current_frame_host(), coop_page, "");
GURL cross_site_iframe(https_server()->GetURL("b.com", "/title1.html"));
TestNavigationManager iframe_navigation(popup_shell->web_contents(),
cross_site_iframe);
EXPECT_TRUE(ExecJs(popup_shell->web_contents(),
"var iframe = document.createElement('iframe');"
"iframe.src = '" +
cross_site_iframe.spec() +
"';"
"document.body.appendChild(iframe);"));
iframe_navigation.WaitForNavigationFinished();
EXPECT_EQ(web_contents()
->GetFrameTree()
->root()
->render_manager()
->GetProxyCount(),
1u);
// Simulate the renderer process crashing.
RenderProcessHost* process = initial_site_instance->GetProcess();
ASSERT_TRUE(process);
std::unique_ptr<RenderProcessHostWatcher> crash_observer(
new RenderProcessHostWatcher(
process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT));
process->Shutdown(0);
crash_observer->Wait();
crash_observer.reset();
// Navigate to a COOP page.
EXPECT_TRUE(NavigateToURL(shell(), coop_page));
EXPECT_TRUE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance(
initial_site_instance.get()));
EXPECT_EQ(current_frame_host()->cross_origin_opener_policy(),
CoopSameOrigin());
// TODO(pmeuleman): The COOP page should still have RenderFrameHostProxies.
EXPECT_EQ(web_contents()
->GetFrameTree()
->root()
->render_manager()
->GetProxyCount(),
0u);
}
// Test a crash during the navigation.
{
// Navigate to a COOP page.
EXPECT_TRUE(NavigateToURL(shell(), coop_page));
scoped_refptr<SiteInstance> initial_site_instance(
current_frame_host()->GetSiteInstance());
// Ensure it has a RenderFrameHostProxy for another cross-site page.
Shell* popup_shell = OpenPopup(current_frame_host(), coop_page, "");
GURL cross_site_iframe(https_server()->GetURL("b.com", "/title1.html"));
TestNavigationManager iframe_navigation(popup_shell->web_contents(),
cross_site_iframe);
EXPECT_TRUE(ExecJs(popup_shell->web_contents(),
"var iframe = document.createElement('iframe');"
"iframe.src = '" +
cross_site_iframe.spec() +
"';"
"document.body.appendChild(iframe);"));
iframe_navigation.WaitForNavigationFinished();
EXPECT_EQ(web_contents()
->GetFrameTree()
->root()
->render_manager()
->GetProxyCount(),
1u);
// Start navigating to a COOP page.
TestNavigationManager coop_navigation(web_contents(), coop_page);
shell()->LoadURL(coop_page);
EXPECT_TRUE(coop_navigation.WaitForRequestStart());
// Simulate the renderer process crashing.
RenderProcessHost* process = initial_site_instance->GetProcess();
ASSERT_TRUE(process);
std::unique_ptr<RenderProcessHostWatcher> crash_observer(
new RenderProcessHostWatcher(
process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT));
process->Shutdown(0);
crash_observer->Wait();
crash_observer.reset();
// Finish the navigation to the COOP page.
coop_navigation.WaitForNavigationFinished();
EXPECT_TRUE(coop_navigation.was_successful());
EXPECT_TRUE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance(
initial_site_instance.get()));
EXPECT_EQ(current_frame_host()->cross_origin_opener_policy(),
CoopSameOrigin());
// TODO(pmeuleman): The COOP page should still have RenderFrameHostProxies.
EXPECT_EQ(web_contents()
->GetFrameTree()
->root()
->render_manager()
->GetProxyCount(),
0u);
}
}
IN_PROC_BROWSER_TEST_F(CrossOriginOpenerPolicyBrowserTest,
ProxiesAreRemovedWhenCrossingCoopBoundary) {
GURL non_coop_page(https_server()->GetURL("a.com", "/title1.html"));
GURL coop_page(https_server()->GetURL(
"a.com", "/cross-origin-opener-policy_same-origin.html"));
RenderFrameHostManager* main_window_rfhm =
web_contents()->GetFrameTree()->root()->render_manager();
EXPECT_TRUE(NavigateToURL(shell(), non_coop_page));
EXPECT_EQ(main_window_rfhm->GetProxyCount(), 0u);
Shell* popup_shell = OpenPopup(shell(), coop_page, "");
// The main frame should not have the popup referencing it.
EXPECT_EQ(main_window_rfhm->GetProxyCount(), 0u);
// It should not have any other related SiteInstance.
EXPECT_EQ(
current_frame_host()->GetSiteInstance()->GetRelatedActiveContentsCount(),
1u);
// The popup should not have the main frame referencing it.
FrameTreeNode* popup =
static_cast<WebContentsImpl*>(popup_shell->web_contents())
->GetFrameTree()
->root();
RenderFrameHostManager* popup_rfhm = popup->render_manager();
EXPECT_EQ(popup_rfhm->GetProxyCount(), 0u);
// The popup should have an empty opener.
EXPECT_FALSE(popup->opener());
}
IN_PROC_BROWSER_TEST_F(CrossOriginOpenerPolicyBrowserTest,
ProxiesAreKeptWhenNavigatingFromCoopToCoop) {
IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
GURL coop_page(https_server()->GetURL(
"a.com", "/cross-origin-opener-policy_same-origin.html"));
// Navigate to a COOP page.
EXPECT_TRUE(NavigateToURL(shell(), coop_page));
scoped_refptr<SiteInstance> initial_site_instance(
current_frame_host()->GetSiteInstance());
// Ensure it has a RenderFrameHostProxy for another cross-site page.
Shell* popup_shell = OpenPopup(current_frame_host(), coop_page, "");
GURL cross_site_iframe(https_server()->GetURL("b.com", "/title1.html"));
TestNavigationManager iframe_navigation(popup_shell->web_contents(),
cross_site_iframe);
EXPECT_TRUE(ExecJs(popup_shell->web_contents(),
"var iframe = document.createElement('iframe');"
"iframe.src = '" +
cross_site_iframe.spec() +
"';"
"document.body.appendChild(iframe);"));
iframe_navigation.WaitForNavigationFinished();
EXPECT_EQ(
web_contents()->GetFrameTree()->root()->render_manager()->GetProxyCount(),
1u);
// Navigate to a COOP page.
EXPECT_TRUE(NavigateToURL(shell(), coop_page));
// The COOP page should still have a RenderFrameProxyHost.
EXPECT_EQ(
web_contents()->GetFrameTree()->root()->render_manager()->GetProxyCount(),
1u);
}
IN_PROC_BROWSER_TEST_F(CrossOriginOpenerPolicyBrowserTest,
IsolateInNewProcessDespiteLimitReached) {
// Set a process limit of 1 for testing.
RenderProcessHostImpl::SetMaxRendererProcessCount(1);
// Navigate to a starting page.
GURL starting_page(https_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), starting_page));
// Open a popup with CrossOriginOpenerPolicy and CrossOriginEmbedderPolicy
// set.
ShellAddedObserver shell_observer;
EXPECT_TRUE(ExecJs(current_frame_host(),
"window.open('/page_with_coop_and_coep.html')"));
auto* popup_webcontents =
static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents());
WaitForLoadStop(popup_webcontents);
// The page and its popup should be in different processes even though the
// process limit was reached.
// TODO(clamy, pmeuleman, ahemery): The assert below should be false once we
// fix the process reuse for COOP.
EXPECT_EQ(current_frame_host()->GetProcess(),
popup_webcontents->GetMainFrame()->GetProcess());
}
IN_PROC_BROWSER_TEST_F(CrossOriginOpenerPolicyBrowserTest,
NoProcessReuseForCOOPProcesses) {
// Set a process limit of 1 for testing.
RenderProcessHostImpl::SetMaxRendererProcessCount(1);
// Navigate to a starting page with CrossOriginOpenerPolicy and
// CrossOriginEmbedderPolicy set.
GURL starting_page(
https_server()->GetURL("a.com", "/page_with_coop_and_coep.html"));
EXPECT_TRUE(NavigateToURL(shell(), starting_page));
// Open a popup without CrossOriginOpenerPolicy and CrossOriginEmbedderPolicy
// set.
ShellAddedObserver shell_observer;
EXPECT_TRUE(ExecJs(current_frame_host(), "window.open('/title1.html')"));
auto* popup_webcontents =
static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents());
WaitForLoadStop(popup_webcontents);
// The page and its popup should be in different processes even though the
// process limit was reached.
// TODO(clamy, pmeuleman, ahemery): The assert below should be false once we
// fix the process reuse for COOP.
EXPECT_EQ(current_frame_host()->GetProcess(),
popup_webcontents->GetMainFrame()->GetProcess());
// Navigate to a new page without COOP and COEP. Because of process reuse, it
// is placed in the popup process.
GURL final_page(https_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), final_page));
EXPECT_EQ(current_frame_host()->GetProcess(),
popup_webcontents->GetMainFrame()->GetProcess());
}
IN_PROC_BROWSER_TEST_F(CrossOriginOpenerPolicyBrowserTest,
SpeculativeRfhsAndCoop) {
GURL non_coop_page(https_server()->GetURL("/title1.html"));
GURL coop_page(https_server()->GetURL("/page_with_coop_and_coep.html"));
// Non-COOP into non-COOP.
{
// Start on a non COOP page.
EXPECT_TRUE(NavigateToURL(shell(), non_coop_page));
scoped_refptr<SiteInstance> initial_site_instance(
current_frame_host()->GetSiteInstance());
// Navigate to a non COOP page.
TestNavigationManager non_coop_navigation(web_contents(), non_coop_page);
shell()->LoadURL(non_coop_page);
EXPECT_TRUE(non_coop_navigation.WaitForRequestStart());
// TODO(ahemery): RenderDocument will always create a Speculative RFH.
// Update these expectations to test the speculative RFH's SI relation when
// RenderDocument lands.
EXPECT_FALSE(web_contents()
->GetFrameTree()
->root()
->render_manager()
->speculative_frame_host());
non_coop_navigation.WaitForNavigationFinished();
EXPECT_TRUE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance(
initial_site_instance.get()));
EXPECT_EQ(current_frame_host()->cross_origin_opener_policy().value,
network::mojom::CrossOriginOpenerPolicyValue::kUnsafeNone);
}
// Non-COOP into COOP.
{
// Start on a non COOP page.
EXPECT_TRUE(NavigateToURL(shell(), non_coop_page));
scoped_refptr<SiteInstance> initial_site_instance(
current_frame_host()->GetSiteInstance());
// Navigate to a COOP page.
TestNavigationManager coop_navigation(web_contents(), coop_page);
shell()->LoadURL(coop_page);
EXPECT_TRUE(coop_navigation.WaitForRequestStart());
// TODO(ahemery): RenderDocument will always create a Speculative RFH.
// Update these expectations to test the speculative RFH's SI relation when
// RenderDocument lands.
EXPECT_FALSE(web_contents()
->GetFrameTree()
->root()
->render_manager()
->speculative_frame_host());
coop_navigation.WaitForNavigationFinished();
EXPECT_FALSE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance(
initial_site_instance.get()));
EXPECT_EQ(current_frame_host()->cross_origin_opener_policy().value,
network::mojom::CrossOriginOpenerPolicyValue::kSameOrigin);
}
// COOP into non-COOP.
{
// Start on a COOP page.
EXPECT_TRUE(NavigateToURL(shell(), coop_page));
scoped_refptr<SiteInstance> initial_site_instance(
current_frame_host()->GetSiteInstance());
// Navigate to a non COOP page.
TestNavigationManager non_coop_navigation(web_contents(), non_coop_page);
shell()->LoadURL(non_coop_page);
EXPECT_TRUE(non_coop_navigation.WaitForRequestStart());
// TODO(ahemery): RenderDocument will always create a Speculative RFH.
// Update these expectations to test the speculative RFH's SI relation when
// RenderDocument lands.
EXPECT_FALSE(web_contents()
->GetFrameTree()
->root()
->render_manager()
->speculative_frame_host());
non_coop_navigation.WaitForNavigationFinished();
EXPECT_FALSE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance(
initial_site_instance.get()));
EXPECT_EQ(current_frame_host()->cross_origin_opener_policy().value,
network::mojom::CrossOriginOpenerPolicyValue::kUnsafeNone);
}
// COOP into COOP.
{
// Start on a COOP page.
EXPECT_TRUE(NavigateToURL(shell(), coop_page));
scoped_refptr<SiteInstance> initial_site_instance(
current_frame_host()->GetSiteInstance());
// Navigate to a COOP page.
TestNavigationManager coop_navigation(web_contents(), coop_page);
shell()->LoadURL(coop_page);
EXPECT_TRUE(coop_navigation.WaitForRequestStart());
// TODO(ahemery): RenderDocument will always create a Speculative RFH.
// Update these expectations to test the speculative RFH's SI relation when
// RenderDocument lands.
EXPECT_FALSE(web_contents()
->GetFrameTree()
->root()
->render_manager()
->speculative_frame_host());
coop_navigation.WaitForNavigationFinished();
EXPECT_TRUE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance(
initial_site_instance.get()));
EXPECT_EQ(current_frame_host()->cross_origin_opener_policy().value,
network::mojom::CrossOriginOpenerPolicyValue::kSameOrigin);
}
}
} // namespace
} // namespace content