Chromium Code Reviews| Index: content/browser/isolate_top_document_browsertest.cc |
| diff --git a/content/browser/isolate_top_document_browsertest.cc b/content/browser/isolate_top_document_browsertest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ebd0020f27f0abba2b4a195154732ee5adc7e447 |
| --- /dev/null |
| +++ b/content/browser/isolate_top_document_browsertest.cc |
| @@ -0,0 +1,468 @@ |
| +// Copyright 2016 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 <string> |
| + |
| +#include "base/command_line.h" |
| +#include "content/browser/frame_host/frame_tree_node.h" |
| +#include "content/browser/web_contents/web_contents_impl.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_navigation_observer.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 { |
| + |
| +// TODO(nick): Rename this class/file to match the new switch name. |
|
Charlie Reis
2016/03/25 19:47:13
Yep, worth doing.
ncarter (slow)
2016/03/28 22:00:29
Done.
|
| +class IsolateTopDocumentBrowserTest : public ContentBrowserTest { |
| + public: |
| + IsolateTopDocumentBrowserTest() {} |
| + |
| + protected: |
| + std::string DepictFrameTree(FrameTreeNode* node) { |
| + return visualizer_.DepictFrameTree(node); |
| + } |
| + |
| + void SetUpCommandLine(base::CommandLine* command_line) override { |
| + command_line->AppendSwitch(switches::kTopDocumentIsolation); |
| + } |
| + |
| + void SetUpOnMainThread() override { |
| + host_resolver()->AddRule("*", "127.0.0.1"); |
| + ASSERT_TRUE(embedded_test_server()->Start()); |
| + SetupCrossSiteRedirector(embedded_test_server()); |
| + } |
| + |
| + FrameTreeNode* root() { |
| + return static_cast<WebContentsImpl*>(shell()->web_contents()) |
| + ->GetFrameTree() |
| + ->root(); |
| + } |
| + |
| + void GoBack() { |
| + TestNavigationObserver back_load_observer(shell()->web_contents()); |
| + shell()->web_contents()->GetController().GoBack(); |
| + back_load_observer.Wait(); |
| + } |
| + |
| + Shell* OpenPopup(FrameTreeNode* opener, const std::string& url) { |
| + GURL gurl = |
| + opener->current_frame_host()->GetLastCommittedURL().Resolve(url); |
| + return content::OpenPopup(opener->current_frame_host(), gurl, "_blank"); |
| + } |
| + |
| + private: |
| + FrameTreeVisualizer visualizer_; |
| +}; |
| + |
| +IN_PROC_BROWSER_TEST_F(IsolateTopDocumentBrowserTest, SameSiteDeeplyNested) { |
| + GURL main_url(embedded_test_server()->GetURL( |
| + "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))")); |
| + |
| + NavigateToURL(shell(), main_url); |
| + |
| + EXPECT_EQ( |
| + " Site A\n" |
| + " |--Site A\n" |
| + " +--Site A\n" |
| + " |--Site A\n" |
| + " +--Site A\n" |
| + " +--Site A\n" |
| + "Where A = http://a.com/", |
| + DepictFrameTree(root())); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(IsolateTopDocumentBrowserTest, CrossSiteDeeplyNested) { |
| + GURL main_url(embedded_test_server()->GetURL( |
| + "a.com", "/cross_site_iframe_factory.html?a(b(c(d(b))))")); |
| + |
| + NavigateToURL(shell(), main_url); |
| + |
| + EXPECT_EQ( |
| + " Site A ------------ proxies for B\n" |
| + " +--Site B ------- proxies for A\n" |
| + " +--Site B -- proxies for A\n" |
| + " +--Site B -- proxies for A\n" |
| + " +--Site B -- proxies for A\n" |
| + "Where A = http://a.com/\n" |
| + " B = default subframe process", |
| + DepictFrameTree(root())); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(IsolateTopDocumentBrowserTest, ReturnToTopSite) { |
| + GURL main_url(embedded_test_server()->GetURL( |
| + "a.com", "/cross_site_iframe_factory.html?a(b(a(c)))")); |
| + |
| + NavigateToURL(shell(), main_url); |
| + |
| + EXPECT_EQ( |
| + " Site A ------------ proxies for B\n" |
| + " +--Site B ------- proxies for A\n" |
| + " +--Site A -- proxies for B\n" |
| + " +--Site B -- proxies for A\n" |
| + "Where A = http://a.com/\n" |
| + " B = default subframe process", |
| + DepictFrameTree(root())); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(IsolateTopDocumentBrowserTest, NavigateToSubframeSite) { |
| + GURL ab_url(embedded_test_server()->GetURL( |
| + "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| + GURL ba_url(embedded_test_server()->GetURL( |
| + "b.com", "/cross_site_iframe_factory.html?b(a, c)")); |
| + |
| + NavigateToURL(shell(), ab_url); |
| + |
| + EXPECT_EQ( |
| + " Site A ------------ proxies for B\n" |
| + " +--Site B ------- proxies for A\n" |
| + "Where A = http://a.com/\n" |
| + " B = default subframe process", |
| + DepictFrameTree(root())); |
| + |
| + NavigateToURL(shell(), ba_url); |
| + |
| + EXPECT_EQ( |
| + " Site C ------------ proxies for B\n" |
| + " |--Site B ------- proxies for C\n" |
| + " +--Site B ------- proxies for C\n" |
| + "Where B = default subframe process\n" |
| + " C = http://b.com/", |
| + DepictFrameTree(root())); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(IsolateTopDocumentBrowserTest, |
| + NavigateToSubframeSiteWithPopup) { |
| + // A(B) -> B(A), but while a separate B(A) popup exists. |
| + GURL ab_url(embedded_test_server()->GetURL( |
| + "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| + |
| + NavigateToURL(shell(), ab_url); |
| + |
| + EXPECT_EQ( |
| + " Site A ------------ proxies for B\n" |
| + " +--Site B ------- proxies for A\n" |
| + "Where A = http://a.com/\n" |
| + " B = default subframe process", |
| + DepictFrameTree(root())); |
| + |
| + Shell* popup = |
| + OpenPopup(root()->child_at(0), "/cross_site_iframe_factory.html?b(a)"); |
| + FrameTreeNode* popup_root = |
| + static_cast<WebContentsImpl*>(popup->web_contents()) |
| + ->GetFrameTree() |
| + ->root(); |
| + |
| + EXPECT_EQ( |
|
Charlie Reis
2016/03/25 19:47:12
Maybe add a comment about how (at least for now) w
ncarter (slow)
2016/03/28 22:00:29
Done.
|
| + " Site B\n" |
| + " +--Site B\n" |
| + "Where B = default subframe process", |
| + DepictFrameTree(popup_root)); |
| + |
| + GURL ba_url(embedded_test_server()->GetURL( |
| + "b.com", "/cross_site_iframe_factory.html?b(a, c)")); |
| + NavigateToURL(shell(), ba_url); |
| + |
| + EXPECT_EQ( |
|
Charlie Reis
2016/03/25 19:47:13
Let's add a comment here as well, saying we're ok
ncarter (slow)
2016/03/28 22:00:29
Done.
|
| + " Site B\n" |
| + " +--Site B\n" |
| + "Where B = default subframe process", |
| + DepictFrameTree(popup_root)); |
| + EXPECT_EQ( |
| + " Site C ------------ proxies for B\n" |
| + " |--Site B ------- proxies for C\n" |
| + " +--Site B ------- proxies for C\n" |
| + "Where B = default subframe process\n" |
| + " C = http://b.com/", |
| + DepictFrameTree(root())); |
| + |
| + // Navigate the popup to a new site. |
| + GURL c_url(embedded_test_server()->GetURL( |
| + "c.com", "/cross_site_iframe_factory.html?c(c, c, c, c)")); |
| + NavigateToURL(popup, c_url); |
| + EXPECT_EQ( |
| + " Site D ------------ proxies for B\n" |
| + " |--Site D ------- proxies for B\n" |
| + " |--Site D ------- proxies for B\n" |
| + " |--Site D ------- proxies for B\n" |
| + " +--Site D ------- proxies for B\n" |
| + "Where B = default subframe process\n" |
| + " D = http://c.com/", |
| + DepictFrameTree(popup_root)); |
| + NavigateToURL(shell(), c_url); |
| + EXPECT_EQ( |
| + " Site D\n" |
| + " |--Site D\n" |
| + " |--Site D\n" |
| + " |--Site D\n" |
| + " +--Site D\n" |
| + "Where D = http://c.com/", |
| + DepictFrameTree(popup_root)); |
| + EXPECT_EQ( |
| + " Site D\n" |
| + " |--Site D\n" |
| + " |--Site D\n" |
| + " |--Site D\n" |
| + " +--Site D\n" |
| + "Where D = http://c.com/", |
| + DepictFrameTree(root())); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(IsolateTopDocumentBrowserTest, |
| + NavigateToSubframeSiteWithPopup2) { |
| + // A(B, C) -> C(A, B), but while a separate C(A) popup exists. |
| + GURL abb_url(embedded_test_server()->GetURL( |
| + "a.com", "/cross_site_iframe_factory.html?a(b, b)")); |
| + |
| + NavigateToURL(shell(), abb_url); |
| + |
| + EXPECT_EQ( |
| + " Site A ------------ proxies for B\n" |
| + " |--Site B ------- proxies for A\n" |
| + " +--Site B ------- proxies for A\n" |
| + "Where A = http://a.com/\n" |
| + " B = default subframe process", |
| + DepictFrameTree(root())); |
| + |
| + // A(B, B) -> A(B, C) |
| + GURL c_url(embedded_test_server()->GetURL( |
| + "c.com", "/cross_site_iframe_factory.html?c")); |
| + NavigateFrameToURL(root()->child_at(1), c_url); |
| + |
| + EXPECT_EQ( |
| + " Site A ------------ proxies for B\n" |
| + " |--Site B ------- proxies for A\n" |
| + " +--Site B ------- proxies for A\n" |
| + "Where A = http://a.com/\n" |
| + " B = default subframe process", |
| + DepictFrameTree(root())); |
| + |
| + // Subframe C creates C(A) popup. |
| + Shell* popup = |
| + OpenPopup(root()->child_at(1), "/cross_site_iframe_factory.html?c(a)"); |
| + |
| + FrameTreeNode* popup_root = |
| + static_cast<WebContentsImpl*>(popup->web_contents()) |
| + ->GetFrameTree() |
| + ->root(); |
| + |
| + // The popup must stay in the default subframe process. |
| + EXPECT_EQ( |
| + " Site B\n" |
| + " +--Site B\n" |
| + "Where B = default subframe process", |
| + DepictFrameTree(popup_root)); |
| + |
| + // Because of the existing popup, this navigation needs to stay in the 3rd |
| + // party process as well. |
|
Charlie Reis
2016/03/25 19:47:13
s/3rd party/subframe/
Also, this comment disagree
ncarter (slow)
2016/03/28 22:00:29
Done.
I also clarified what the difference is bet
|
| + GURL ba_url(embedded_test_server()->GetURL( |
|
Charlie Reis
2016/03/25 19:47:12
nit: ca_url?
ncarter (slow)
2016/03/28 22:00:28
Done.
|
| + "c.com", "/cross_site_iframe_factory.html?c(a, b)")); |
| + NavigateToURL(shell(), ba_url); |
| + |
| + // TODO(nick): This c.com navigation currently breaks out of the default |
| + // subframe process, even though that process houses a c.com pop-up. Bug or |
| + // feature? |
|
Charlie Reis
2016/03/25 19:47:12
I think this is probably ok for now. The subframe
ncarter (slow)
2016/03/28 22:00:28
Done.
|
| + EXPECT_EQ( |
| + " Site C ------------ proxies for B\n" |
| + " |--Site B ------- proxies for C\n" |
| + " +--Site B ------- proxies for C\n" |
| + "Where B = default subframe process\n" |
| + " C = http://c.com/", |
| + DepictFrameTree(root())); |
| + |
| + // c.com popup should remain where it was, in the subframe process. |
|
Charlie Reis
2016/03/25 19:47:12
Is there a reason to check this? We haven't chang
ncarter (slow)
2016/03/28 22:00:29
Yes. Proxies could have been created.
Charlie Reis
2016/03/29 17:17:12
Acknowledged.
|
| + EXPECT_EQ( |
| + " Site B\n" |
| + " +--Site B\n" |
| + "Where B = default subframe process", |
| + DepictFrameTree(popup_root)); |
| + EXPECT_EQ(nullptr, popup_root->opener()); |
| + |
| + // If we navigate the popup to a new site, it ought to transfer processes. |
| + GURL d_url(embedded_test_server()->GetURL( |
| + "d.com", "/cross_site_iframe_factory.html?d")); |
| + NavigateToURL(popup, d_url); |
| + EXPECT_EQ( |
| + " Site D ------------ proxies for B\n" |
| + "Where B = default subframe process\n" |
| + " D = http://d.com/", |
| + DepictFrameTree(popup_root)); |
| + NavigateToURL(shell(), d_url); |
| + EXPECT_EQ( |
| + " Site D\n" |
| + "Where D = http://d.com/", |
| + DepictFrameTree(popup_root)); |
| + EXPECT_EQ( |
| + " Site D\n" |
| + "Where D = http://d.com/", |
| + DepictFrameTree(root())); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(IsolateTopDocumentBrowserTest, FramesForSitesInHistory) { |
| + // First, do a series of navigations. |
| + NavigateToURL(shell(), embedded_test_server()->GetURL( |
| + "a.com", "/cross_site_iframe_factory.html?a")); |
| + EXPECT_EQ( |
| + " Site A\n" |
| + "Where A = http://a.com/", |
| + DepictFrameTree(root())); |
| + NavigateToURL(shell(), embedded_test_server()->GetURL( |
| + "b.com", "/cross_site_iframe_factory.html?b")); |
| + |
| + // TODO(nick): Without --isolate-top-document, we would not swap processes |
|
Charlie Reis
2016/03/25 19:47:12
nit: --top-document-isolation, here and below.
ncarter (slow)
2016/03/28 22:00:29
Done.
|
| + // for these cross-site navigations. What should the behavior be here, for |
| + // --isolate-top-document? |
|
Charlie Reis
2016/03/25 19:47:12
I don't follow. We do swap processes for top-leve
ncarter (slow)
2016/03/28 22:00:29
My original prototype was based on making the top
|
| + EXPECT_EQ( |
| + " Site B\n" |
| + "Where B = http://b.com/", |
| + DepictFrameTree(root())); |
| + NavigateToURL(shell(), embedded_test_server()->GetURL( |
| + "c.com", "/cross_site_iframe_factory.html?c")); |
| + EXPECT_EQ( |
| + " Site C\n" |
| + "Where C = http://c.com/", |
| + DepictFrameTree(root())); |
| + |
| + // Now, navigate to a fourth site with iframes to the sites in the history. |
| + NavigateToURL(shell(), |
| + embedded_test_server()->GetURL( |
| + "d.com", "/cross_site_iframe_factory.html?d(a,b,c)")); |
| + |
| + // TODO(nick): These subframes ought to end up in the third-party process, |
|
Xiaocheng
2016/03/25 08:30:52
nit: This TODO can be removed now.
ncarter (slow)
2016/03/28 22:00:29
Done.
|
| + // but because we cache the SiteInstances in the navigation entries, we |
| + // can't place these subframes into the siteinstance for 3rd party frames. |
| + EXPECT_EQ( |
| + " Site D ------------ proxies for E\n" |
| + " |--Site E ------- proxies for D\n" |
| + " |--Site E ------- proxies for D\n" |
| + " +--Site E ------- proxies for D\n" |
| + "Where D = http://d.com/\n" |
| + " E = default subframe process", |
| + DepictFrameTree(root())); |
| + |
| + // Now try going back. |
| + GoBack(); |
| + EXPECT_EQ( |
| + " Site C\n" |
| + "Where C = http://c.com/", |
| + DepictFrameTree(root())); |
| + GoBack(); |
| + EXPECT_EQ( |
| + " Site B\n" |
| + "Where B = http://b.com/", |
| + DepictFrameTree(root())); |
| + GoBack(); |
| + EXPECT_EQ( |
| + " Site A\n" |
| + "Where A = http://a.com/", |
| + DepictFrameTree(root())); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(IsolateTopDocumentBrowserTest, CrossSiteAtLevelTwo) { |
| + GURL main_url(embedded_test_server()->GetURL( |
| + "a.com", "/cross_site_iframe_factory.html?a(a(b, a))")); |
| + |
| + NavigateToURL(shell(), main_url); |
| + |
| + EXPECT_EQ( |
| + " Site A ------------ proxies for B\n" |
| + " +--Site A ------- proxies for B\n" |
| + " |--Site B -- proxies for A\n" |
| + " +--Site A -- proxies for B\n" |
| + "Where A = http://a.com/\n" |
| + " B = default subframe process", |
| + DepictFrameTree(root())); |
| + |
| + GURL c_url(embedded_test_server()->GetURL( |
| + "c.com", "/cross_site_iframe_factory.html?c")); |
| + NavigateFrameToURL(root()->child_at(0)->child_at(1), c_url); |
| + |
| + // This navigation should complete using the existing 3rd party SiteInstance. |
| + EXPECT_EQ( |
| + " Site A ------------ proxies for B\n" |
| + " +--Site A ------- proxies for B\n" |
| + " |--Site B -- proxies for A\n" |
| + " +--Site B -- proxies for A\n" |
| + "Where A = http://a.com/\n" |
| + " B = default subframe process", |
| + DepictFrameTree(root())); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(IsolateTopDocumentBrowserTest, PopupAndRedirection) { |
| + GURL main_url(embedded_test_server()->GetURL( |
| + "page.com", "/cross_site_iframe_factory.html?page(adnetwork)")); |
| + |
| + // User opens page on page.com which contains a subframe from adnetwork.com |
|
Charlie Reis
2016/03/25 19:47:12
nit: End with period.
ncarter (slow)
2016/03/28 22:00:29
Done.
|
| + NavigateToURL(shell(), main_url); |
| + |
| + EXPECT_EQ( |
| + " Site A ------------ proxies for B\n" |
| + " +--Site B ------- proxies for A\n" |
| + "Where A = http://page.com/\n" |
| + " B = default subframe process", |
| + DepictFrameTree(root())); |
| + |
| + GURL ad_url(embedded_test_server()->GetURL( |
| + "ad.com", "/cross_site_iframe_factory.html?ad")); |
| + |
| + // adnetwork.com retrieves an ad from advertiser (ad.com) and redirects the |
| + // subframe to C. |
|
Xiaocheng
2016/03/25 08:30:52
nit: C -> ad.com
ncarter (slow)
2016/03/28 22:00:29
Done.
|
| + // TODO(nick): Make this a renderer-inititated navigation. |
|
Charlie Reis
2016/03/25 19:47:13
Yep, let's do this. Shouldn't change the outcome,
ncarter (slow)
2016/03/28 22:00:29
Done.
|
| + NavigateFrameToURL(root()->child_at(0), ad_url); |
| + |
| + // The subframe still uses the same third-party SiteInstance after navigation. |
| + EXPECT_EQ( |
| + " Site A ------------ proxies for B\n" |
| + " +--Site B ------- proxies for A\n" |
| + "Where A = http://page.com/\n" |
| + " B = default subframe process", |
| + DepictFrameTree(root())); |
| + |
| + // User clicks the ad in the subframe, which opens a popup on the ad |
| + // platform's domain. |
|
Charlie Reis
2016/03/25 19:47:12
s/platform/network/
ncarter (slow)
2016/03/28 22:00:28
Done.
|
| + GURL popup_url(embedded_test_server()->GetURL( |
| + "adnetwork.com", "/cross_site_iframe_factory.html?adnetwork")); |
| + Shell* popup = OpenPopup(root()->child_at(0), popup_url.spec()); |
| + |
| + FrameTreeNode* popup_root = |
| + static_cast<WebContentsImpl*>(popup->web_contents()) |
| + ->GetFrameTree() |
| + ->root(); |
| + |
| + EXPECT_EQ( |
|
Charlie Reis
2016/03/25 19:47:12
Let's add a comment about how we think it's ok for
ncarter (slow)
2016/03/28 22:00:29
Done.
|
| + " Site A ------------ proxies for B C\n" |
| + " +--Site B ------- proxies for A C\n" |
| + "Where A = http://page.com/\n" |
| + " B = default subframe process\n" |
| + " C = http://adnetwork.com/", |
| + DepictFrameTree(root())); |
| + EXPECT_EQ( |
| + " Site C ------------ proxies for B\n" |
| + "Where B = default subframe process\n" |
| + " C = http://adnetwork.com/", |
| + DepictFrameTree(popup_root)); |
| + |
| + // The popup redirects itself to the advertiser's website (ad.com). |
| + NavigateToURL(popup, ad_url); |
| + |
| + // This must join its same-site opener, in the default subframe SiteInstance. |
|
Charlie Reis
2016/03/25 19:47:12
Wow, I'm impressed this passes. That's a cool con
ncarter (slow)
2016/03/28 22:00:29
Acknowledged.
|
| + EXPECT_EQ( |
| + " Site A ------------ proxies for B\n" |
| + " +--Site B ------- proxies for A\n" |
| + "Where A = http://page.com/\n" |
| + " B = default subframe process", |
| + DepictFrameTree(root())); |
| + EXPECT_EQ( |
| + " Site B\n" |
| + "Where B = default subframe process", |
| + DepictFrameTree(popup_root)); |
| +} |
| + |
| +} // namespace content |