Move content/browser/frame_host/* over to content/browser/renderer_host/
We allow these directories to work together now and have decided to
merge them to simplify understanding the code relationships.
Add forwarding headers in content/browser/frame_host/ to make this
transition easier. PRESUBMIT and tricum errors are not addressed in this
CL as it is just moving code.
[email protected]
Bug: 1091083
Change-Id: Id112b1eb4c8de0ac074a593f495dd79f4d02105d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2401303
Commit-Queue: danakj <[email protected]>
Reviewed-by: Avi Drissman <[email protected]>
Auto-Submit: danakj <[email protected]>
Cr-Commit-Position: refs/heads/master@{#805452}
diff --git a/content/browser/renderer_host/embedding_token_browsertest.cc b/content/browser/renderer_host/embedding_token_browsertest.cc
new file mode 100644
index 0000000..acc9c56e
--- /dev/null
+++ b/content/browser/renderer_host/embedding_token_browsertest.cc
@@ -0,0 +1,337 @@
+// 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 "base/unguessable_token.h"
+#include "content/browser/renderer_host/frame_tree.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/content_navigation_policy.h"
+#include "content/public/test/browser_test.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_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 "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+class EmbeddingTokenBrowserTest : public ContentBrowserTest {
+ public:
+ EmbeddingTokenBrowserTest() = default;
+
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ scoped_feature_list_.InitAndEnableFeatureWithParameters(
+ features::kBackForwardCache,
+ {
+ // Set a very long TTL before expiration (longer than the test
+ // timeout) so tests that are expecting deletion don't pass when
+ // they shouldn't.
+ {"TimeToLiveInBackForwardCacheInSeconds", "3600"},
+ });
+ ContentBrowserTest::SetUpCommandLine(command_line);
+ IsolateAllSitesForTesting(command_line);
+ }
+
+ void SetUpOnMainThread() override {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ SetupCrossSiteRedirector(embedded_test_server());
+ ASSERT_TRUE(embedded_test_server()->Start());
+ }
+
+ WebContents* web_contents() { return shell()->web_contents(); }
+
+ RenderFrameHostImpl* top_frame_host() {
+ return static_cast<RenderFrameHostImpl*>(web_contents()->GetMainFrame());
+ }
+
+ EmbeddingTokenBrowserTest(const EmbeddingTokenBrowserTest&) = delete;
+ EmbeddingTokenBrowserTest& operator=(const EmbeddingTokenBrowserTest&) =
+ delete;
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(EmbeddingTokenBrowserTest, EmbeddingTokenOnMainFrame) {
+ GURL a_url = embedded_test_server()->GetURL("a.com", "/site_isolation/");
+ GURL b_url = embedded_test_server()->GetURL("b.com", "/site_isolation/");
+ // Starts without an embedding token.
+ EXPECT_FALSE(top_frame_host()->GetEmbeddingToken().has_value());
+
+ // Embedding tokens should get added to the main frame.
+ EXPECT_TRUE(NavigateToURL(shell(), a_url.Resolve("blank.html")));
+ EXPECT_TRUE(top_frame_host()->GetEmbeddingToken().has_value());
+ auto first_token = top_frame_host()->GetEmbeddingToken().value();
+
+ EXPECT_TRUE(NavigateToURL(shell(), b_url.Resolve("blank.html")));
+ EXPECT_TRUE(top_frame_host()->GetEmbeddingToken().has_value());
+ EXPECT_NE(top_frame_host()->GetEmbeddingToken().value(), first_token);
+}
+
+IN_PROC_BROWSER_TEST_F(EmbeddingTokenBrowserTest,
+ EmbeddingTokensAddedToCrossDocumentIFrames) {
+ EXPECT_TRUE(NavigateToURL(
+ shell(), embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b(a),c,a)")));
+
+ ASSERT_EQ(3U, top_frame_host()->child_count());
+ EXPECT_TRUE(top_frame_host()->GetEmbeddingToken().has_value());
+ auto top_token = top_frame_host()->GetEmbeddingToken().value();
+
+ // Child 0 (b) should have an embedding token.
+ auto child_0_token =
+ top_frame_host()->child_at(0)->current_frame_host()->GetEmbeddingToken();
+ ASSERT_TRUE(child_0_token.has_value());
+ EXPECT_NE(base::UnguessableToken::Null(), child_0_token);
+ EXPECT_NE(top_token, child_0_token);
+
+ // Child 0 (a) of Child 0 (b) should have an embedding token.
+ ASSERT_EQ(1U, top_frame_host()->child_at(0)->child_count());
+ auto child_0_0_token = top_frame_host()
+ ->child_at(0)
+ ->child_at(0)
+ ->current_frame_host()
+ ->GetEmbeddingToken();
+ ASSERT_TRUE(child_0_0_token.has_value());
+ EXPECT_NE(base::UnguessableToken::Null(), child_0_0_token);
+ EXPECT_NE(top_token, child_0_0_token);
+ EXPECT_NE(child_0_token, child_0_0_token);
+
+ // Child 1 (c) should have an embedding token.
+ auto child_1_token =
+ top_frame_host()->child_at(1)->current_frame_host()->GetEmbeddingToken();
+ ASSERT_TRUE(child_1_token.has_value());
+ EXPECT_NE(base::UnguessableToken::Null(), child_1_token);
+ EXPECT_NE(top_token, child_1_token);
+ EXPECT_NE(child_0_token, child_1_token);
+ EXPECT_NE(child_0_0_token, child_1_token);
+
+ // Child 2 (a) should have an embedding token.
+ auto child_2_token =
+ top_frame_host()->child_at(2)->current_frame_host()->GetEmbeddingToken();
+ ASSERT_TRUE(child_2_token.has_value());
+ EXPECT_NE(base::UnguessableToken::Null(), child_2_token);
+ EXPECT_NE(top_token, child_2_token);
+ EXPECT_NE(child_0_token, child_2_token);
+ EXPECT_NE(child_0_0_token, child_2_token);
+
+ // TODO(ckitagawa): Somehow assert that the parent and child have matching
+ // embedding tokens in parent HTMLOwnerElement and child LocalFrame.
+}
+
+IN_PROC_BROWSER_TEST_F(EmbeddingTokenBrowserTest,
+ EmbeddingTokenSwapsOnCrossDocumentNavigation) {
+ EXPECT_TRUE(NavigateToURL(
+ shell(), embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b)")));
+
+ ASSERT_EQ(1U, top_frame_host()->child_count());
+ EXPECT_TRUE(top_frame_host()->GetEmbeddingToken().has_value());
+ auto top_token = top_frame_host()->GetEmbeddingToken().value();
+
+ // Child 0 (b) should have an embedding token.
+ RenderFrameHost* target = top_frame_host()->child_at(0)->current_frame_host();
+ auto child_0_token = target->GetEmbeddingToken();
+ ASSERT_TRUE(child_0_token.has_value());
+ EXPECT_NE(base::UnguessableToken::Null(), child_0_token);
+ EXPECT_NE(top_token, child_0_token);
+
+ // Navigate child 0 (b) to same-site the token should swap.
+ NavigateIframeToURL(shell()->web_contents(), "child-0",
+ embedded_test_server()
+ ->GetURL("b.com", "/site_isolation/")
+ .Resolve("blank.html"));
+ auto same_site_new_child_0_token =
+ top_frame_host()->child_at(0)->current_frame_host()->GetEmbeddingToken();
+ ASSERT_TRUE(same_site_new_child_0_token.has_value());
+ EXPECT_NE(base::UnguessableToken::Null(), same_site_new_child_0_token);
+ EXPECT_NE(top_token, same_site_new_child_0_token);
+ EXPECT_NE(child_0_token, same_site_new_child_0_token);
+
+ // Navigate child 0 (b) to another site (cross-process) the token should swap.
+ {
+ RenderFrameDeletedObserver deleted_observer(target);
+ NavigateIframeToURL(shell()->web_contents(), "child-0",
+ embedded_test_server()
+ ->GetURL("c.com", "/site_isolation/")
+ .Resolve("blank.html"));
+ deleted_observer.WaitUntilDeleted();
+ }
+ auto new_site_child_0_token =
+ top_frame_host()->child_at(0)->current_frame_host()->GetEmbeddingToken();
+ ASSERT_TRUE(same_site_new_child_0_token.has_value());
+ EXPECT_NE(base::UnguessableToken::Null(), new_site_child_0_token);
+ EXPECT_NE(top_token, new_site_child_0_token);
+ EXPECT_NE(child_0_token, new_site_child_0_token);
+ EXPECT_NE(same_site_new_child_0_token, new_site_child_0_token);
+
+ // TODO(ckitagawa): Somehow assert that the parent and child have matching
+ // embedding tokens in parent HTMLOwnerElement and child LocalFrame.
+}
+
+IN_PROC_BROWSER_TEST_F(
+ EmbeddingTokenBrowserTest,
+ EmbeddingTokenNotChangedOnSubframeSameDocumentNavigation) {
+ EXPECT_TRUE(NavigateToURL(
+ shell(), embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(a)")));
+
+ ASSERT_EQ(1U, top_frame_host()->child_count());
+ EXPECT_TRUE(top_frame_host()->GetEmbeddingToken().has_value());
+ auto top_token = top_frame_host()->GetEmbeddingToken().value();
+
+ // Child 0 (a) should have an embedding token.
+ RenderFrameHost* target = top_frame_host()->child_at(0)->current_frame_host();
+ auto child_0_token = target->GetEmbeddingToken();
+ ASSERT_TRUE(child_0_token.has_value());
+ EXPECT_NE(base::UnguessableToken::Null(), child_0_token);
+ EXPECT_NE(top_token, child_0_token);
+
+ auto b_url = embedded_test_server()->GetURL("b.com", "/site_isolation/");
+ // Navigate child 0 to another site (cross-process) a token should be created.
+ {
+ RenderFrameDeletedObserver deleted_observer(
+ top_frame_host()->child_at(0)->current_frame_host());
+ NavigateIframeToURL(web_contents(), "child-0", b_url.Resolve("blank.html"));
+ deleted_observer.WaitUntilDeleted();
+ }
+
+ // Child 0 (b) should have a new embedding token.
+ auto new_child_0_token =
+ top_frame_host()->child_at(0)->current_frame_host()->GetEmbeddingToken();
+ ASSERT_TRUE(child_0_token.has_value());
+ EXPECT_NE(base::UnguessableToken::Null(), new_child_0_token);
+ EXPECT_NE(top_token, new_child_0_token);
+ EXPECT_NE(child_0_token, new_child_0_token);
+
+ // Navigate child 0 (b) to same document the token should not swap.
+ NavigateIframeToURL(web_contents(), "child-0",
+ b_url.Resolve("blank.html#foo"));
+ auto same_document_new_child_0_token =
+ top_frame_host()->child_at(0)->current_frame_host()->GetEmbeddingToken();
+ ASSERT_TRUE(same_document_new_child_0_token.has_value());
+ EXPECT_EQ(new_child_0_token, same_document_new_child_0_token);
+
+ // TODO(ckitagawa): Somehow assert that the parent and child have matching
+ // embedding tokens in parent HTMLOwnerElement and child LocalFrame.
+}
+
+IN_PROC_BROWSER_TEST_F(EmbeddingTokenBrowserTest,
+ EmbeddingTokenChangedOnSubframeNavigationToNewDocument) {
+ auto a_url = embedded_test_server()->GetURL("a.com", "/");
+ EXPECT_TRUE(NavigateToURL(
+ shell(), a_url.Resolve("cross_site_iframe_factory.html?a(b)")));
+
+ ASSERT_EQ(1U, top_frame_host()->child_count());
+ EXPECT_TRUE(top_frame_host()->GetEmbeddingToken().has_value());
+ auto top_token = top_frame_host()->GetEmbeddingToken().value();
+
+ // Child 0 (b) should have an embedding token.
+ RenderFrameHost* target = top_frame_host()->child_at(0)->current_frame_host();
+ auto child_0_token = target->GetEmbeddingToken();
+ ASSERT_TRUE(child_0_token.has_value());
+ EXPECT_NE(base::UnguessableToken::Null(), child_0_token);
+ EXPECT_NE(top_token, child_0_token);
+
+ // Navigate child 0 (b) to the same site as the main frame. This should create
+ // an embedding token.
+ {
+ RenderFrameDeletedObserver deleted_observer(target);
+ NavigateIframeToURL(web_contents(), "child-0",
+ a_url.Resolve("site_isolation/").Resolve("blank.html"));
+ deleted_observer.WaitUntilDeleted();
+ }
+
+ auto new_child_0_token =
+ top_frame_host()->child_at(0)->current_frame_host()->GetEmbeddingToken();
+ ASSERT_TRUE(new_child_0_token.has_value());
+ EXPECT_NE(base::UnguessableToken::Null(), new_child_0_token);
+ EXPECT_NE(top_token, new_child_0_token);
+ EXPECT_NE(child_0_token, new_child_0_token);
+
+ // TODO(ckitagawa): Somehow assert that the parent and child have matching
+ // embedding tokens in parent HTMLOwnerElement and child LocalFrame.
+}
+
+IN_PROC_BROWSER_TEST_F(EmbeddingTokenBrowserTest,
+ BackForwardCacheCrossDocument) {
+ auto a_url = embedded_test_server()->GetURL("a.com", "/site_isolation/");
+ auto b_url = embedded_test_server()->GetURL("b.com", "/site_isolation/");
+ EXPECT_TRUE(NavigateToURL(shell(), a_url.Resolve("blank.html")));
+
+ EXPECT_TRUE(top_frame_host()->GetEmbeddingToken().has_value());
+ auto top_token_a = top_frame_host()->GetEmbeddingToken().value();
+
+ EXPECT_TRUE(NavigateToURL(shell(), b_url.Resolve("blank.html")));
+ EXPECT_TRUE(top_frame_host()->GetEmbeddingToken().has_value());
+ auto top_token_b = top_frame_host()->GetEmbeddingToken().value();
+ EXPECT_NE(top_token_a, top_token_b);
+
+ // Navigate back to the first origin. The back forward cache should keep
+ // the embedding token.
+ web_contents()->GetController().GoBack();
+ EXPECT_TRUE(content::WaitForLoadStop(web_contents()));
+
+ EXPECT_TRUE(top_frame_host()->GetEmbeddingToken().has_value());
+ auto top_token_a_prime = top_frame_host()->GetEmbeddingToken().value();
+ EXPECT_EQ(top_token_a, top_token_a_prime);
+}
+
+IN_PROC_BROWSER_TEST_F(EmbeddingTokenBrowserTest,
+ BackForwardCacheCrossDocumentAfterSameDocument) {
+ auto a_url = embedded_test_server()->GetURL("a.com", "/site_isolation/");
+ auto b_url = embedded_test_server()->GetURL("b.com", "/site_isolation/");
+ EXPECT_TRUE(NavigateToURL(shell(), a_url.Resolve("blank.html")));
+
+ EXPECT_TRUE(top_frame_host()->GetEmbeddingToken().has_value());
+ auto top_token_a = top_frame_host()->GetEmbeddingToken().value();
+
+ EXPECT_TRUE(NavigateToURL(shell(), a_url.Resolve("blank.html#foo")));
+ EXPECT_TRUE(top_frame_host()->GetEmbeddingToken().has_value());
+ EXPECT_EQ(top_frame_host()->GetEmbeddingToken().value(), top_token_a);
+
+ EXPECT_TRUE(NavigateToURL(shell(), b_url.Resolve("blank.html")));
+ EXPECT_TRUE(top_frame_host()->GetEmbeddingToken().has_value());
+ auto top_token_b = top_frame_host()->GetEmbeddingToken().value();
+ EXPECT_NE(top_token_a, top_token_b);
+
+ // Navigate back to the first origin. The back forward cache should keep
+ // the embedding token even when the embedding token is not present in the
+ // most recent navigation.
+ web_contents()->GetController().GoBack();
+ EXPECT_TRUE(content::WaitForLoadStop(web_contents()));
+
+ EXPECT_TRUE(top_frame_host()->GetEmbeddingToken().has_value());
+ auto top_token_a_prime = top_frame_host()->GetEmbeddingToken().value();
+ EXPECT_EQ(top_token_a, top_token_a_prime);
+}
+
+IN_PROC_BROWSER_TEST_F(EmbeddingTokenBrowserTest,
+ SameDocumentHistoryPreservesTokens) {
+ auto a_url = embedded_test_server()->GetURL("a.com", "/site_isolation/");
+ EXPECT_TRUE(NavigateToURL(shell(), a_url.Resolve("blank.html")));
+
+ EXPECT_TRUE(top_frame_host()->GetEmbeddingToken().has_value());
+ auto top_token_a = top_frame_host()->GetEmbeddingToken().value();
+
+ EXPECT_TRUE(NavigateToURL(shell(), a_url.Resolve("blank.html#foo")));
+ EXPECT_TRUE(top_frame_host()->GetEmbeddingToken().has_value());
+ auto top_token_a_prime = top_frame_host()->GetEmbeddingToken().value();
+ EXPECT_EQ(top_token_a, top_token_a_prime);
+
+ // Navigate back to before the fragment was added. This should preserve the
+ // embedding token.
+ web_contents()->GetController().GoBack();
+ EXPECT_TRUE(content::WaitForLoadStop(web_contents()));
+
+ EXPECT_TRUE(top_frame_host()->GetEmbeddingToken().has_value());
+ auto top_token_a_prime_prime = top_frame_host()->GetEmbeddingToken().value();
+ EXPECT_EQ(top_token_a, top_token_a_prime_prime);
+}
+
+} // namespace content