Chromium Code Reviews| Index: content/browser/isolated_origin_browsertest.cc |
| diff --git a/content/browser/isolated_origin_browsertest.cc b/content/browser/isolated_origin_browsertest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..6e9db5d514a6932a702af068fec3512a5b149929 |
| --- /dev/null |
| +++ b/content/browser/isolated_origin_browsertest.cc |
| @@ -0,0 +1,232 @@ |
| +// Copyright 2017 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 "content/browser/site_instance_impl.h" |
| +#include "content/browser/web_contents/web_contents_impl.h" |
| +#include "content/public/browser/render_process_host.h" |
| +#include "content/public/common/content_switches.h" |
| +#include "content/public/test/browser_test_utils.h" |
| +#include "content/public/test/content_browser_test.h" |
| +#include "content/public/test/content_browser_test_utils.h" |
| +#include "content/public/test/test_frame_navigation_observer.h" |
| +#include "content/public/test/test_navigation_observer.h" |
| +#include "content/public/test/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 "net/test/embedded_test_server/embedded_test_server.h" |
| +#include "url/gurl.h" |
| + |
| +namespace content { |
| + |
| +class IsolatedOriginTest : public ContentBrowserTest { |
| + public: |
| + IsolatedOriginTest() {} |
| + ~IsolatedOriginTest() override {} |
| + |
| + void SetUpCommandLine(base::CommandLine* command_line) override { |
| + ASSERT_TRUE(embedded_test_server()->InitializeAndListen()); |
| + |
| + std::string origin_list = |
| + embedded_test_server()->GetURL("isolated.foo.com", "/").spec() + "," + |
| + embedded_test_server()->GetURL("isolated.bar.com", "/").spec(); |
| + command_line->AppendSwitchASCII(switches::kIsolateOrigins, origin_list); |
| + } |
| + |
| + void SetUpOnMainThread() override { |
| + host_resolver()->AddRule("*", "127.0.0.1"); |
| + embedded_test_server()->StartAcceptingConnections(); |
| + } |
| + |
| + WebContentsImpl* web_contents() const { |
| + return static_cast<WebContentsImpl*>(shell()->web_contents()); |
| + } |
| +}; |
| + |
| +// Check that navigating a main frame from an non-isolated origin to an |
| +// isolated origin and vice versa swaps processes and uses a new SiteInstance, |
| +// both for browser-initiated and renderer-initiated navigations. |
| +IN_PROC_BROWSER_TEST_F(IsolatedOriginTest, MainFrameNavigation) { |
| + GURL unisolated_url( |
| + embedded_test_server()->GetURL("www.foo.com", "/title1.html")); |
| + GURL isolated_url( |
| + embedded_test_server()->GetURL("isolated.foo.com", "/title2.html")); |
| + |
| + EXPECT_TRUE(NavigateToURL(shell(), unisolated_url)); |
| + |
| + // Open a same-site popup to keep the www.foo.com process alive. |
| + Shell* popup = OpenPopup(shell(), GURL(url::kAboutBlankURL), "foo"); |
| + SiteInstance* unisolated_instance = |
| + popup->web_contents()->GetMainFrame()->GetSiteInstance(); |
| + |
| + // Navigate to an isolated origin and ensure that this ends up in a new |
|
Charlie Reis
2017/05/05 23:18:51
Let's clarify this is a browser-initiated navigati
alexmos
2017/05/16 17:26:37
Done.
|
| + // process and SiteInstance for isolated.foo.com. |
| + EXPECT_TRUE(NavigateToURL(shell(), isolated_url)); |
| + |
| + scoped_refptr<SiteInstance> isolated_instance = |
| + web_contents()->GetSiteInstance(); |
| + EXPECT_NE(isolated_instance, unisolated_instance); |
| + EXPECT_NE(web_contents()->GetMainFrame()->GetProcess(), |
| + popup->web_contents()->GetMainFrame()->GetProcess()); |
| + |
| + // The site URL for isolated.foo.com should be the full origin rather than |
| + // eTLD+1. |
| + EXPECT_EQ(isolated_url.GetOrigin(), isolated_instance->GetSiteURL()); |
| + |
| + // Navigate to www.foo.com. This should end up in the |popup|'s process. |
|
Charlie Reis
2017/05/05 23:18:51
And that this is a renderer-initiated navigation.
alexmos
2017/05/16 17:26:37
Done.
|
| + { |
| + TestNavigationObserver observer(web_contents()); |
| + EXPECT_TRUE(ExecuteScript( |
| + web_contents(), "location.href = '" + unisolated_url.spec() + "'")); |
| + observer.Wait(); |
| + } |
| + |
| + EXPECT_EQ(web_contents()->GetSiteInstance(), unisolated_instance); |
| + EXPECT_EQ(web_contents()->GetMainFrame()->GetProcess(), |
| + popup->web_contents()->GetMainFrame()->GetProcess()); |
| + |
| + // Go back and verify that we end up in an isolated process once again. |
| + TestNavigationObserver back_observer(web_contents()); |
| + web_contents()->GetController().GoBack(); |
| + back_observer.Wait(); |
| + |
| + EXPECT_EQ(web_contents()->GetSiteInstance(), isolated_instance); |
|
Charlie Reis
2017/05/05 23:18:51
nit: Swap order (expected, actual)
alexmos
2017/05/16 17:26:37
Done.
|
| + EXPECT_NE(web_contents()->GetMainFrame()->GetProcess(), |
| + popup->web_contents()->GetMainFrame()->GetProcess()); |
| + |
| + // Navigate to another isolated origin and ensure there is a different |
| + // isolated process. |
| + GURL second_isolated_url( |
| + embedded_test_server()->GetURL("isolated.bar.com", "/title3.html")); |
| + { |
| + TestNavigationObserver observer(web_contents()); |
| + EXPECT_TRUE( |
| + ExecuteScript(web_contents(), |
| + "location.href = '" + second_isolated_url.spec() + "'")); |
| + observer.Wait(); |
| + } |
| + |
| + EXPECT_EQ(second_isolated_url.GetOrigin(), |
| + web_contents()->GetSiteInstance()->GetSiteURL()); |
| + EXPECT_NE(web_contents()->GetSiteInstance(), isolated_instance); |
| + EXPECT_NE(web_contents()->GetSiteInstance(), unisolated_instance); |
| +} |
| + |
| +// Check that opening a popup for an isolated origin puts it into a new process |
| +// and its own SiteInstance. |
| +IN_PROC_BROWSER_TEST_F(IsolatedOriginTest, Popup) { |
| + GURL unisolated_url( |
| + embedded_test_server()->GetURL("foo.com", "/title1.html")); |
| + GURL isolated_url( |
| + embedded_test_server()->GetURL("isolated.foo.com", "/title2.html")); |
| + |
| + EXPECT_TRUE(NavigateToURL(shell(), unisolated_url)); |
| + |
| + // Open a popup to a URL with an isolated origin and ensure that there was a |
| + // process swap. |
| + Shell* popup = OpenPopup(shell(), isolated_url, "foo"); |
| + |
| + EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
| + popup->web_contents()->GetSiteInstance()); |
| + |
| + // The popup's site URL should match the full isolated origin. |
| + EXPECT_EQ(isolated_url.GetOrigin(), |
| + popup->web_contents()->GetSiteInstance()->GetSiteURL()); |
| + |
| + // Now open a second popup from an isolated origin to a URL with an |
| + // unisolated origin and ensure that there was another process swap. |
| + Shell* popup2 = OpenPopup(popup, unisolated_url, "bar"); |
| + EXPECT_EQ(shell()->web_contents()->GetSiteInstance(), |
| + popup2->web_contents()->GetSiteInstance()); |
| + EXPECT_NE(popup->web_contents()->GetSiteInstance(), |
| + popup2->web_contents()->GetSiteInstance()); |
| +} |
| + |
| +// Check that navigating a subframe to an isolated origin puts the subframe |
| +// into an OOPIF and its own SiteInstance. Also check that the isolated |
| +// frame's subframes also end up in correct SiteInstance. |
| +IN_PROC_BROWSER_TEST_F(IsolatedOriginTest, Subframe) { |
| + GURL top_url( |
| + embedded_test_server()->GetURL("www.foo.com", "/page_with_iframe.html")); |
| + EXPECT_TRUE(NavigateToURL(shell(), top_url)); |
| + |
| + GURL isolated_url(embedded_test_server()->GetURL("isolated.foo.com", |
| + "/page_with_iframe.html")); |
| + |
| + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| + FrameTreeNode* child = root->child_at(0); |
| + |
| + NavigateIframeToURL(web_contents(), "test_iframe", isolated_url); |
| + EXPECT_EQ(child->current_url(), isolated_url); |
| + |
| + // Verify that the child frame is an OOPIF with a different SiteInstance. |
| + EXPECT_NE(web_contents()->GetSiteInstance(), |
| + child->current_frame_host()->GetSiteInstance()); |
| + EXPECT_TRUE(child->current_frame_host()->IsCrossProcessSubframe()); |
| + EXPECT_EQ(isolated_url.GetOrigin(), |
| + child->current_frame_host()->GetSiteInstance()->GetSiteURL()); |
| + |
| + // Verify that the isolated frame's subframe (which starts out at a relative |
| + // path) is kept in the isolated parent's SiteInstance. |
| + FrameTreeNode* grandchild = child->child_at(0); |
| + EXPECT_EQ(child->current_frame_host()->GetSiteInstance(), |
| + grandchild->current_frame_host()->GetSiteInstance()); |
| + |
| + // Navigating the grandchild to www.foo.com should put it into the top |
| + // frame's SiteInstance. |
| + GURL non_isolated_url( |
| + embedded_test_server()->GetURL("www.foo.com", "/title3.html")); |
| + TestFrameNavigationObserver observer(grandchild); |
| + EXPECT_TRUE(ExecuteScript( |
| + grandchild, "location.href = '" + non_isolated_url.spec() + "';")); |
| + observer.Wait(); |
| + EXPECT_EQ(grandchild->current_url(), non_isolated_url); |
| + |
| + EXPECT_EQ(root->current_frame_host()->GetSiteInstance(), |
| + grandchild->current_frame_host()->GetSiteInstance()); |
| + EXPECT_NE(child->current_frame_host()->GetSiteInstance(), |
| + grandchild->current_frame_host()->GetSiteInstance()); |
| +} |
| + |
| +// Check that when an non-isolated origin foo.com embeds a subframe from an |
| +// isolated origin, which then navigates to a non-isolated origin bar.com, |
| +// bar.com goes back to the main frame's SiteInstance. See |
| +// https://crbug.com/711006. |
| +IN_PROC_BROWSER_TEST_F(IsolatedOriginTest, |
| + NoOOPIFWhenIsolatedOriginNavigatesToNonIsolatedOrigin) { |
| + if (AreAllSitesIsolatedForTesting()) |
| + return; |
| + |
| + GURL top_url( |
| + embedded_test_server()->GetURL("www.foo.com", "/page_with_iframe.html")); |
| + EXPECT_TRUE(NavigateToURL(shell(), top_url)); |
| + |
| + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| + FrameTreeNode* child = root->child_at(0); |
| + |
| + GURL isolated_url(embedded_test_server()->GetURL("isolated.foo.com", |
| + "/page_with_iframe.html")); |
| + |
| + NavigateIframeToURL(web_contents(), "test_iframe", isolated_url); |
| + EXPECT_EQ(child->current_url(), isolated_url); |
| + |
| + // Verify that the child frame is an OOPIF with a different SiteInstance. |
| + EXPECT_NE(web_contents()->GetSiteInstance(), |
| + child->current_frame_host()->GetSiteInstance()); |
| + EXPECT_TRUE(child->current_frame_host()->IsCrossProcessSubframe()); |
| + EXPECT_EQ(isolated_url.GetOrigin(), |
| + child->current_frame_host()->GetSiteInstance()->GetSiteURL()); |
| + |
| + // Navigate the child frame cross-site, but to a non-isolated origin. When |
| + // not in --site-per-process, this should bring the subframe back into the |
| + // main frame's SiteInstance. |
| + GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html")); |
| + EXPECT_FALSE(SiteInstanceImpl::IsIsolatedOrigin(url::Origin(bar_url))); |
| + NavigateIframeToURL(web_contents(), "test_iframe", bar_url); |
| + EXPECT_EQ(web_contents()->GetSiteInstance(), |
| + child->current_frame_host()->GetSiteInstance()); |
| + EXPECT_FALSE(child->current_frame_host()->IsCrossProcessSubframe()); |
| +} |
| + |
| +} // namespace content |