blob: ec88cbbc9e703c0ad4831fe6089e7c61c2eeaddf [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2014 The Chromium Authors
[email protected]5f96f5a62014-01-10 00:05:112// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ken Rockot86bea1c2017-05-16 06:21:355#include "base/command_line.h"
Ari Chivukula5d15efb2023-01-21 04:33:526#include "base/strings/strcat.h"
Aaron Colwelle953e562019-07-24 16:47:367#include "base/strings/stringprintf.h"
shivanigithubf33e469c2021-08-02 13:52:208#include "base/synchronization/lock.h"
shivanigithub93878d02021-06-15 11:37:539#include "base/test/scoped_feature_list.h"
avib7348942015-12-25 20:57:1010#include "build/build_config.h"
danakjc492bf82020-09-09 20:02:4411#include "content/browser/renderer_host/frame_tree.h"
12#include "content/browser/renderer_host/frame_tree_node.h"
Yao Xiao6e1f7d32022-01-07 03:28:4013#include "content/browser/renderer_host/navigation_request.h"
danakjc492bf82020-09-09 20:02:4414#include "content/browser/renderer_host/render_frame_host_impl.h"
[email protected]5f96f5a62014-01-10 00:05:1115#include "content/browser/renderer_host/render_view_host_impl.h"
16#include "content/browser/web_contents/web_contents_impl.h"
shivanigithubf33e469c2021-08-02 13:52:2017#include "content/public/browser/browser_thread.h"
Dave Tapuska87696ae2021-11-18 18:48:3118#include "content/public/browser/navigation_handle.h"
Nasko Oskov0401d812021-02-05 22:20:0819#include "content/public/browser/site_isolation_policy.h"
Annie Sullivan35977ad2019-04-30 21:04:2820#include "content/public/common/content_features.h"
nickdb193a12016-09-09 23:09:2321#include "content/public/common/content_switches.h"
Nasko Oskov039121012019-01-11 00:21:3222#include "content/public/common/origin_util.h"
[email protected]5f96f5a62014-01-10 00:05:1123#include "content/public/common/url_constants.h"
Peter Kasting919ce652020-05-07 10:22:3624#include "content/public/test/browser_test.h"
[email protected]5f96f5a62014-01-10 00:05:1125#include "content/public/test/browser_test_utils.h"
[email protected]6e9def12014-03-27 20:23:2826#include "content/public/test/content_browser_test.h"
27#include "content/public/test/content_browser_test_utils.h"
Ari Chivukula5d15efb2023-01-21 04:33:5228#include "content/public/test/content_mock_cert_verifier.h"
John Abd-El-Malek3fea4c42019-01-10 01:15:4229#include "content/public/test/test_frame_navigation_observer.h"
[email protected]5f96f5a62014-01-10 00:05:1130#include "content/public/test/test_navigation_observer.h"
31#include "content/public/test/test_utils.h"
32#include "content/shell/browser/shell.h"
nickdb193a12016-09-09 23:09:2333#include "content/shell/common/shell_switches.h"
[email protected]82307f6b2014-08-07 03:30:1234#include "content/test/content_browser_test_utils_internal.h"
David Sandersc9ef3002022-02-02 15:27:0135#include "net/base/features.h"
[email protected]5f96f5a62014-01-10 00:05:1136#include "net/dns/mock_host_resolver.h"
Nan Linea8e9d202022-04-13 18:31:0137#include "net/test/embedded_test_server/controllable_http_response.h"
Dave Tapuska708c2732022-09-23 22:47:4938#include "net/test/embedded_test_server/default_handlers.h"
alexmos478dcbb2014-12-10 21:24:4639#include "net/test/embedded_test_server/embedded_test_server.h"
shivanigithubf33e469c2021-08-02 13:52:2040#include "net/test/embedded_test_server/http_request.h"
Ari Chivukula5d15efb2023-01-21 04:33:5241#include "services/network/public/cpp/network_switches.h"
arthursonzognib93a4472020-04-10 07:38:0042#include "services/network/public/cpp/web_sandbox_flags.h"
43#include "services/network/public/mojom/web_sandbox_flags.mojom-shared.h"
Gyuyoung Kim107c2a02021-04-13 01:49:3044#include "third_party/blink/public/common/chrome_debug_urls.h"
shivanigithub93878d02021-06-15 11:37:5345#include "third_party/blink/public/common/features.h"
Ari Chivukula5d15efb2023-01-21 04:33:5246#include "third_party/blink/public/common/storage_key/storage_key.h"
Antonio Gomes4b2c5132020-01-16 11:49:4847#include "third_party/blink/public/mojom/frame/user_activation_update_types.mojom.h"
nick1466c842015-11-25 20:08:0648#include "url/url_constants.h"
[email protected]5f96f5a62014-01-10 00:05:1149
50namespace content {
51
nickdb193a12016-09-09 23:09:2352namespace {
53
Nick Carterb7e71312018-08-03 23:36:1354EvalJsResult GetOriginFromRenderer(FrameTreeNode* node) {
Philip Jägenstedt67302a22018-09-14 09:58:0555 return EvalJs(node, "self.origin");
nickdb193a12016-09-09 23:09:2356}
57
Yuzu Saijo03dbf9b2022-07-22 04:29:4558// Expect that frame_name, id and src match the node's values.
59void ExpectAttributesEq(FrameTreeNode* node,
60 const std::string& frame_name,
Yuzu Saijodc870f92023-01-20 03:39:1161 const absl::optional<std::string> id,
62 const absl::optional<std::string> src) {
Yuzu Saijo03dbf9b2022-07-22 04:29:4563 EXPECT_EQ(frame_name, node->frame_name());
64 EXPECT_EQ(id, node->html_id());
65 EXPECT_EQ(src, node->html_src());
66}
67
nickdb193a12016-09-09 23:09:2368} // namespace
69
[email protected]5f96f5a62014-01-10 00:05:1170class FrameTreeBrowserTest : public ContentBrowserTest {
71 public:
Fergal Dalya1d569972021-03-16 03:24:5372 FrameTreeBrowserTest() = default;
[email protected]5f96f5a62014-01-10 00:05:1173
Peter Boström9b036532021-10-28 23:37:2874 FrameTreeBrowserTest(const FrameTreeBrowserTest&) = delete;
75 FrameTreeBrowserTest& operator=(const FrameTreeBrowserTest&) = delete;
76
alexmos478dcbb2014-12-10 21:24:4677 void SetUpOnMainThread() override {
78 host_resolver()->AddRule("*", "127.0.0.1");
alexmos478dcbb2014-12-10 21:24:4679 SetupCrossSiteRedirector(embedded_test_server());
martijn12d2dad2016-11-11 10:59:2780 ASSERT_TRUE(embedded_test_server()->Start());
alexmos478dcbb2014-12-10 21:24:4681 }
[email protected]5f96f5a62014-01-10 00:05:1182};
83
84// Ensures FrameTree correctly reflects page structure during navigations.
85IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape) {
alexmos478dcbb2014-12-10 21:24:4686 GURL base_url = embedded_test_server()->GetURL("A.com", "/site_isolation/");
[email protected]5f96f5a62014-01-10 00:05:1187
88 // Load doc without iframes. Verify FrameTree just has root.
89 // Frame tree:
90 // Site-A Root
Alex Moshchukaa95adf52019-08-13 00:02:0291 EXPECT_TRUE(NavigateToURL(shell(), base_url.Resolve("blank.html")));
Aran Gilman37d11632019-10-08 23:07:1592 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
Carlos Caballero15caeeb2021-10-27 09:57:5593 ->GetPrimaryFrameTree()
94 .root();
[email protected]5f96f5a62014-01-10 00:05:1195 EXPECT_EQ(0U, root->child_count());
96
97 // Add 2 same-site frames. Verify 3 nodes in tree with proper names.
98 // Frame tree:
99 // Site-A Root -- Site-A frame1
100 // \-- Site-A frame2
[email protected]71bc140b2022-03-14 23:45:01101 LoadStopObserver observer1(shell()->web_contents());
Alex Moshchukaa95adf52019-08-13 00:02:02102 EXPECT_TRUE(NavigateToURL(shell(), base_url.Resolve("frames-X-X.html")));
[email protected]5f96f5a62014-01-10 00:05:11103 observer1.Wait();
104 ASSERT_EQ(2U, root->child_count());
105 EXPECT_EQ(0U, root->child_at(0)->child_count());
106 EXPECT_EQ(0U, root->child_at(1)->child_count());
107}
108
109// TODO(ajwong): Talk with nasko and merge this functionality with
110// FrameTreeShape.
111IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape2) {
Alex Moshchukaa95adf52019-08-13 00:02:02112 EXPECT_TRUE(NavigateToURL(
113 shell(), embedded_test_server()->GetURL("/frame_tree/top.html")));
[email protected]5f96f5a62014-01-10 00:05:11114
115 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
Carlos Caballero15caeeb2021-10-27 09:57:55116 FrameTreeNode* root = wc->GetPrimaryFrameTree().root();
[email protected]5f96f5a62014-01-10 00:05:11117
[email protected]58faf942014-02-20 21:03:58118 // Check that the root node is properly created.
[email protected]5f96f5a62014-01-10 00:05:11119 ASSERT_EQ(3UL, root->child_count());
Yuzu Saijodc870f92023-01-20 03:39:11120 ExpectAttributesEq(root, std::string(), absl::nullopt, absl::nullopt);
[email protected]5f96f5a62014-01-10 00:05:11121
122 ASSERT_EQ(2UL, root->child_at(0)->child_count());
Yuzu Saijo03dbf9b2022-07-22 04:29:45123 ExpectAttributesEq(root->child_at(0), "1-1-name", "1-1-id", "1-1.html");
[email protected]5f96f5a62014-01-10 00:05:11124
125 // Verify the deepest node exists and has the right name.
126 ASSERT_EQ(2UL, root->child_at(2)->child_count());
127 EXPECT_EQ(1UL, root->child_at(2)->child_at(1)->child_count());
128 EXPECT_EQ(0UL, root->child_at(2)->child_at(1)->child_at(0)->child_count());
Yuzu Saijo03dbf9b2022-07-22 04:29:45129 ExpectAttributesEq(root->child_at(2)->child_at(1)->child_at(0), "3-1-name",
130 "3-1-id", "3-1.html");
[email protected]5f96f5a62014-01-10 00:05:11131
132 // Navigate to about:blank, which should leave only the root node of the frame
133 // tree in the browser process.
Alex Moshchukaa95adf52019-08-13 00:02:02134 EXPECT_TRUE(
135 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
[email protected]5f96f5a62014-01-10 00:05:11136
Carlos Caballero15caeeb2021-10-27 09:57:55137 root = wc->GetPrimaryFrameTree().root();
[email protected]5f96f5a62014-01-10 00:05:11138 EXPECT_EQ(0UL, root->child_count());
Yuzu Saijodc870f92023-01-20 03:39:11139 ExpectAttributesEq(root, std::string(), absl::nullopt, absl::nullopt);
Yuzu Saijo03dbf9b2022-07-22 04:29:45140}
141
142// Frame attributes of iframe elements are correctly tracked in FrameTree.
143IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeAttributesUpdate) {
144 EXPECT_TRUE(NavigateToURL(
145 shell(), embedded_test_server()->GetURL("/frame_tree/top.html")));
146
147 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
148 FrameTreeNode* root = wc->GetPrimaryFrameTree().root();
149
150 // Check that the root node is properly created.
151 ASSERT_EQ(3UL, root->child_count());
Yuzu Saijodc870f92023-01-20 03:39:11152 ExpectAttributesEq(root, std::string(), absl::nullopt, absl::nullopt);
Yuzu Saijo03dbf9b2022-07-22 04:29:45153
154 ASSERT_EQ(2UL, root->child_at(0)->child_count());
155 ExpectAttributesEq(root->child_at(0), "1-1-name", "1-1-id", "1-1.html");
156
157 // Change id, name and src of the iframe.
158 EXPECT_TRUE(ExecJs(root->current_frame_host(), R"(
159 let iframe = document.getElementById('1-1-id');
160 iframe.id = '1-1-updated-id';
161 iframe.name = '1-1-updated-name';
162 iframe.src = '1-1-updated.html';
163 )"));
164 // |html_name()| gets updated whenever the name attribute gets updated.
165 EXPECT_EQ("1-1-updated-name", root->child_at(0)->html_name());
166 ExpectAttributesEq(root->child_at(0), "1-1-name", "1-1-updated-id",
167 "1-1-updated.html");
168}
169
170// Ensures that frames' name attributes and their updates are tracked in
171// |html_name()| and window.name and its updates are tracked in |frame_name()|.
172IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameNameVSWindowName) {
173 EXPECT_TRUE(NavigateToURL(
174 shell(), embedded_test_server()->GetURL("/frame_tree/top.html")));
175
176 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
177 FrameTreeNode* root = wc->GetPrimaryFrameTree().root();
178
179 // Check that the root node is properly created.
180 ASSERT_EQ(3UL, root->child_count());
Yuzu Saijodc870f92023-01-20 03:39:11181 EXPECT_EQ(absl::nullopt, root->html_name());
[email protected]5f96f5a62014-01-10 00:05:11182 EXPECT_EQ(std::string(), root->frame_name());
Yuzu Saijo03dbf9b2022-07-22 04:29:45183
184 ASSERT_EQ(2UL, root->child_at(0)->child_count());
185 EXPECT_EQ("1-1-name", root->child_at(0)->html_name());
186 EXPECT_EQ("1-1-name", root->child_at(0)->frame_name());
187
188 // Change the name attribute of the iframe.
189 EXPECT_TRUE(ExecJs(root->current_frame_host(), R"(
190 let iframe = document.getElementById('1-1-id');
191 iframe.name = '1-1-updated-name';
192 )"));
193 // |html_name()| gets updated whenever the name attribute gets updated.
194 EXPECT_EQ("1-1-updated-name", root->child_at(0)->html_name());
195 // |frame_name()| stays the same.
196 EXPECT_EQ("1-1-name", root->child_at(0)->frame_name());
197
198 // Change the window.name of the iframe.
199 EXPECT_TRUE(ExecJs(root->current_frame_host(), R"(
200 let iframe = document.getElementById('1-1-id');
201 iframe.contentWindow.name = '1-1-updated-name-2';
202 )"));
203 // |html_name()| stays the same.
204 EXPECT_EQ("1-1-updated-name", root->child_at(0)->html_name());
205 // |frame_name()| gets updated.
206 EXPECT_EQ("1-1-updated-name-2", root->child_at(0)->frame_name());
207}
208
209// Ensures that long attributes are cut down to the max length.
210IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, LongAttributesCutDown) {
211 EXPECT_TRUE(NavigateToURL(
212 shell(), embedded_test_server()->GetURL("/frame_tree/top.html")));
213
214 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
215 FrameTreeNode* root = wc->GetPrimaryFrameTree().root();
216
217 // Check that the root node is properly created.
218 ASSERT_EQ(3UL, root->child_count());
219 ASSERT_EQ(2UL, root->child_at(0)->child_count());
220 EXPECT_EQ("1-1-name", root->child_at(0)->html_name());
221
222 // Change the name attribute of the iframe.
223 EXPECT_TRUE(ExecJs(root->current_frame_host(), R"(
224 let iframe = document.getElementById('1-1-id');
225 iframe.id += 'a'.repeat(1200);
226 iframe.name += 'b'.repeat(1200);
227 iframe.src += 'c'.repeat(1200) + '.html';
228 )"));
229 // Long attribute is cut down to the maximum length.
Yuzu Saijodc870f92023-01-20 03:39:11230 EXPECT_EQ(1024UL, root->child_at(0)->html_id()->size());
231 EXPECT_EQ(1024UL, root->child_at(0)->html_name()->size());
232 EXPECT_EQ(1024UL, root->child_at(0)->html_src()->size());
Yuzu Saijo03dbf9b2022-07-22 04:29:45233}
234
235// Insert a frame into the frame tree and ensure that the inserted frame's
236// attributes are correctly captured.
237IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, InsertFrameInTree) {
238 EXPECT_TRUE(NavigateToURL(
239 shell(), embedded_test_server()->GetURL("/frame_tree/top.html")));
240
241 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
242 FrameTreeNode* root = wc->GetPrimaryFrameTree().root();
243
244 // Check that the root node is properly created.
245 ASSERT_EQ(3UL, root->child_count());
Yuzu Saijodc870f92023-01-20 03:39:11246 ExpectAttributesEq(root, std::string(), absl::nullopt, absl::nullopt);
Yuzu Saijo03dbf9b2022-07-22 04:29:45247
248 ASSERT_EQ(2UL, root->child_at(0)->child_count());
249 ExpectAttributesEq(root->child_at(0), "1-1-name", "1-1-id", "1-1.html");
250
251 // Insert a child iframe.
252 EXPECT_TRUE(ExecJs(root->current_frame_host(), R"(
253 let new_iframe = document.createElement('iframe');
254 new_iframe.id = '1-1-child-id';
255 new_iframe.src = '1-1-child.html';
256 new_iframe.name = '1-1-child-name';
257
258 document.body.appendChild(new_iframe);
259 )"));
260 // Check that the new iframe is inserted and their attributes are correct.
261 ASSERT_EQ(4UL, root->child_count());
262 ExpectAttributesEq(root->child_at(3), "1-1-child-name", "1-1-child-id",
263 "1-1-child.html");
[email protected]5f96f5a62014-01-10 00:05:11264}
265
266// Test that we can navigate away if the previous renderer doesn't clean up its
267// child frames.
268IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeAfterCrash) {
Alex Moshchukaa95adf52019-08-13 00:02:02269 EXPECT_TRUE(NavigateToURL(
270 shell(), embedded_test_server()->GetURL("/frame_tree/top.html")));
[email protected]5f96f5a62014-01-10 00:05:11271
creise42f2a52014-09-18 18:14:57272 // Ensure the view and frame are live.
Lingqi Chi641aeee2021-09-08 00:32:58273 RenderFrameHostImpl* rfh1 = static_cast<RenderFrameHostImpl*>(
Dave Tapuska327c06c92022-06-13 20:31:51274 shell()->web_contents()->GetPrimaryMainFrame());
Kevin McNeeec162302022-04-14 16:00:28275 RenderViewHostImpl* rvh = rfh1->render_view_host();
creise42f2a52014-09-18 18:14:57276 EXPECT_TRUE(rvh->IsRenderViewLive());
arthursonzognif4c4a4a2019-08-08 18:54:44277 EXPECT_TRUE(rfh1->IsRenderFrameLive());
creise42f2a52014-09-18 18:14:57278
[email protected]5f96f5a62014-01-10 00:05:11279 // Crash the renderer so that it doesn't send any FrameDetached messages.
280 RenderProcessHostWatcher crash_observer(
281 shell()->web_contents(),
282 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
Wez0abfbf512018-03-03 01:54:45283 ASSERT_TRUE(
Dave Tapuska327c06c92022-06-13 20:31:51284 shell()->web_contents()->GetPrimaryMainFrame()->GetProcess()->Shutdown(
285 0));
[email protected]5f96f5a62014-01-10 00:05:11286 crash_observer.Wait();
287
[email protected]58faf942014-02-20 21:03:58288 // The frame tree should be cleared.
[email protected]5f96f5a62014-01-10 00:05:11289 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
Carlos Caballero15caeeb2021-10-27 09:57:55290 FrameTreeNode* root = wc->GetPrimaryFrameTree().root();
[email protected]5f96f5a62014-01-10 00:05:11291 EXPECT_EQ(0UL, root->child_count());
[email protected]5f96f5a62014-01-10 00:05:11292
creise42f2a52014-09-18 18:14:57293 // Ensure the view and frame aren't live anymore.
294 EXPECT_FALSE(rvh->IsRenderViewLive());
arthursonzognif4c4a4a2019-08-08 18:54:44295 EXPECT_FALSE(rfh1->IsRenderFrameLive());
creise42f2a52014-09-18 18:14:57296
[email protected]5f96f5a62014-01-10 00:05:11297 // Navigate to a new URL.
alexmos478dcbb2014-12-10 21:24:46298 GURL url(embedded_test_server()->GetURL("/title1.html"));
Alex Moshchukaa95adf52019-08-13 00:02:02299 EXPECT_TRUE(NavigateToURL(shell(), url));
[email protected]5f96f5a62014-01-10 00:05:11300 EXPECT_EQ(0UL, root->child_count());
[email protected]58faf942014-02-20 21:03:58301 EXPECT_EQ(url, root->current_url());
creise42f2a52014-09-18 18:14:57302
arthursonzognif4c4a4a2019-08-08 18:54:44303 RenderFrameHostImpl* rfh2 = root->current_frame_host();
creise42f2a52014-09-18 18:14:57304 // Ensure the view and frame are live again.
305 EXPECT_TRUE(rvh->IsRenderViewLive());
arthursonzognif4c4a4a2019-08-08 18:54:44306 EXPECT_TRUE(rfh2->IsRenderFrameLive());
[email protected]5f96f5a62014-01-10 00:05:11307}
308
309// Test that we can navigate away if the previous renderer doesn't clean up its
310// child frames.
Nasko Oskov31c45ff2019-10-16 01:15:19311IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, NavigateWithLeftoverFrames) {
alexmos478dcbb2014-12-10 21:24:46312 GURL base_url = embedded_test_server()->GetURL("A.com", "/site_isolation/");
[email protected]5f96f5a62014-01-10 00:05:11313
Alex Moshchukaa95adf52019-08-13 00:02:02314 EXPECT_TRUE(NavigateToURL(
315 shell(), embedded_test_server()->GetURL("/frame_tree/top.html")));
[email protected]5f96f5a62014-01-10 00:05:11316
317 // Hang the renderer so that it doesn't send any FrameDetached messages.
318 // (This navigation will never complete, so don't wait for it.)
Gyuyoung Kim107c2a02021-04-13 01:49:30319 shell()->LoadURL(GURL(blink::kChromeUIHangURL));
[email protected]5f96f5a62014-01-10 00:05:11320
321 // Check that the frame tree still has children.
322 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
Carlos Caballero15caeeb2021-10-27 09:57:55323 FrameTreeNode* root = wc->GetPrimaryFrameTree().root();
[email protected]5f96f5a62014-01-10 00:05:11324 ASSERT_EQ(3UL, root->child_count());
325
326 // Navigate to a new URL. We use LoadURL because NavigateToURL will try to
327 // wait for the previous navigation to stop.
328 TestNavigationObserver tab_observer(wc, 1);
329 shell()->LoadURL(base_url.Resolve("blank.html"));
330 tab_observer.Wait();
331
[email protected]58faf942014-02-20 21:03:58332 // The frame tree should now be cleared.
[email protected]5f96f5a62014-01-10 00:05:11333 EXPECT_EQ(0UL, root->child_count());
[email protected]5f96f5a62014-01-10 00:05:11334}
335
creise42f2a52014-09-18 18:14:57336// Ensure that IsRenderFrameLive is true for main frames and same-site iframes.
337IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, IsRenderFrameLive) {
alexmos478dcbb2014-12-10 21:24:46338 GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
Alex Moshchukaa95adf52019-08-13 00:02:02339 EXPECT_TRUE(NavigateToURL(shell(), main_url));
creise42f2a52014-09-18 18:14:57340
341 // It is safe to obtain the root frame tree node here, as it doesn't change.
342 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
Carlos Caballero15caeeb2021-10-27 09:57:55343 ->GetPrimaryFrameTree()
344 .root();
creise42f2a52014-09-18 18:14:57345
346 // The root and subframe should each have a live RenderFrame.
347 EXPECT_TRUE(
348 root->current_frame_host()->render_view_host()->IsRenderViewLive());
349 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
350 EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
351
352 // Load a same-site page into iframe and it should still be live.
alexmos478dcbb2014-12-10 21:24:46353 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
Lukasz Anforowicz69c25dfd2020-11-12 21:50:20354 EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), http_url));
creise42f2a52014-09-18 18:14:57355 EXPECT_TRUE(
356 root->current_frame_host()->render_view_host()->IsRenderViewLive());
357 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
358 EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
359}
360
alexmosbc7eafa2014-12-06 01:38:09361// Ensure that origins are correctly set on navigations.
362IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, OriginSetOnNavigation) {
nick1466c842015-11-25 20:08:06363 GURL about_blank(url::kAboutBlankURL);
364 GURL main_url(
365 embedded_test_server()->GetURL("a.com", "/frame_tree/top.html"));
alexmosbc7eafa2014-12-06 01:38:09366 EXPECT_TRUE(NavigateToURL(shell(), main_url));
nick1466c842015-11-25 20:08:06367 WebContents* contents = shell()->web_contents();
alexmosbc7eafa2014-12-06 01:38:09368
369 // It is safe to obtain the root frame tree node here, as it doesn't change.
nick1466c842015-11-25 20:08:06370 FrameTreeNode* root =
Carlos Caballero15caeeb2021-10-27 09:57:55371 static_cast<WebContentsImpl*>(contents)->GetPrimaryFrameTree().root();
alexmosbc7eafa2014-12-06 01:38:09372
373 // Extra '/' is added because the replicated origin is serialized in RFC 6454
374 // format, which dictates no trailing '/', whereas GURL::GetOrigin does put a
375 // '/' at the end.
Mike West800532c2021-10-14 09:26:52376 EXPECT_EQ(main_url.DeprecatedGetOriginAsURL().spec(),
nick1466c842015-11-25 20:08:06377 root->current_origin().Serialize() + '/');
378 EXPECT_EQ(
Mike West800532c2021-10-14 09:26:52379 main_url.DeprecatedGetOriginAsURL().spec(),
nick1466c842015-11-25 20:08:06380 root->current_frame_host()->GetLastCommittedOrigin().Serialize() + '/');
alexmosbc7eafa2014-12-06 01:38:09381
nick1466c842015-11-25 20:08:06382 // The iframe is inititially same-origin.
383 EXPECT_TRUE(
384 root->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
385 root->child_at(0)->current_frame_host()->GetLastCommittedOrigin()));
386 EXPECT_EQ(root->current_origin().Serialize(), GetOriginFromRenderer(root));
387 EXPECT_EQ(root->child_at(0)->current_origin().Serialize(),
388 GetOriginFromRenderer(root->child_at(0)));
389
390 // Navigate the iframe cross-origin.
391 GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
Lukasz Anforowicz69c25dfd2020-11-12 21:50:20392 EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
nick1466c842015-11-25 20:08:06393 EXPECT_EQ(frame_url, root->child_at(0)->current_url());
Mike West800532c2021-10-14 09:26:52394 EXPECT_EQ(frame_url.DeprecatedGetOriginAsURL().spec(),
nick1466c842015-11-25 20:08:06395 root->child_at(0)->current_origin().Serialize() + '/');
396 EXPECT_FALSE(
397 root->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
398 root->child_at(0)->current_frame_host()->GetLastCommittedOrigin()));
399 EXPECT_EQ(root->current_origin().Serialize(), GetOriginFromRenderer(root));
400 EXPECT_EQ(root->child_at(0)->current_origin().Serialize(),
401 GetOriginFromRenderer(root->child_at(0)));
alexmosbc7eafa2014-12-06 01:38:09402
nick1466c842015-11-25 20:08:06403 // Parent-initiated about:blank navigation should inherit the parent's a.com
404 // origin.
405 NavigateIframeToURL(contents, "1-1-id", about_blank);
406 EXPECT_EQ(about_blank, root->child_at(0)->current_url());
Mike West800532c2021-10-14 09:26:52407 EXPECT_EQ(main_url.DeprecatedGetOriginAsURL().spec(),
nick1466c842015-11-25 20:08:06408 root->child_at(0)->current_origin().Serialize() + '/');
409 EXPECT_EQ(root->current_frame_host()->GetLastCommittedOrigin().Serialize(),
410 root->child_at(0)
411 ->current_frame_host()
412 ->GetLastCommittedOrigin()
413 .Serialize());
414 EXPECT_TRUE(
415 root->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
416 root->child_at(0)->current_frame_host()->GetLastCommittedOrigin()));
417 EXPECT_EQ(root->current_origin().Serialize(), GetOriginFromRenderer(root));
418 EXPECT_EQ(root->child_at(0)->current_origin().Serialize(),
419 GetOriginFromRenderer(root->child_at(0)));
alexmosbc7eafa2014-12-06 01:38:09420
421 GURL data_url("data:text/html,foo");
422 EXPECT_TRUE(NavigateToURL(shell(), data_url));
423
424 // Navigating to a data URL should set a unique origin. This is represented
425 // as "null" per RFC 6454.
nick1466c842015-11-25 20:08:06426 EXPECT_EQ("null", root->current_origin().Serialize());
Dave Tapuska327c06c92022-06-13 20:31:51427 EXPECT_TRUE(
428 contents->GetPrimaryMainFrame()->GetLastCommittedOrigin().opaque());
nick1466c842015-11-25 20:08:06429 EXPECT_EQ("null", GetOriginFromRenderer(root));
alexmosbc7eafa2014-12-06 01:38:09430
431 // Re-navigating to a normal URL should update the origin.
432 EXPECT_TRUE(NavigateToURL(shell(), main_url));
Mike West800532c2021-10-14 09:26:52433 EXPECT_EQ(main_url.DeprecatedGetOriginAsURL().spec(),
nick1466c842015-11-25 20:08:06434 root->current_origin().Serialize() + '/');
435 EXPECT_EQ(
Mike West800532c2021-10-14 09:26:52436 main_url.DeprecatedGetOriginAsURL().spec(),
Dave Tapuska327c06c92022-06-13 20:31:51437 contents->GetPrimaryMainFrame()->GetLastCommittedOrigin().Serialize() +
438 '/');
439 EXPECT_FALSE(
440 contents->GetPrimaryMainFrame()->GetLastCommittedOrigin().opaque());
nick1466c842015-11-25 20:08:06441 EXPECT_EQ(root->current_origin().Serialize(), GetOriginFromRenderer(root));
alexmosbc7eafa2014-12-06 01:38:09442}
443
nick9f34e2892016-01-12 21:01:07444// Tests a cross-origin navigation to a blob URL. The main frame initiates this
445// navigation on its grandchild. It should wind up in the main frame's process.
446IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, NavigateGrandchildToBlob) {
447 WebContents* contents = shell()->web_contents();
448 FrameTreeNode* root =
Carlos Caballero15caeeb2021-10-27 09:57:55449 static_cast<WebContentsImpl*>(contents)->GetPrimaryFrameTree().root();
nick9f34e2892016-01-12 21:01:07450
451 // First, snapshot the FrameTree for a normal A(B(A)) case where all frames
452 // are served over http. The blob test should result in the same structure.
453 EXPECT_TRUE(NavigateToURL(
454 shell(), embedded_test_server()->GetURL(
455 "a.com", "/cross_site_iframe_factory.html?a(b(a))")));
Fergal Daly79f44292020-12-01 02:30:48456 std::string reference_tree = DepictFrameTree(*root);
nick9f34e2892016-01-12 21:01:07457
458 GURL main_url(embedded_test_server()->GetURL(
459 "a.com", "/cross_site_iframe_factory.html?a(b(c))"));
460 EXPECT_TRUE(NavigateToURL(shell(), main_url));
461
462 // The root node will initiate the navigation; its grandchild node will be the
463 // target of the navigation.
464 FrameTreeNode* target = root->child_at(0)->child_at(0);
465
creisb2d5f1f32016-11-07 23:25:05466 RenderFrameDeletedObserver deleted_observer(target->current_frame_host());
Nick Carterb7e71312018-08-03 23:36:13467 std::string html =
468 "<html><body><div>This is blob content.</div>"
469 "<script>"
Philip Jägenstedt67302a22018-09-14 09:58:05470 "window.parent.parent.postMessage('HI', self.origin);"
Nick Carterb7e71312018-08-03 23:36:13471 "</script></body></html>";
472 std::string script = JsReplace(
473 "new Promise((resolve) => {"
474 " window.addEventListener('message', resolve, false);"
475 " var blob = new Blob([$1], {type: 'text/html'});"
476 " var blob_url = URL.createObjectURL(blob);"
477 " frames[0][0].location.href = blob_url;"
478 "}).then((event) => {"
nick9f34e2892016-01-12 21:01:07479 " document.body.appendChild(document.createTextNode(event.data));"
Nick Carterb7e71312018-08-03 23:36:13480 " return event.source.location.href;"
481 "});",
482 html);
483 std::string blob_url_string = EvalJs(root, script).ExtractString();
creisb2d5f1f32016-11-07 23:25:05484 // Wait for the RenderFrame to go away, if this will be cross-process.
485 if (AreAllSitesIsolatedForTesting())
486 deleted_observer.WaitUntilDeleted();
nick9f34e2892016-01-12 21:01:07487 EXPECT_EQ(GURL(blob_url_string), target->current_url());
488 EXPECT_EQ(url::kBlobScheme, target->current_url().scheme());
Chris Palmerab5e5b52018-09-28 19:19:30489 EXPECT_FALSE(target->current_origin().opaque());
nick9f34e2892016-01-12 21:01:07490 EXPECT_EQ("a.com", target->current_origin().host());
491 EXPECT_EQ(url::kHttpScheme, target->current_origin().scheme());
Nick Carterb7e71312018-08-03 23:36:13492 EXPECT_EQ("This is blob content.",
493 EvalJs(target, "document.body.children[0].innerHTML"));
Fergal Daly79f44292020-12-01 02:30:48494 EXPECT_EQ(reference_tree, DepictFrameTree(*root));
nick9f34e2892016-01-12 21:01:07495}
496
497IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, NavigateChildToAboutBlank) {
498 GURL main_url(embedded_test_server()->GetURL(
499 "a.com", "/cross_site_iframe_factory.html?a(b(c))"));
500 EXPECT_TRUE(NavigateToURL(shell(), main_url));
501 WebContentsImpl* contents =
502 static_cast<WebContentsImpl*>(shell()->web_contents());
503
504 // The leaf node (c.com) will be navigated. Its parent node (b.com) will
505 // initiate the navigation.
506 FrameTreeNode* target =
Carlos Caballero15caeeb2021-10-27 09:57:55507 contents->GetPrimaryFrameTree().root()->child_at(0)->child_at(0);
Harkiran Bolaria4eaae3072021-09-21 10:45:48508 RenderFrameHost* initiator_rfh = target->parent();
nick9f34e2892016-01-12 21:01:07509
510 // Give the target a name.
Nick Carterb7e71312018-08-03 23:36:13511 EXPECT_TRUE(ExecJs(target, "window.name = 'target';"));
nick9f34e2892016-01-12 21:01:07512
513 // Use window.open(about:blank), then poll the document for access.
Nick Carterb7e71312018-08-03 23:36:13514 EvalJsResult about_blank_origin = EvalJs(
Harkiran Bolaria4eaae3072021-09-21 10:45:48515 initiator_rfh,
Nick Carterb7e71312018-08-03 23:36:13516 "new Promise(resolve => {"
517 " var didNavigate = false;"
518 " var intervalID = setInterval(function() {"
519 " if (!didNavigate) {"
520 " didNavigate = true;"
521 " window.open('about:blank', 'target');"
522 " }"
523 " // Poll the document until it doesn't throw a SecurityError.\n"
524 " try {"
525 " frames[0].document.write('Hi from ' + document.domain);"
526 " } catch (e) { return; }"
527 " clearInterval(intervalID);"
Philip Jägenstedt67302a22018-09-14 09:58:05528 " resolve(frames[0].self.origin);"
Nick Carterb7e71312018-08-03 23:36:13529 " }, 16);"
530 "});");
531 EXPECT_EQ(target->current_origin(), about_blank_origin);
Nate Chapinab67b042021-05-04 21:00:51532 EXPECT_EQ(GURL(url::kAboutBlankURL), target->current_url());
533 EXPECT_EQ(url::kAboutScheme, target->current_url().scheme());
Chris Palmerab5e5b52018-09-28 19:19:30534 EXPECT_FALSE(target->current_origin().opaque());
nick9f34e2892016-01-12 21:01:07535 EXPECT_EQ("b.com", target->current_origin().host());
536 EXPECT_EQ(url::kHttpScheme, target->current_origin().scheme());
nick9f34e2892016-01-12 21:01:07537
Nick Carterb7e71312018-08-03 23:36:13538 EXPECT_EQ("Hi from b.com", EvalJs(target, "document.body.innerHTML"));
nick9f34e2892016-01-12 21:01:07539}
540
541// Nested iframes, three origins: A(B(C)). Frame A navigates C to about:blank
542// (via window.open). This should wind up in A's origin per the spec. Test fails
543// because of http://crbug.com/564292
544IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest,
545 DISABLED_NavigateGrandchildToAboutBlank) {
546 GURL main_url(embedded_test_server()->GetURL(
547 "a.com", "/cross_site_iframe_factory.html?a(b(c))"));
548 EXPECT_TRUE(NavigateToURL(shell(), main_url));
549 WebContentsImpl* contents =
550 static_cast<WebContentsImpl*>(shell()->web_contents());
551
552 // The leaf node (c.com) will be navigated. Its grandparent node (a.com) will
553 // initiate the navigation.
554 FrameTreeNode* target =
Carlos Caballero15caeeb2021-10-27 09:57:55555 contents->GetPrimaryFrameTree().root()->child_at(0)->child_at(0);
Harkiran Bolaria4eaae3072021-09-21 10:45:48556 RenderFrameHost* initiator_rfh = target->parent()->GetParent();
nick9f34e2892016-01-12 21:01:07557
558 // Give the target a name.
Nick Carterb7e71312018-08-03 23:36:13559 EXPECT_TRUE(ExecJs(target, "window.name = 'target';"));
nick9f34e2892016-01-12 21:01:07560
561 // Use window.open(about:blank), then poll the document for access.
Nick Carterb7e71312018-08-03 23:36:13562 EvalJsResult about_blank_origin =
Harkiran Bolaria4eaae3072021-09-21 10:45:48563 EvalJs(initiator_rfh,
Nick Carterb7e71312018-08-03 23:36:13564 "new Promise((resolve) => {"
565 " var didNavigate = false;"
566 " var intervalID = setInterval(() => {"
567 " if (!didNavigate) {"
568 " didNavigate = true;"
569 " window.open('about:blank', 'target');"
570 " }"
571 " // May raise a SecurityError, that's expected.\n"
572 " try {"
573 " frames[0][0].document.write('Hi from ' + document.domain);"
574 " } catch (e) { return; }"
575 " clearInterval(intervalID);"
Philip Jägenstedt67302a22018-09-14 09:58:05576 " resolve(frames[0][0].self.origin);"
Nick Carterb7e71312018-08-03 23:36:13577 " }, 16);"
578 "});");
579 EXPECT_EQ(target->current_origin(), about_blank_origin);
nick9f34e2892016-01-12 21:01:07580 EXPECT_EQ(GURL(url::kAboutBlankURL), target->current_url());
581 EXPECT_EQ(url::kAboutScheme, target->current_url().scheme());
Chris Palmerab5e5b52018-09-28 19:19:30582 EXPECT_FALSE(target->current_origin().opaque());
nick9f34e2892016-01-12 21:01:07583 EXPECT_EQ("a.com", target->current_origin().host());
584 EXPECT_EQ(url::kHttpScheme, target->current_origin().scheme());
nick9f34e2892016-01-12 21:01:07585
Nick Carterb7e71312018-08-03 23:36:13586 EXPECT_EQ("Hi from a.com", EvalJs(target, "document.body.innerHTML"));
nick9f34e2892016-01-12 21:01:07587}
588
Nasko Oskov039121012019-01-11 00:21:32589// Tests a cross-origin navigation to a data: URL. The main frame initiates this
590// navigation on its grandchild. It should wind up in the main frame's process
591// and have precursor origin of the main frame origin.
592IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, NavigateGrandchildToDataUrl) {
593 GURL main_url(embedded_test_server()->GetURL(
594 "a.com", "/cross_site_iframe_factory.html?a(b(c))"));
595 EXPECT_TRUE(NavigateToURL(shell(), main_url));
596 WebContentsImpl* contents =
597 static_cast<WebContentsImpl*>(shell()->web_contents());
598
599 // The leaf node (c.com) will be navigated. Its grandparent node (a.com) will
600 // initiate the navigation.
601 FrameTreeNode* target =
Carlos Caballero15caeeb2021-10-27 09:57:55602 contents->GetPrimaryFrameTree().root()->child_at(0)->child_at(0);
Harkiran Bolaria4eaae3072021-09-21 10:45:48603 RenderFrameHostImpl* initiator_rfh = target->parent()->GetParent();
Nasko Oskov039121012019-01-11 00:21:32604
605 // Give the target a name.
606 EXPECT_TRUE(ExecJs(target, "window.name = 'target';"));
607
608 // Navigate the target frame through the initiator frame.
609 {
610 TestFrameNavigationObserver observer(target);
Harkiran Bolaria4eaae3072021-09-21 10:45:48611 EXPECT_TRUE(ExecJs(initiator_rfh,
612 "window.open('data:text/html,content', 'target');"));
Nasko Oskov039121012019-01-11 00:21:32613 observer.Wait();
614 }
615
616 url::Origin original_target_origin =
617 target->current_frame_host()->GetLastCommittedOrigin();
618 EXPECT_TRUE(original_target_origin.opaque());
619 EXPECT_EQ(original_target_origin.GetTupleOrPrecursorTupleIfOpaque(),
620 url::SchemeHostPort(main_url));
621
622 // Navigate the grandchild frame again cross-process to foo.com, then
Rakina Zata Amnic7367852022-11-07 17:10:40623 // go back in session history. The frame should commit a new opaque origin,
624 // but it will still have the same precursor origin (the main frame origin).
Nasko Oskov039121012019-01-11 00:21:32625 {
626 TestFrameNavigationObserver observer(target);
627 EXPECT_TRUE(ExecJs(target, JsReplace("window.location = $1",
628 embedded_test_server()->GetURL(
629 "foo.com", "/title2.html"))));
630 observer.Wait();
631 }
632 EXPECT_NE(original_target_origin,
633 target->current_frame_host()->GetLastCommittedOrigin());
634 {
635 TestFrameNavigationObserver observer(target);
636 contents->GetController().GoBack();
637 observer.Wait();
638 }
639
640 url::Origin target_origin =
641 target->current_frame_host()->GetLastCommittedOrigin();
Rakina Zata Amnic7367852022-11-07 17:10:40642 EXPECT_NE(target_origin, original_target_origin);
Nasko Oskov039121012019-01-11 00:21:32643 EXPECT_TRUE(target_origin.opaque());
644 EXPECT_EQ(target_origin.GetTupleOrPrecursorTupleIfOpaque(),
Rakina Zata Amnic7367852022-11-07 17:10:40645 original_target_origin.GetTupleOrPrecursorTupleIfOpaque());
646 EXPECT_EQ(target_origin.GetTupleOrPrecursorTupleIfOpaque(),
Nasko Oskov039121012019-01-11 00:21:32647 url::SchemeHostPort(main_url));
Nasko Oskov039121012019-01-11 00:21:32648}
649
naskofaa01fb2016-04-30 01:04:17650// Ensures that iframe with srcdoc is always put in the same origin as its
651// parent frame.
652IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, ChildFrameWithSrcdoc) {
653 GURL main_url(embedded_test_server()->GetURL(
654 "a.com", "/cross_site_iframe_factory.html?a(b)"));
655 EXPECT_TRUE(NavigateToURL(shell(), main_url));
656 WebContentsImpl* contents =
657 static_cast<WebContentsImpl*>(shell()->web_contents());
Carlos Caballero15caeeb2021-10-27 09:57:55658 FrameTreeNode* root = contents->GetPrimaryFrameTree().root();
naskofaa01fb2016-04-30 01:04:17659 EXPECT_EQ(1U, root->child_count());
660
661 FrameTreeNode* child = root->child_at(0);
Philip Jägenstedt67302a22018-09-14 09:58:05662 std::string frame_origin = EvalJs(child, "self.origin;").ExtractString();
naskofaa01fb2016-04-30 01:04:17663 EXPECT_TRUE(
664 child->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
Daniel Cheng88186bd52017-10-20 08:14:46665 url::Origin::Create(GURL(frame_origin))));
naskofaa01fb2016-04-30 01:04:17666 EXPECT_FALSE(
667 root->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
Daniel Cheng88186bd52017-10-20 08:14:46668 url::Origin::Create(GURL(frame_origin))));
naskofaa01fb2016-04-30 01:04:17669
670 // Create a new iframe with srcdoc and add it to the main frame. It should
671 // be created in the same SiteInstance as the parent.
672 {
Aran Gilman37d11632019-10-08 23:07:15673 std::string script(
674 "var f = document.createElement('iframe');"
675 "f.srcdoc = 'some content';"
676 "document.body.appendChild(f)");
naskofaa01fb2016-04-30 01:04:17677 TestNavigationObserver observer(shell()->web_contents());
Nick Carterb7e71312018-08-03 23:36:13678 EXPECT_TRUE(ExecJs(root, script));
naskofaa01fb2016-04-30 01:04:17679 EXPECT_EQ(2U, root->child_count());
680 observer.Wait();
681
Lukasz Anforowicz42d3d07f2019-06-19 01:06:42682 EXPECT_TRUE(root->child_at(1)->current_url().IsAboutSrcdoc());
Peter Kastingeb8c3ce2021-08-20 04:39:35683 EvalJsResult js_result = EvalJs(root->child_at(1), "self.origin");
Mike West800532c2021-10-14 09:26:52684 EXPECT_EQ(root->current_frame_host()
685 ->GetLastCommittedURL()
686 .DeprecatedGetOriginAsURL(),
Peter Kastingeb8c3ce2021-08-20 04:39:35687 GURL(js_result.ExtractString()));
Mike West800532c2021-10-14 09:26:52688 EXPECT_NE(child->current_frame_host()
689 ->GetLastCommittedURL()
690 .DeprecatedGetOriginAsURL(),
Peter Kastingeb8c3ce2021-08-20 04:39:35691 GURL(js_result.ExtractString()));
naskofaa01fb2016-04-30 01:04:17692 }
693
694 // Set srcdoc on the existing cross-site frame. It should navigate the frame
695 // back to the origin of the parent.
696 {
Aran Gilman37d11632019-10-08 23:07:15697 std::string script(
698 "var f = document.getElementById('child-0');"
699 "f.srcdoc = 'some content';");
naskofaa01fb2016-04-30 01:04:17700 TestNavigationObserver observer(shell()->web_contents());
Nick Carterb7e71312018-08-03 23:36:13701 EXPECT_TRUE(ExecJs(root, script));
naskofaa01fb2016-04-30 01:04:17702 observer.Wait();
703
Lukasz Anforowicz42d3d07f2019-06-19 01:06:42704 EXPECT_TRUE(child->current_url().IsAboutSrcdoc());
Avi Drissmana3144c582021-10-14 17:00:26705 EXPECT_EQ(root->current_frame_host()->GetLastCommittedOrigin().Serialize(),
706 EvalJs(child, "self.origin"));
naskofaa01fb2016-04-30 01:04:17707 }
708}
709
Ian Clelland5cbaaf82017-11-27 22:00:03710// Ensure that sandbox flags are correctly set in the main frame when set by
711// Content-Security-Policy header.
712IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, SandboxFlagsSetForMainFrame) {
713 GURL main_url(embedded_test_server()->GetURL("/csp_sandboxed_frame.html"));
714 EXPECT_TRUE(NavigateToURL(shell(), main_url));
715
716 // It is safe to obtain the root frame tree node here, as it doesn't change.
717 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
Carlos Caballero15caeeb2021-10-27 09:57:55718 ->GetPrimaryFrameTree()
719 .root();
Ian Clelland5cbaaf82017-11-27 22:00:03720
721 // Verify that sandbox flags are set properly for the root FrameTreeNode and
722 // RenderFrameHost. Root frame is sandboxed with "allow-scripts".
arthursonzognib93a4472020-04-10 07:38:00723 EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
Ian Clelland5cbaaf82017-11-27 22:00:03724 root->effective_frame_policy().sandbox_flags);
arthursonzognib93a4472020-04-10 07:38:00725 EXPECT_EQ(network::mojom::WebSandboxFlags::kAll &
726 ~network::mojom::WebSandboxFlags::kScripts &
727 ~network::mojom::WebSandboxFlags::kAutomaticFeatures,
Ian Clelland5cbaaf82017-11-27 22:00:03728 root->active_sandbox_flags());
729 EXPECT_EQ(root->active_sandbox_flags(),
730 root->current_frame_host()->active_sandbox_flags());
731
732 // Verify that child frames inherit sandbox flags from the root. First frame
733 // has no explicitly set flags of its own, and should inherit those from the
734 // root. Second frame is completely sandboxed.
arthursonzognib93a4472020-04-10 07:38:00735 EXPECT_EQ(network::mojom::WebSandboxFlags::kAll &
736 ~network::mojom::WebSandboxFlags::kScripts &
737 ~network::mojom::WebSandboxFlags::kAutomaticFeatures,
Ian Clelland5cbaaf82017-11-27 22:00:03738 root->child_at(0)->effective_frame_policy().sandbox_flags);
arthursonzognib93a4472020-04-10 07:38:00739 EXPECT_EQ(network::mojom::WebSandboxFlags::kAll &
740 ~network::mojom::WebSandboxFlags::kScripts &
741 ~network::mojom::WebSandboxFlags::kAutomaticFeatures,
Ian Clelland5cbaaf82017-11-27 22:00:03742 root->child_at(0)->active_sandbox_flags());
743 EXPECT_EQ(root->child_at(0)->active_sandbox_flags(),
744 root->child_at(0)->current_frame_host()->active_sandbox_flags());
arthursonzognib93a4472020-04-10 07:38:00745 EXPECT_EQ(network::mojom::WebSandboxFlags::kAll,
Ian Clelland5cbaaf82017-11-27 22:00:03746 root->child_at(1)->effective_frame_policy().sandbox_flags);
arthursonzognib93a4472020-04-10 07:38:00747 EXPECT_EQ(network::mojom::WebSandboxFlags::kAll,
Ian Clelland5cbaaf82017-11-27 22:00:03748 root->child_at(1)->active_sandbox_flags());
749 EXPECT_EQ(root->child_at(1)->active_sandbox_flags(),
750 root->child_at(1)->current_frame_host()->active_sandbox_flags());
751
752 // Navigating the main frame to a different URL should clear sandbox flags.
753 GURL unsandboxed_url(embedded_test_server()->GetURL("/title1.html"));
Lukasz Anforowicz69c25dfd2020-11-12 21:50:20754 EXPECT_TRUE(NavigateToURLFromRenderer(root, unsandboxed_url));
Ian Clelland5cbaaf82017-11-27 22:00:03755
756 // Verify that sandbox flags are cleared properly for the root FrameTreeNode
757 // and RenderFrameHost.
arthursonzognib93a4472020-04-10 07:38:00758 EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
Ian Clelland5cbaaf82017-11-27 22:00:03759 root->effective_frame_policy().sandbox_flags);
arthursonzognib93a4472020-04-10 07:38:00760 EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
761 root->active_sandbox_flags());
762 EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
Ian Clelland5cbaaf82017-11-27 22:00:03763 root->current_frame_host()->active_sandbox_flags());
764}
765
alexmosf832a2f2015-01-27 22:44:03766// Ensure that sandbox flags are correctly set when child frames are created.
767IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, SandboxFlagsSetForChildFrames) {
768 GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
769 EXPECT_TRUE(NavigateToURL(shell(), main_url));
770
771 // It is safe to obtain the root frame tree node here, as it doesn't change.
772 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
Carlos Caballero15caeeb2021-10-27 09:57:55773 ->GetPrimaryFrameTree()
774 .root();
alexmosf832a2f2015-01-27 22:44:03775
776 // Verify that sandbox flags are set properly for all FrameTreeNodes.
777 // First frame is completely sandboxed; second frame uses "allow-scripts",
778 // which resets both SandboxFlags::Scripts and
779 // SandboxFlags::AutomaticFeatures bits per blink::parseSandboxPolicy(), and
780 // third frame has "allow-scripts allow-same-origin".
arthursonzognib93a4472020-04-10 07:38:00781 EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
Ian Clellandcdc4f312017-10-13 22:24:12782 root->effective_frame_policy().sandbox_flags);
arthursonzognib93a4472020-04-10 07:38:00783 EXPECT_EQ(network::mojom::WebSandboxFlags::kAll,
Ian Clellandcdc4f312017-10-13 22:24:12784 root->child_at(0)->effective_frame_policy().sandbox_flags);
arthursonzognib93a4472020-04-10 07:38:00785 EXPECT_EQ(network::mojom::WebSandboxFlags::kAll &
786 ~network::mojom::WebSandboxFlags::kScripts &
787 ~network::mojom::WebSandboxFlags::kAutomaticFeatures,
Ian Clellandcdc4f312017-10-13 22:24:12788 root->child_at(1)->effective_frame_policy().sandbox_flags);
arthursonzognib93a4472020-04-10 07:38:00789 EXPECT_EQ(network::mojom::WebSandboxFlags::kAll &
790 ~network::mojom::WebSandboxFlags::kScripts &
791 ~network::mojom::WebSandboxFlags::kAutomaticFeatures &
792 ~network::mojom::WebSandboxFlags::kOrigin,
Ian Clellandcdc4f312017-10-13 22:24:12793 root->child_at(2)->effective_frame_policy().sandbox_flags);
alexmosf832a2f2015-01-27 22:44:03794
795 // Sandboxed frames should set a unique origin unless they have the
796 // "allow-same-origin" directive.
alexmos6e940102016-01-19 22:47:25797 EXPECT_EQ("null", root->child_at(0)->current_origin().Serialize());
798 EXPECT_EQ("null", root->child_at(1)->current_origin().Serialize());
Mike West800532c2021-10-14 09:26:52799 EXPECT_EQ(main_url.DeprecatedGetOriginAsURL().spec(),
alexmos6e940102016-01-19 22:47:25800 root->child_at(2)->current_origin().Serialize() + "/");
alexmosf832a2f2015-01-27 22:44:03801
802 // Navigating to a different URL should not clear sandbox flags.
803 GURL frame_url(embedded_test_server()->GetURL("/title1.html"));
804 NavigateFrameToURL(root->child_at(0), frame_url);
arthursonzognib93a4472020-04-10 07:38:00805 EXPECT_EQ(network::mojom::WebSandboxFlags::kAll,
Ian Clellandcdc4f312017-10-13 22:24:12806 root->child_at(0)->effective_frame_policy().sandbox_flags);
alexmosf832a2f2015-01-27 22:44:03807}
808
Ian Clelland5cbaaf82017-11-27 22:00:03809// Ensure that sandbox flags are correctly set in the child frames when set by
810// Content-Security-Policy header, and in combination with the sandbox iframe
811// attribute.
812IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest,
813 SandboxFlagsSetByCSPForChildFrames) {
814 GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames_csp.html"));
815 EXPECT_TRUE(NavigateToURL(shell(), main_url));
816
817 // It is safe to obtain the root frame tree node here, as it doesn't change.
818 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
Carlos Caballero15caeeb2021-10-27 09:57:55819 ->GetPrimaryFrameTree()
820 .root();
Ian Clelland5cbaaf82017-11-27 22:00:03821
822 // Verify that sandbox flags are set properly for all FrameTreeNodes.
823 // First frame has no iframe sandbox flags, but the framed document is served
824 // with a CSP header which sets "allow-scripts", "allow-popups" and
825 // "allow-pointer-lock".
826 // Second frame is sandboxed with "allow-scripts", "allow-pointer-lock" and
827 // "allow-orientation-lock", and the framed document is also served with a CSP
828 // header which uses "allow-popups" and "allow-pointer-lock". The resulting
829 // sandbox for the frame should only have "allow-pointer-lock".
arthursonzognib93a4472020-04-10 07:38:00830 EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
Ian Clelland5cbaaf82017-11-27 22:00:03831 root->effective_frame_policy().sandbox_flags);
arthursonzognib93a4472020-04-10 07:38:00832 EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
833 root->active_sandbox_flags());
Ian Clelland5cbaaf82017-11-27 22:00:03834 EXPECT_EQ(root->active_sandbox_flags(),
835 root->current_frame_host()->active_sandbox_flags());
arthursonzognib93a4472020-04-10 07:38:00836 EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
Ian Clelland5cbaaf82017-11-27 22:00:03837 root->child_at(0)->effective_frame_policy().sandbox_flags);
Arthur Sonzogni4ba3104f2022-03-09 09:04:39838 EXPECT_EQ(
839 network::mojom::WebSandboxFlags::kAll &
840 ~network::mojom::WebSandboxFlags::kAutomaticFeatures &
841 ~network::mojom::WebSandboxFlags::kPointerLock &
842 ~network::mojom::WebSandboxFlags::kPopups &
843 ~network::mojom::WebSandboxFlags::kScripts &
844 ~network::mojom::WebSandboxFlags::kTopNavigationToCustomProtocols,
845 root->child_at(0)->active_sandbox_flags());
Ian Clelland5cbaaf82017-11-27 22:00:03846 EXPECT_EQ(root->child_at(0)->active_sandbox_flags(),
847 root->child_at(0)->current_frame_host()->active_sandbox_flags());
arthursonzognib93a4472020-04-10 07:38:00848 EXPECT_EQ(network::mojom::WebSandboxFlags::kAll &
849 ~network::mojom::WebSandboxFlags::kScripts &
850 ~network::mojom::WebSandboxFlags::kAutomaticFeatures &
851 ~network::mojom::WebSandboxFlags::kPointerLock &
852 ~network::mojom::WebSandboxFlags::kOrientationLock,
Ian Clelland5cbaaf82017-11-27 22:00:03853 root->child_at(1)->effective_frame_policy().sandbox_flags);
arthursonzognib93a4472020-04-10 07:38:00854 EXPECT_EQ(network::mojom::WebSandboxFlags::kAll &
855 ~network::mojom::WebSandboxFlags::kScripts &
856 ~network::mojom::WebSandboxFlags::kAutomaticFeatures &
857 ~network::mojom::WebSandboxFlags::kPointerLock,
Ian Clelland5cbaaf82017-11-27 22:00:03858 root->child_at(1)->active_sandbox_flags());
859 EXPECT_EQ(root->child_at(1)->active_sandbox_flags(),
860 root->child_at(1)->current_frame_host()->active_sandbox_flags());
861
862 // Navigating to a different URL *should* clear CSP-set sandbox flags, but
863 // should retain those flags set by the frame owner.
864 GURL frame_url(embedded_test_server()->GetURL("/title1.html"));
865
Lukasz Anforowicz69c25dfd2020-11-12 21:50:20866 EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
arthursonzognib93a4472020-04-10 07:38:00867 EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
Ian Clelland5cbaaf82017-11-27 22:00:03868 root->child_at(0)->effective_frame_policy().sandbox_flags);
arthursonzognib93a4472020-04-10 07:38:00869 EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
Ian Clelland5cbaaf82017-11-27 22:00:03870 root->child_at(0)->active_sandbox_flags());
871 EXPECT_EQ(root->child_at(0)->active_sandbox_flags(),
872 root->child_at(0)->current_frame_host()->active_sandbox_flags());
873
Lukasz Anforowicz69c25dfd2020-11-12 21:50:20874 EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(1), frame_url));
arthursonzognib93a4472020-04-10 07:38:00875 EXPECT_EQ(network::mojom::WebSandboxFlags::kAll &
876 ~network::mojom::WebSandboxFlags::kScripts &
877 ~network::mojom::WebSandboxFlags::kAutomaticFeatures &
878 ~network::mojom::WebSandboxFlags::kPointerLock &
879 ~network::mojom::WebSandboxFlags::kOrientationLock,
Ian Clelland5cbaaf82017-11-27 22:00:03880 root->child_at(1)->effective_frame_policy().sandbox_flags);
arthursonzognib93a4472020-04-10 07:38:00881 EXPECT_EQ(network::mojom::WebSandboxFlags::kAll &
882 ~network::mojom::WebSandboxFlags::kScripts &
883 ~network::mojom::WebSandboxFlags::kAutomaticFeatures &
884 ~network::mojom::WebSandboxFlags::kPointerLock &
885 ~network::mojom::WebSandboxFlags::kOrientationLock,
Ian Clelland5cbaaf82017-11-27 22:00:03886 root->child_at(1)->active_sandbox_flags());
887 EXPECT_EQ(root->child_at(1)->active_sandbox_flags(),
888 root->child_at(1)->current_frame_host()->active_sandbox_flags());
889}
890
alexmose201c7cd2015-06-10 17:14:21891// Ensure that a popup opened from a subframe sets its opener to the subframe's
892// FrameTreeNode, and that the opener is cleared if the subframe is destroyed.
893IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, SubframeOpenerSetForNewWindow) {
894 GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
895 EXPECT_TRUE(NavigateToURL(shell(), main_url));
896
897 // It is safe to obtain the root frame tree node here, as it doesn't change.
898 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
Carlos Caballero15caeeb2021-10-27 09:57:55899 ->GetPrimaryFrameTree()
900 .root();
alexmose201c7cd2015-06-10 17:14:21901
902 // Open a new window from a subframe.
903 ShellAddedObserver new_shell_observer;
904 GURL popup_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
Nick Carterb7e71312018-08-03 23:36:13905 EXPECT_TRUE(
906 ExecJs(root->child_at(0), JsReplace("window.open($1);", popup_url)));
alexmose201c7cd2015-06-10 17:14:21907 Shell* new_shell = new_shell_observer.GetShell();
908 WebContents* new_contents = new_shell->web_contents();
Fergal Dalyf0522332020-07-18 06:09:46909 EXPECT_TRUE(WaitForLoadStop(new_contents));
alexmose201c7cd2015-06-10 17:14:21910
911 // Check that the new window's opener points to the correct subframe on
912 // original window.
913 FrameTreeNode* popup_root =
Carlos Caballero15caeeb2021-10-27 09:57:55914 static_cast<WebContentsImpl*>(new_contents)->GetPrimaryFrameTree().root();
alexmose201c7cd2015-06-10 17:14:21915 EXPECT_EQ(root->child_at(0), popup_root->opener());
916
917 // Close the original window. This should clear the new window's opener.
918 shell()->Close();
919 EXPECT_EQ(nullptr, popup_root->opener());
920}
921
Shivani Sharmac4f561582018-11-15 15:58:39922// Tests that the user activation bits get cleared when a same-site document is
923// installed in the frame.
924IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest,
925 ClearUserActivationForNewDocument) {
926 GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
927 EXPECT_TRUE(NavigateToURL(shell(), main_url));
928
929 // It is safe to obtain the root frame tree node here, as it doesn't change.
930 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
Carlos Caballero15caeeb2021-10-27 09:57:55931 ->GetPrimaryFrameTree()
932 .root();
Shivani Sharmac4f561582018-11-15 15:58:39933
Mustaq Ahmed4baa9a6e82019-12-20 23:43:46934 EXPECT_FALSE(root->HasStickyUserActivation());
Shivani Sharmac4f561582018-11-15 15:58:39935 EXPECT_FALSE(root->HasTransientUserActivation());
936
937 // Set the user activation bits.
938 root->UpdateUserActivationState(
Mustaq Ahmeddc195e5b2020-08-04 18:45:11939 blink::mojom::UserActivationUpdateType::kNotifyActivation,
940 blink::mojom::UserActivationNotificationType::kTest);
Mustaq Ahmed4baa9a6e82019-12-20 23:43:46941 EXPECT_TRUE(root->HasStickyUserActivation());
Shivani Sharmac4f561582018-11-15 15:58:39942 EXPECT_TRUE(root->HasTransientUserActivation());
943
944 // Install a new same-site document to check the clearing of user activation
945 // bits.
946 GURL url(embedded_test_server()->GetURL("/title1.html"));
947 EXPECT_TRUE(NavigateToURL(shell(), url));
948
Mustaq Ahmed4baa9a6e82019-12-20 23:43:46949 EXPECT_FALSE(root->HasStickyUserActivation());
Shivani Sharmac4f561582018-11-15 15:58:39950 EXPECT_FALSE(root->HasTransientUserActivation());
951}
952
[email protected]82307f6b2014-08-07 03:30:12953class CrossProcessFrameTreeBrowserTest : public ContentBrowserTest {
954 public:
Fergal Dalya1d569972021-03-16 03:24:53955 CrossProcessFrameTreeBrowserTest() = default;
[email protected]82307f6b2014-08-07 03:30:12956
Peter Boström9b036532021-10-28 23:37:28957 CrossProcessFrameTreeBrowserTest(const CrossProcessFrameTreeBrowserTest&) =
958 delete;
959 CrossProcessFrameTreeBrowserTest& operator=(
960 const CrossProcessFrameTreeBrowserTest&) = delete;
961
dchengc2282aa2014-10-21 12:07:58962 void SetUpCommandLine(base::CommandLine* command_line) override {
nickd30fd962015-07-27 21:51:08963 IsolateAllSitesForTesting(command_line);
[email protected]82307f6b2014-08-07 03:30:12964 }
965
alexmos478dcbb2014-12-10 21:24:46966 void SetUpOnMainThread() override {
967 host_resolver()->AddRule("*", "127.0.0.1");
alexmos478dcbb2014-12-10 21:24:46968 SetupCrossSiteRedirector(embedded_test_server());
martijn12d2dad2016-11-11 10:59:27969 ASSERT_TRUE(embedded_test_server()->Start());
alexmos478dcbb2014-12-10 21:24:46970 }
[email protected]82307f6b2014-08-07 03:30:12971};
972
973// Ensure that we can complete a cross-process subframe navigation.
[email protected]82307f6b2014-08-07 03:30:12974IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
nasko83fe5dc2015-07-01 16:34:19975 CreateCrossProcessSubframeProxies) {
alexmos478dcbb2014-12-10 21:24:46976 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
Alex Moshchukaa95adf52019-08-13 00:02:02977 EXPECT_TRUE(NavigateToURL(shell(), main_url));
[email protected]82307f6b2014-08-07 03:30:12978
979 // It is safe to obtain the root frame tree node here, as it doesn't change.
980 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
Carlos Caballero15caeeb2021-10-27 09:57:55981 ->GetPrimaryFrameTree()
982 .root();
[email protected]82307f6b2014-08-07 03:30:12983
[email protected]14522ce42014-08-08 18:56:16984 // There should not be a proxy for the root's own SiteInstance.
Sharon Yang7424bda2021-11-04 20:27:43985 SiteInstanceImpl* root_instance =
986 root->current_frame_host()->GetSiteInstance();
Harkiran Bolariad22a1dca2022-02-22 17:01:12987 EXPECT_FALSE(root->current_frame_host()
988 ->browsing_context_state()
989 ->GetRenderFrameProxyHost(root_instance->group()));
[email protected]14522ce42014-08-08 18:56:16990
[email protected]82307f6b2014-08-07 03:30:12991 // Load same-site page into iframe.
alexmos478dcbb2014-12-10 21:24:46992 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
Lukasz Anforowicz69c25dfd2020-11-12 21:50:20993 EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), http_url));
[email protected]82307f6b2014-08-07 03:30:12994
[email protected]82307f6b2014-08-07 03:30:12995 // Load cross-site page into iframe.
alexmos478dcbb2014-12-10 21:24:46996 GURL cross_site_url(
997 embedded_test_server()->GetURL("foo.com", "/title2.html"));
Lukasz Anforowicz69c25dfd2020-11-12 21:50:20998 EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), cross_site_url));
[email protected]82307f6b2014-08-07 03:30:12999
1000 // Ensure that we have created a new process for the subframe.
naskoe6edde32014-10-17 15:36:481001 ASSERT_EQ(2U, root->child_count());
[email protected]82307f6b2014-08-07 03:30:121002 FrameTreeNode* child = root->child_at(0);
Sharon Yang7424bda2021-11-04 20:27:431003 SiteInstanceImpl* child_instance =
1004 child->current_frame_host()->GetSiteInstance();
[email protected]82307f6b2014-08-07 03:30:121005 RenderViewHost* rvh = child->current_frame_host()->render_view_host();
1006 RenderProcessHost* rph = child->current_frame_host()->GetProcess();
1007
Dave Tapuska327c06c92022-06-13 20:31:511008 EXPECT_NE(shell()->web_contents()->GetPrimaryMainFrame()->GetRenderViewHost(),
1009 rvh);
[email protected]14522ce42014-08-08 18:56:161010 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), child_instance);
Dave Tapuska327c06c92022-06-13 20:31:511011 EXPECT_NE(shell()->web_contents()->GetPrimaryMainFrame()->GetProcess(), rph);
[email protected]82307f6b2014-08-07 03:30:121012
1013 // Ensure that the root node has a proxy for the child node's SiteInstance.
Harkiran Bolariad22a1dca2022-02-22 17:01:121014 EXPECT_TRUE(root->current_frame_host()
1015 ->browsing_context_state()
1016 ->GetRenderFrameProxyHost(child_instance->group()));
[email protected]82307f6b2014-08-07 03:30:121017
1018 // Also ensure that the child has a proxy for the root node's SiteInstance.
Harkiran Bolariad22a1dca2022-02-22 17:01:121019 EXPECT_TRUE(child->current_frame_host()
1020 ->browsing_context_state()
1021 ->GetRenderFrameProxyHost(root_instance->group()));
[email protected]14522ce42014-08-08 18:56:161022
1023 // The nodes should not have proxies for their own SiteInstance.
Harkiran Bolariad22a1dca2022-02-22 17:01:121024 EXPECT_FALSE(root->current_frame_host()
1025 ->browsing_context_state()
1026 ->GetRenderFrameProxyHost(root_instance->group()));
1027 EXPECT_FALSE(child->current_frame_host()
1028 ->browsing_context_state()
1029 ->GetRenderFrameProxyHost(child_instance->group()));
creise42f2a52014-09-18 18:14:571030
1031 // Ensure that the RenderViews and RenderFrames are all live.
1032 EXPECT_TRUE(
1033 root->current_frame_host()->render_view_host()->IsRenderViewLive());
1034 EXPECT_TRUE(
1035 child->current_frame_host()->render_view_host()->IsRenderViewLive());
1036 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
1037 EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
[email protected]82307f6b2014-08-07 03:30:121038}
1039
alexmosbc7eafa2014-12-06 01:38:091040IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
Nasko Oskov039121012019-01-11 00:21:321041 OriginSetOnNavigations) {
alexmos478dcbb2014-12-10 21:24:461042 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
alexmosbc7eafa2014-12-06 01:38:091043 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1044
1045 // It is safe to obtain the root frame tree node here, as it doesn't change.
1046 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
Carlos Caballero15caeeb2021-10-27 09:57:551047 ->GetPrimaryFrameTree()
1048 .root();
alexmosbc7eafa2014-12-06 01:38:091049
creisabdd2bd62015-11-21 01:14:581050 EXPECT_EQ(root->current_origin().Serialize() + '/',
Mike West800532c2021-10-14 09:26:521051 main_url.DeprecatedGetOriginAsURL().spec());
alexmosbc7eafa2014-12-06 01:38:091052
1053 // First frame is an about:blank frame. Check that its origin is correctly
1054 // inherited from the parent.
creisabdd2bd62015-11-21 01:14:581055 EXPECT_EQ(root->child_at(0)->current_origin().Serialize() + '/',
Mike West800532c2021-10-14 09:26:521056 main_url.DeprecatedGetOriginAsURL().spec());
alexmosbc7eafa2014-12-06 01:38:091057
1058 // Second frame loads a same-site page. Its origin should also be the same
1059 // as the parent.
creisabdd2bd62015-11-21 01:14:581060 EXPECT_EQ(root->child_at(1)->current_origin().Serialize() + '/',
Mike West800532c2021-10-14 09:26:521061 main_url.DeprecatedGetOriginAsURL().spec());
alexmosbc7eafa2014-12-06 01:38:091062
alexmosbc7eafa2014-12-06 01:38:091063 // Load cross-site page into the first frame.
alexmos478dcbb2014-12-10 21:24:461064 GURL cross_site_url(
1065 embedded_test_server()->GetURL("foo.com", "/title2.html"));
Lukasz Anforowicz69c25dfd2020-11-12 21:50:201066 EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), cross_site_url));
alexmosbc7eafa2014-12-06 01:38:091067
creisabdd2bd62015-11-21 01:14:581068 EXPECT_EQ(root->child_at(0)->current_origin().Serialize() + '/',
Mike West800532c2021-10-14 09:26:521069 cross_site_url.DeprecatedGetOriginAsURL().spec());
alexmosbc7eafa2014-12-06 01:38:091070
1071 // The root's origin shouldn't have changed.
creisabdd2bd62015-11-21 01:14:581072 EXPECT_EQ(root->current_origin().Serialize() + '/',
Mike West800532c2021-10-14 09:26:521073 main_url.DeprecatedGetOriginAsURL().spec());
alexmosbc7eafa2014-12-06 01:38:091074
Nasko Oskov039121012019-01-11 00:21:321075 {
1076 GURL data_url("data:text/html,foo");
1077 TestNavigationObserver observer(shell()->web_contents());
1078 EXPECT_TRUE(
1079 ExecJs(root->child_at(1), JsReplace("window.location = $1", data_url)));
1080 observer.Wait();
1081 }
alexmosbc7eafa2014-12-06 01:38:091082
1083 // Navigating to a data URL should set a unique origin. This is represented
Nasko Oskov039121012019-01-11 00:21:321084 // as "null" per RFC 6454. A frame navigating itself to a data: URL does not
1085 // require a process transfer, but should retain the original origin
1086 // as its precursor.
creisabdd2bd62015-11-21 01:14:581087 EXPECT_EQ(root->child_at(1)->current_origin().Serialize(), "null");
Nasko Oskov039121012019-01-11 00:21:321088 EXPECT_TRUE(root->child_at(1)->current_origin().opaque());
1089 ASSERT_EQ(
1090 url::SchemeHostPort(main_url),
1091 root->child_at(1)->current_origin().GetTupleOrPrecursorTupleIfOpaque())
1092 << "Expected the precursor origin to be preserved; should be the "
1093 "initiator of a data: navigation.";
1094
1095 // Adding an <iframe sandbox srcdoc=> frame should result in a unique origin
1096 // that is different-origin from its data: URL parent.
1097 {
1098 TestNavigationObserver observer(shell()->web_contents());
1099
1100 ASSERT_EQ(0U, root->child_at(1)->child_count());
1101 EXPECT_TRUE(
1102 ExecJs(root->child_at(1), JsReplace(
1103 R"(
1104 var iframe = document.createElement('iframe');
1105 iframe.setAttribute('sandbox', 'allow-scripts');
1106 iframe.srcdoc = $1;
1107 document.body.appendChild(iframe);
1108 )",
1109 "<html><body>This sandboxed doc should "
1110 "be different-origin.</body></html>")));
1111 observer.Wait();
1112 ASSERT_EQ(1U, root->child_at(1)->child_count());
1113 }
1114
1115 url::Origin root_origin = root->current_origin();
1116 url::Origin child_1 = root->child_at(1)->current_origin();
1117 url::Origin child_1_0 = root->child_at(1)->child_at(0)->current_origin();
1118 EXPECT_FALSE(root_origin.opaque());
1119 EXPECT_TRUE(child_1.opaque());
1120 EXPECT_TRUE(child_1_0.opaque());
1121 EXPECT_NE(child_1, child_1_0);
1122 EXPECT_EQ(url::SchemeHostPort(main_url),
1123 root_origin.GetTupleOrPrecursorTupleIfOpaque());
1124 EXPECT_EQ(url::SchemeHostPort(main_url),
1125 child_1.GetTupleOrPrecursorTupleIfOpaque());
1126 EXPECT_EQ(url::SchemeHostPort(main_url),
1127 child_1_0.GetTupleOrPrecursorTupleIfOpaque());
1128
1129 {
1130 TestNavigationObserver observer(shell()->web_contents());
1131
1132 ASSERT_EQ(1U, root->child_at(1)->child_count());
1133 EXPECT_TRUE(
1134 ExecJs(root->child_at(1), JsReplace(
1135 R"(
1136 var iframe = document.createElement('iframe');
1137 iframe.srcdoc = $1;
1138 document.body.appendChild(iframe);
1139 )",
1140 "<html><body>This srcdoc document should "
1141 "be same-origin.</body></html>")));
1142 observer.Wait();
1143 ASSERT_EQ(2U, root->child_at(1)->child_count());
1144 }
1145 EXPECT_EQ(root_origin, root->current_origin());
1146 EXPECT_EQ(child_1, root->child_at(1)->current_origin());
1147 EXPECT_EQ(child_1_0, root->child_at(1)->child_at(0)->current_origin());
1148 url::Origin child_1_1 = root->child_at(1)->child_at(1)->current_origin();
1149 EXPECT_EQ(child_1, child_1_1);
1150 EXPECT_NE(child_1_0, child_1_1);
1151
1152 {
1153 TestNavigationObserver observer(shell()->web_contents());
1154
1155 ASSERT_EQ(2U, root->child_at(1)->child_count());
1156 EXPECT_TRUE(
1157 ExecJs(root->child_at(1), JsReplace(
1158 R"(
1159 var iframe = document.createElement('iframe');
1160 iframe.src = 'data:text/html;base64,' + btoa($1);
1161 document.body.appendChild(iframe);
1162 )",
1163 "<html><body>This data: doc should be "
1164 "different-origin.</body></html>")));
1165 observer.Wait();
1166 ASSERT_EQ(3U, root->child_at(1)->child_count());
1167 }
1168 EXPECT_EQ(root_origin, root->current_origin());
1169 EXPECT_EQ(child_1, root->child_at(1)->current_origin());
1170 EXPECT_EQ(child_1_0, root->child_at(1)->child_at(0)->current_origin());
1171 EXPECT_EQ(child_1_1, root->child_at(1)->child_at(1)->current_origin());
1172 url::Origin child_1_2 = root->child_at(1)->child_at(2)->current_origin();
1173 EXPECT_NE(child_1, child_1_2);
1174 EXPECT_NE(child_1_0, child_1_2);
1175 EXPECT_NE(child_1_1, child_1_2);
1176 EXPECT_EQ(url::SchemeHostPort(main_url),
1177 child_1_2.GetTupleOrPrecursorTupleIfOpaque());
1178
1179 // If the parent navigates its child to a data URL, it should transfer
1180 // to the parent's process, and the precursor origin should track the
1181 // parent's origin.
1182 {
1183 GURL data_url("data:text/html,foo2");
1184 TestNavigationObserver observer(shell()->web_contents());
1185 EXPECT_TRUE(ExecJs(root, JsReplace("frames[0].location = $1", data_url)));
1186 observer.Wait();
1187 EXPECT_EQ(data_url, root->child_at(0)->current_url());
1188 }
1189
1190 EXPECT_EQ(root->child_at(0)->current_origin().Serialize(), "null");
1191 EXPECT_TRUE(root->child_at(0)->current_origin().opaque());
1192 EXPECT_EQ(
1193 url::SchemeHostPort(main_url),
1194 root->child_at(0)->current_origin().GetTupleOrPrecursorTupleIfOpaque());
1195 EXPECT_EQ(root->current_frame_host()->GetProcess(),
1196 root->child_at(0)->current_frame_host()->GetProcess());
1197}
1198
1199// Test to verify that a blob: URL that is created by a unique opaque origin
1200// will correctly set the origin_to_commit on a session history navigation.
1201IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
1202 OriginForBlobUrlsFromUniqueOpaqueOrigin) {
1203 // Start off with a navigation to data: URL in the main frame. It should
1204 // result in a unique opaque origin without any precursor information.
1205 GURL data_url("data:text/html,foo<iframe id='child' src='" +
1206 embedded_test_server()->GetURL("/title1.html").spec() +
1207 "'></iframe>");
1208 EXPECT_TRUE(NavigateToURL(shell(), data_url));
1209
1210 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
Carlos Caballero15caeeb2021-10-27 09:57:551211 ->GetPrimaryFrameTree()
1212 .root();
Nasko Oskov039121012019-01-11 00:21:321213 EXPECT_TRUE(root->current_origin().opaque());
Nasko Oskov55119382020-01-17 18:22:181214 EXPECT_FALSE(
1215 root->current_origin().GetTupleOrPrecursorTupleIfOpaque().IsValid());
Nasko Oskov039121012019-01-11 00:21:321216 EXPECT_EQ(1UL, root->child_count());
1217 FrameTreeNode* child = root->child_at(0);
1218
1219 // Create a blob: URL and navigate the child frame to it.
1220 std::string html = "<html><body>This is blob content.</body></html>";
1221 std::string script = JsReplace(
1222 "var blob = new Blob([$1], {type: 'text/html'});"
1223 "var blob_url = URL.createObjectURL(blob);"
1224 "document.getElementById('child').src = blob_url;"
1225 "blob_url;",
1226 html);
1227 GURL blob_url;
1228 {
1229 TestFrameNavigationObserver observer(child);
1230 blob_url = GURL(EvalJs(root, script).ExtractString());
1231 observer.Wait();
1232 EXPECT_EQ(blob_url, child->current_frame_host()->GetLastCommittedURL());
1233 }
1234
1235 // We expect the frame to have committed in an opaque origin which contains
1236 // the same precursor information - none.
1237 url::Origin blob_origin = child->current_origin();
1238 EXPECT_TRUE(blob_origin.opaque());
1239 EXPECT_EQ(root->current_origin().GetTupleOrPrecursorTupleIfOpaque(),
1240 blob_origin.GetTupleOrPrecursorTupleIfOpaque());
Rakina Zata Amnic7367852022-11-07 17:10:401241 EXPECT_FALSE(
1242 child->current_origin().GetTupleOrPrecursorTupleIfOpaque().IsValid());
Nasko Oskov039121012019-01-11 00:21:321243
1244 // Navigate the frame away to any web URL.
1245 {
1246 GURL url(embedded_test_server()->GetURL("/title2.html"));
1247 TestFrameNavigationObserver observer(child);
1248 EXPECT_TRUE(ExecJs(child, JsReplace("window.location = $1", url)));
1249 observer.Wait();
1250 EXPECT_EQ(url, child->current_frame_host()->GetLastCommittedURL());
1251 }
1252 EXPECT_FALSE(child->current_origin().opaque());
1253 EXPECT_TRUE(shell()->web_contents()->GetController().CanGoBack());
1254 EXPECT_EQ(3, shell()->web_contents()->GetController().GetEntryCount());
1255 EXPECT_EQ(
1256 2, shell()->web_contents()->GetController().GetLastCommittedEntryIndex());
1257
1258 // Verify the blob URL still exists in the main frame, which keeps it alive
1259 // allowing a session history navigation back to succeed.
1260 EXPECT_EQ(blob_url, GURL(EvalJs(root, "blob_url;").ExtractString()));
1261
1262 // Now navigate back in session history. It should successfully go back to
Rakina Zata Amnic7367852022-11-07 17:10:401263 // the blob: URL. The child frame won't be reusing the exact same origin it
1264 // used before, but it will commit a new opaque origin which will still have
1265 // no precursor information.
Nasko Oskov039121012019-01-11 00:21:321266 {
1267 TestFrameNavigationObserver observer(child);
1268 shell()->web_contents()->GetController().GoBack();
1269 observer.Wait();
1270 }
1271 EXPECT_EQ(blob_url, child->current_frame_host()->GetLastCommittedURL());
1272 EXPECT_TRUE(child->current_origin().opaque());
Rakina Zata Amnic7367852022-11-07 17:10:401273 EXPECT_NE(blob_origin, child->current_origin());
Nasko Oskov039121012019-01-11 00:21:321274 EXPECT_EQ(root->current_origin().GetTupleOrPrecursorTupleIfOpaque(),
1275 child->current_origin().GetTupleOrPrecursorTupleIfOpaque());
Rakina Zata Amnic7367852022-11-07 17:10:401276 EXPECT_FALSE(
1277 child->current_origin().GetTupleOrPrecursorTupleIfOpaque().IsValid());
Nasko Oskov039121012019-01-11 00:21:321278}
1279
1280// Test to verify that about:blank iframe, which is a child of a sandboxed
1281// iframe is not considered same origin, but precursor information is preserved
1282// in its origin.
1283IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
1284 AboutBlankSubframeInSandboxedFrame) {
1285 // Start off by navigating to a page with sandboxed iframe, which allows
1286 // script execution.
1287 GURL main_url(
1288 embedded_test_server()->GetURL("/sandboxed_main_frame_script.html"));
1289 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1290
1291 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
Carlos Caballero15caeeb2021-10-27 09:57:551292 ->GetPrimaryFrameTree()
1293 .root();
Nasko Oskov039121012019-01-11 00:21:321294 EXPECT_EQ(1UL, root->child_count());
1295 FrameTreeNode* child = root->child_at(0);
1296
1297 // Navigate the frame to data: URL to cause it to have an opaque origin that
1298 // is derived from the |main_url| origin.
1299 GURL data_url("data:text/html,<html><body>foo</body></html>");
1300 {
1301 TestFrameNavigationObserver observer(child);
1302 EXPECT_TRUE(ExecJs(root, JsReplace("frames[0].location = $1", data_url)));
1303 observer.Wait();
1304 EXPECT_EQ(data_url, child->current_frame_host()->GetLastCommittedURL());
1305 }
1306
1307 // Add an about:blank iframe to the data: frame, which should not inherit the
1308 // origin, but should preserve the precursor information.
1309 {
1310 EXPECT_TRUE(ExecJs(child,
1311 "var f = document.createElement('iframe');"
1312 "document.body.appendChild(f);"));
1313 }
1314 EXPECT_EQ(1UL, child->child_count());
1315 FrameTreeNode* grandchild = child->child_at(0);
1316
1317 EXPECT_TRUE(grandchild->current_origin().opaque());
1318 EXPECT_EQ(GURL(url::kAboutBlankURL),
1319 grandchild->current_frame_host()->GetLastCommittedURL());
1320
1321 // The origin of the data: document should have precursor information matching
1322 // the main frame origin.
1323 EXPECT_EQ(root->current_origin().GetTupleOrPrecursorTupleIfOpaque(),
1324 child->current_origin().GetTupleOrPrecursorTupleIfOpaque());
1325
1326 // The same should hold also for the about:blank subframe of the data: frame.
1327 EXPECT_EQ(root->current_origin().GetTupleOrPrecursorTupleIfOpaque(),
1328 grandchild->current_origin().GetTupleOrPrecursorTupleIfOpaque());
1329
1330 // The about:blank document should not be able to access its parent, as they
1331 // are considered cross origin due to the sandbox flags on the parent.
1332 EXPECT_FALSE(ExecJs(grandchild, "window.parent.foo = 'bar';"));
1333 EXPECT_NE(child->current_origin(), grandchild->current_origin());
alexmosbc7eafa2014-12-06 01:38:091334}
1335
Ian Clelland5cbaaf82017-11-27 22:00:031336// Ensure that a popup opened from a sandboxed main frame inherits sandbox flags
1337// from its opener.
1338IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
1339 SandboxFlagsSetForNewWindow) {
1340 GURL main_url(
1341 embedded_test_server()->GetURL("/sandboxed_main_frame_script.html"));
1342 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1343
1344 // It is safe to obtain the root frame tree node here, as it doesn't change.
1345 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
Carlos Caballero15caeeb2021-10-27 09:57:551346 ->GetPrimaryFrameTree()
1347 .root();
Ian Clelland5cbaaf82017-11-27 22:00:031348
1349 // Open a new window from the main frame.
1350 GURL popup_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
1351 Shell* new_shell = OpenPopup(root->current_frame_host(), popup_url, "");
1352 EXPECT_TRUE(new_shell);
1353 WebContents* new_contents = new_shell->web_contents();
1354
1355 // Check that the new window's sandbox flags correctly reflect the opener's
1356 // flags. Main frame sets allow-popups, allow-pointer-lock and allow-scripts.
1357 FrameTreeNode* popup_root =
Carlos Caballero15caeeb2021-10-27 09:57:551358 static_cast<WebContentsImpl*>(new_contents)->GetPrimaryFrameTree().root();
arthursonzognib93a4472020-04-10 07:38:001359 network::mojom::WebSandboxFlags main_frame_sandbox_flags =
Ian Clelland5cbaaf82017-11-27 22:00:031360 root->current_frame_host()->active_sandbox_flags();
Arthur Sonzogni4ba3104f2022-03-09 09:04:391361 EXPECT_EQ(
1362 network::mojom::WebSandboxFlags::kAll &
1363 ~network::mojom::WebSandboxFlags::kAutomaticFeatures &
1364 ~network::mojom::WebSandboxFlags::kPointerLock &
1365 ~network::mojom::WebSandboxFlags::kPopups &
1366 ~network::mojom::WebSandboxFlags::kScripts &
1367 ~network::mojom::WebSandboxFlags::kTopNavigationToCustomProtocols,
1368 main_frame_sandbox_flags);
Ian Clelland5cbaaf82017-11-27 22:00:031369
1370 EXPECT_EQ(main_frame_sandbox_flags,
1371 popup_root->effective_frame_policy().sandbox_flags);
1372 EXPECT_EQ(main_frame_sandbox_flags, popup_root->active_sandbox_flags());
1373 EXPECT_EQ(main_frame_sandbox_flags,
1374 popup_root->current_frame_host()->active_sandbox_flags());
1375}
1376
Shivani Sharmac4f561582018-11-15 15:58:391377// Tests that the user activation bits get cleared when a cross-site document is
1378// installed in the frame.
1379IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
1380 ClearUserActivationForNewDocument) {
1381 GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
1382 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1383
1384 // It is safe to obtain the root frame tree node here, as it doesn't change.
1385 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
Carlos Caballero15caeeb2021-10-27 09:57:551386 ->GetPrimaryFrameTree()
1387 .root();
Shivani Sharmac4f561582018-11-15 15:58:391388
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461389 EXPECT_FALSE(root->HasStickyUserActivation());
Shivani Sharmac4f561582018-11-15 15:58:391390 EXPECT_FALSE(root->HasTransientUserActivation());
1391
1392 // Set the user activation bits.
1393 root->UpdateUserActivationState(
Mustaq Ahmeddc195e5b2020-08-04 18:45:111394 blink::mojom::UserActivationUpdateType::kNotifyActivation,
1395 blink::mojom::UserActivationNotificationType::kTest);
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461396 EXPECT_TRUE(root->HasStickyUserActivation());
Shivani Sharmac4f561582018-11-15 15:58:391397 EXPECT_TRUE(root->HasTransientUserActivation());
1398
1399 // Install a new cross-site document to check the clearing of user activation
1400 // bits.
1401 GURL cross_site_url(
1402 embedded_test_server()->GetURL("foo.com", "/title2.html"));
1403 EXPECT_TRUE(NavigateToURL(shell(), cross_site_url));
1404
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461405 EXPECT_FALSE(root->HasStickyUserActivation());
Shivani Sharmac4f561582018-11-15 15:58:391406 EXPECT_FALSE(root->HasTransientUserActivation());
1407}
1408
Dave Tapuska708c2732022-09-23 22:47:491409class BrowserContextGroupSwapFrameTreeBrowserTest : public ContentBrowserTest {
1410 public:
1411 BrowserContextGroupSwapFrameTreeBrowserTest()
1412 : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
1413
1414 void SetUpCommandLine(base::CommandLine* command_line) override {
1415 IsolateAllSitesForTesting(command_line);
1416 }
1417
1418 void SetUpOnMainThread() override {
1419 ContentBrowserTest::SetUpOnMainThread();
1420 host_resolver()->AddRule("*", "127.0.0.1");
1421 https_server_.ServeFilesFromSourceDirectory(GetTestDataFilePath());
1422 https_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
1423 net::test_server::RegisterDefaultHandlers(&https_server_);
1424 ASSERT_TRUE(https_server_.Start());
1425 }
1426
1427 net::EmbeddedTestServer* https_server() { return &https_server_; }
1428
1429 public:
1430 net::EmbeddedTestServer https_server_;
1431};
1432
1433// Force a race between when the RenderViewHostImpl's main frame is running
1434// the unload handlers and when a new navigation occurs that tries to
1435// reuse a RenderViewHostImpl.
1436IN_PROC_BROWSER_TEST_F(BrowserContextGroupSwapFrameTreeBrowserTest,
1437 NavigateAndGoBack) {
1438 GURL main_url(https_server()->GetURL("a.test", "/title1.html"));
1439 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1440
1441 auto* web_contents = static_cast<WebContentsImpl*>(shell()->web_contents());
1442 web_contents->GetPrimaryMainFrame()->DoNotDeleteForTesting();
1443 DisableBFCacheForRFHForTesting(
1444 web_contents->GetPrimaryFrameTree().root()->current_frame_host());
1445
1446 // Load a page with COOP set to force the browsing context group swap
1447 // and clears out old proxies.
1448 GURL new_main_url(https_server()->GetURL(
1449 "b.test", "/set-header?Cross-Origin-Opener-Policy: same-origin"));
1450
1451 EXPECT_TRUE(NavigateToURL(shell(), new_main_url));
1452
1453 TestNavigationObserver back_load_observer(web_contents);
1454 web_contents->GetController().GoBack();
1455 back_load_observer.Wait();
1456}
1457
nickdb193a12016-09-09 23:09:231458// FrameTreeBrowserTest variant where we isolate http://*.is, Iceland's top
naskoabed2a52017-05-03 05:10:171459// level domain. This is an analogue to isolating extensions, which we can use
1460// inside content_browsertests, where extensions don't exist. Iceland, like an
nickdb193a12016-09-09 23:09:231461// extension process, is a special place with magical powers; we want to protect
1462// it from outsiders.
1463class IsolateIcelandFrameTreeBrowserTest : public ContentBrowserTest {
1464 public:
Fergal Dalya1d569972021-03-16 03:24:531465 IsolateIcelandFrameTreeBrowserTest() = default;
nickdb193a12016-09-09 23:09:231466
Peter Boström9b036532021-10-28 23:37:281467 IsolateIcelandFrameTreeBrowserTest(
1468 const IsolateIcelandFrameTreeBrowserTest&) = delete;
1469 IsolateIcelandFrameTreeBrowserTest& operator=(
1470 const IsolateIcelandFrameTreeBrowserTest&) = delete;
1471
nickdb193a12016-09-09 23:09:231472 void SetUpCommandLine(base::CommandLine* command_line) override {
Lukasz Anforowicze7c87d12018-11-03 02:53:341473 // Blink suppresses navigations to blob URLs of origins different from the
alexis.menard83f1b6d2017-05-17 19:37:331474 // frame initiating the navigation. We disable those checks for this test,
1475 // to test what happens in a compromise scenario.
1476 command_line->AppendSwitch(switches::kDisableWebSecurity);
Lukasz Anforowicze7c87d12018-11-03 02:53:341477
1478 // ProcessSwitchForIsolatedBlob test below requires that one of URLs used in
Lukasz Anforowicz25420932018-12-18 20:59:221479 // the test (blob:http://b.is/) belongs to an isolated origin.
1480 command_line->AppendSwitchASCII(switches::kIsolateOrigins, "http://b.is/");
nickdb193a12016-09-09 23:09:231481 }
1482
1483 void SetUpOnMainThread() override {
1484 host_resolver()->AddRule("*", "127.0.0.1");
nickdb193a12016-09-09 23:09:231485 SetupCrossSiteRedirector(embedded_test_server());
martijn12d2dad2016-11-11 10:59:271486 ASSERT_TRUE(embedded_test_server()->Start());
nickdb193a12016-09-09 23:09:231487 }
nickdb193a12016-09-09 23:09:231488};
1489
1490// Regression test for https://crbug.com/644966
1491IN_PROC_BROWSER_TEST_F(IsolateIcelandFrameTreeBrowserTest,
1492 ProcessSwitchForIsolatedBlob) {
nickdb193a12016-09-09 23:09:231493 // Set up an iframe.
1494 WebContents* contents = shell()->web_contents();
1495 FrameTreeNode* root =
Carlos Caballero15caeeb2021-10-27 09:57:551496 static_cast<WebContentsImpl*>(contents)->GetPrimaryFrameTree().root();
nickdb193a12016-09-09 23:09:231497 GURL main_url(embedded_test_server()->GetURL(
nick07fd7e12016-09-12 18:54:061498 "a.com", "/cross_site_iframe_factory.html?a(a)"));
nickdb193a12016-09-09 23:09:231499 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1500
1501 // The navigation targets an invalid blob url; that's intentional to trigger
1502 // an error response. The response should commit in a process dedicated to
Nasko Oskov0401d812021-02-05 22:20:081503 // http://b.is or error pages, depending on policy.
Nick Carterb7e71312018-08-03 23:36:131504 EXPECT_EQ(
1505 "done",
1506 EvalJs(
1507 root,
1508 "new Promise((resolve) => {"
1509 " var iframe_element = document.getElementsByTagName('iframe')[0];"
1510 " iframe_element.onload = () => resolve('done');"
Lukasz Anforowicz25420932018-12-18 20:59:221511 " iframe_element.src = 'blob:http://b.is/';"
Nick Carterb7e71312018-08-03 23:36:131512 "});"));
Fergal Dalyf0522332020-07-18 06:09:461513 EXPECT_TRUE(WaitForLoadStop(contents));
nickdb193a12016-09-09 23:09:231514
1515 // Make sure we did a process transfer back to "b.is".
Aaron Colwelle953e562019-07-24 16:47:361516 const std::string kExpectedSiteURL =
1517 AreDefaultSiteInstancesEnabled()
1518 ? SiteInstanceImpl::GetDefaultSiteURL().spec()
1519 : "http://a.com/";
Nasko Oskov0401d812021-02-05 22:20:081520 const std::string kExpectedSubframeSiteURL =
1521 SiteIsolationPolicy::IsErrorPageIsolationEnabled(/*in_main_frame*/ false)
1522 ? "chrome-error://chromewebdata/"
1523 : "http://b.is/";
Aaron Colwelle953e562019-07-24 16:47:361524 EXPECT_EQ(base::StringPrintf(" Site A ------------ proxies for B\n"
1525 " +--Site B ------- proxies for A\n"
1526 "Where A = %s\n"
Nasko Oskov0401d812021-02-05 22:20:081527 " B = %s",
1528 kExpectedSiteURL.c_str(),
1529 kExpectedSubframeSiteURL.c_str()),
Fergal Daly79f44292020-12-01 02:30:481530 DepictFrameTree(*root));
nickdb193a12016-09-09 23:09:231531}
1532
Arthur Sonzogni64457592022-11-22 11:08:591533class FrameTreeCredentiallessIframeBrowserTest : public FrameTreeBrowserTest {
Antonio Sartori5abc8de2021-07-13 08:42:471534 public:
Arthur Sonzogni64457592022-11-22 11:08:591535 FrameTreeCredentiallessIframeBrowserTest() = default;
Antonio Sartori5abc8de2021-07-13 08:42:471536
1537 void SetUpCommandLine(base::CommandLine* command_line) override {
Antonio Sartori753cd6d2021-07-23 08:34:551538 command_line->AppendSwitch(switches::kEnableBlinkTestFeatures);
Antonio Sartori5abc8de2021-07-13 08:42:471539 }
1540};
1541
Arthur Sonzogni64457592022-11-22 11:08:591542// Tests the mojo propagation of the 'credentialless' attribute to the browser.
1543IN_PROC_BROWSER_TEST_F(FrameTreeCredentiallessIframeBrowserTest,
Antonio Sartori5abc8de2021-07-13 08:42:471544 AttributeIsPropagatedToBrowser) {
1545 GURL main_url(embedded_test_server()->GetURL("/hello.html"));
1546 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1547
1548 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
Carlos Caballero15caeeb2021-10-27 09:57:551549 ->GetPrimaryFrameTree()
1550 .root();
Antonio Sartori5abc8de2021-07-13 08:42:471551
Arthur Sonzogni64457592022-11-22 11:08:591552 // Not setting the attribute => the iframe is not credentialless.
Antonio Sartori5abc8de2021-07-13 08:42:471553 EXPECT_TRUE(ExecJs(root,
1554 "var f = document.createElement('iframe');"
1555 "document.body.appendChild(f);"));
1556 EXPECT_EQ(1U, root->child_count());
Miyoung Shinc9ff4812023-01-05 08:58:051557 EXPECT_FALSE(root->child_at(0)->Credentialless());
Yifan Luoe1a2e05d2022-01-12 16:47:591558 EXPECT_EQ(false, EvalJs(root->child_at(0)->current_frame_host(),
Arthur Sonzogni64457592022-11-22 11:08:591559 "window.credentialless"));
Antonio Sartori5abc8de2021-07-13 08:42:471560
Arthur Sonzogni64457592022-11-22 11:08:591561 // Setting the attribute on the iframe element makes the iframe
1562 // credentialless.
Antonio Sartori5abc8de2021-07-13 08:42:471563 EXPECT_TRUE(ExecJs(root,
1564 "var d = document.createElement('div');"
Arthur Sonzogni64457592022-11-22 11:08:591565 "d.innerHTML = '<iframe credentialless></iframe>';"
Antonio Sartori5abc8de2021-07-13 08:42:471566 "document.body.appendChild(d);"));
1567 EXPECT_EQ(2U, root->child_count());
Miyoung Shinc9ff4812023-01-05 08:58:051568 EXPECT_TRUE(root->child_at(1)->Credentialless());
Yifan Luo400867472022-05-19 09:34:201569 EXPECT_EQ(true, EvalJs(root->child_at(1)->current_frame_host(),
Arthur Sonzogni64457592022-11-22 11:08:591570 "window.credentialless"));
Antonio Sartori5abc8de2021-07-13 08:42:471571
1572 // Setting the attribute via javascript works.
1573 EXPECT_TRUE(ExecJs(root,
1574 "var g = document.createElement('iframe');"
Arthur Sonzogni64457592022-11-22 11:08:591575 "g.credentialless = true;"
Antonio Sartori5abc8de2021-07-13 08:42:471576 "document.body.appendChild(g);"));
1577 EXPECT_EQ(3U, root->child_count());
Miyoung Shinc9ff4812023-01-05 08:58:051578 EXPECT_TRUE(root->child_at(2)->Credentialless());
Yifan Luo400867472022-05-19 09:34:201579 EXPECT_EQ(true, EvalJs(root->child_at(2)->current_frame_host(),
Arthur Sonzogni64457592022-11-22 11:08:591580 "window.credentialless"));
Antonio Sartori5abc8de2021-07-13 08:42:471581
Arthur Sonzogni64457592022-11-22 11:08:591582 EXPECT_TRUE(ExecJs(root, "g.credentialless = false;"));
Miyoung Shinc9ff4812023-01-05 08:58:051583 EXPECT_FALSE(root->child_at(2)->Credentialless());
Yifan Luo400867472022-05-19 09:34:201584 EXPECT_EQ(true, EvalJs(root->child_at(2)->current_frame_host(),
Arthur Sonzogni64457592022-11-22 11:08:591585 "window.credentialless"));
Antonio Sartori5abc8de2021-07-13 08:42:471586
Arthur Sonzogni64457592022-11-22 11:08:591587 EXPECT_TRUE(ExecJs(root, "g.credentialless = true;"));
Miyoung Shinc9ff4812023-01-05 08:58:051588 EXPECT_TRUE(root->child_at(2)->Credentialless());
Yifan Luo400867472022-05-19 09:34:201589 EXPECT_EQ(true, EvalJs(root->child_at(2)->current_frame_host(),
Arthur Sonzogni64457592022-11-22 11:08:591590 "window.credentialless"));
Antonio Sartori5abc8de2021-07-13 08:42:471591}
1592
Ari Chivukula5d15efb2023-01-21 04:33:521593// TODO(crbug.com/1407150): Remove this when deprecation trial is complete.
1594class FrameTreeSessionStorageDeprecationTrialBrowserTest
1595 : public ContentBrowserTest {
1596 public:
1597 FrameTreeSessionStorageDeprecationTrialBrowserTest()
1598 : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
1599 feature_list_.InitAndEnableFeature(
1600 net::features::kThirdPartyStoragePartitioning);
1601 }
1602
1603 protected:
1604 void SetUpCommandLine(base::CommandLine* command_line) override {
1605 https_server_.ServeFilesFromSourceDirectory("content/test/data");
1606 // EmbeddedTestServer::InitializeAndListen() initializes its `base_url_`
1607 // which is required below. This cannot invoke Start() however as that kicks
1608 // off the "EmbeddedTestServer IO Thread" which then races with
1609 // initialization in ContentBrowserTest::SetUp(), http://crbug.com/674545.
1610 ASSERT_TRUE(https_server_.InitializeAndListen());
1611
1612 // Add a host resolver rule to map all outgoing requests to the test server.
1613 // This allows us to use "real" hostnames in URLs, which we can use to
1614 // create arbitrary SiteInstances.
1615 command_line->AppendSwitchASCII(
1616 network::switches::kHostResolverRules,
1617 "MAP * " +
1618 net::HostPortPair::FromURL(https_server_.base_url()).ToString() +
1619 ",EXCLUDE localhost");
1620 mock_cert_verifier_.SetUpCommandLine(command_line);
1621 }
1622
1623 void SetUp() override { ContentBrowserTest::SetUp(); }
1624
1625 void SetUpOnMainThread() override {
1626 // Complete the manual Start() after ContentBrowserTest's own
1627 // initialization, ref. comment on InitializeAndListen() above.
1628 https_server_.StartAcceptingConnections();
1629 mock_cert_verifier_.mock_cert_verifier()->set_default_result(net::OK);
1630 }
1631
1632 void SetUpInProcessBrowserTestFixture() override {
1633 mock_cert_verifier_.SetUpInProcessBrowserTestFixture();
1634 }
1635
1636 void TearDownInProcessBrowserTestFixture() override {
1637 mock_cert_verifier_.TearDownInProcessBrowserTestFixture();
1638 }
1639
1640 private:
1641 base::test::ScopedFeatureList feature_list_;
1642 content::ContentMockCertVerifier mock_cert_verifier_;
1643 net::EmbeddedTestServer https_server_;
1644};
1645
1646IN_PROC_BROWSER_TEST_F(FrameTreeSessionStorageDeprecationTrialBrowserTest,
1647 RegisterOriginForUnpartitionedSessionStorageAccess) {
1648 const url::Origin origin = url::Origin::Create(GURL("https://example.com"));
1649 const blink::StorageKey first_party = blink::StorageKey(origin);
1650 const blink::StorageKey third_party =
1651 blink::StorageKey::CreateWithOptionalNonce(
1652 origin, net::SchemefulSite(GURL("https://notexample.com")), nullptr,
1653 blink::mojom::AncestorChainBit::kSameSite);
1654 const url::Origin opaque_origin = url::Origin();
1655 const blink::StorageKey opaque_first_party = blink::StorageKey(opaque_origin);
1656 const blink::StorageKey opaque_third_party =
1657 blink::StorageKey::CreateWithOptionalNonce(
1658 opaque_origin, net::SchemefulSite(GURL("https://notexample.com")),
1659 nullptr, blink::mojom::AncestorChainBit::kSameSite);
1660 EXPECT_NE(first_party, third_party);
1661 EXPECT_NE(opaque_first_party, opaque_third_party);
1662 FrameTree& frame_tree = static_cast<WebContentsImpl*>(shell()->web_contents())
1663 ->GetPrimaryFrameTree();
1664
1665 // Before registering any origins we expect partitioned access for both keys.
1666 EXPECT_EQ(third_party, frame_tree.GetSessionStorageKey(third_party));
1667 EXPECT_EQ(opaque_third_party,
1668 frame_tree.GetSessionStorageKey(opaque_third_party));
1669
1670 // We then register both origins.
1671 frame_tree.RegisterOriginForUnpartitionedSessionStorageAccess(origin);
1672 frame_tree.RegisterOriginForUnpartitionedSessionStorageAccess(opaque_origin);
1673
1674 // After registration the non-opaque key is unpartitioned but the opaque one
1675 // is still partitioned.
1676 EXPECT_EQ(first_party, frame_tree.GetSessionStorageKey(third_party));
1677 EXPECT_EQ(opaque_third_party,
1678 frame_tree.GetSessionStorageKey(opaque_third_party));
1679}
1680
1681IN_PROC_BROWSER_TEST_F(FrameTreeSessionStorageDeprecationTrialBrowserTest,
1682 GetSessionStorageKey) {
1683 const blink::StorageKey dt_third_party =
1684 blink::StorageKey::CreateWithOptionalNonce(
1685 url::Origin::Create(GURL("https://example.com")),
1686 net::SchemefulSite(GURL("https://notexample.com")), nullptr,
1687 blink::mojom::AncestorChainBit::kSameSite);
1688 const blink::StorageKey dt_first_party =
1689 blink::StorageKey::CreateFromStringForTesting("https://example.com");
1690 const blink::StorageKey random_third_party =
1691 blink::StorageKey::CreateWithOptionalNonce(
1692 url::Origin::Create(GURL("https://otherexample.com")),
1693 net::SchemefulSite(GURL("https://notexample.com")), nullptr,
1694 blink::mojom::AncestorChainBit::kSameSite);
1695 EXPECT_NE(dt_third_party, dt_first_party);
1696
1697 // Load a page without the origin trial token.
1698 EXPECT_TRUE(NavigateToURL(shell(), GURL("https://example.com/empty.html")));
1699 // We should be able to get a partitioned storage key for example.com.
1700 EXPECT_EQ(dt_third_party,
1701 static_cast<WebContentsImpl*>(shell()->web_contents())
1702 ->GetPrimaryFrameTree()
1703 .GetSessionStorageKey(dt_third_party));
1704
1705 // Load a page with the origin trial token.
1706 EXPECT_TRUE(NavigateToURL(shell(), GURL("https://example.com/session_storage/"
1707 "partition_deprecation_trial.html")));
1708 // We shouldn't be able to get a partitioned storage key for example.com.
1709 EXPECT_EQ(dt_first_party,
1710 static_cast<WebContentsImpl*>(shell()->web_contents())
1711 ->GetPrimaryFrameTree()
1712 .GetSessionStorageKey(dt_third_party));
1713 // Other origins can still get partitioned storage keys.
1714 EXPECT_EQ(random_third_party,
1715 static_cast<WebContentsImpl*>(shell()->web_contents())
1716 ->GetPrimaryFrameTree()
1717 .GetSessionStorageKey(random_third_party));
1718
1719 // Load a page without the token after having loaded a page with the token.
1720 EXPECT_TRUE(
1721 NavigateToURL(shell(), GURL("https://otherexample.com/empty.html")));
1722 // We shouldn't be able to get a partitioned storage key for example.com.
1723 EXPECT_EQ(dt_first_party,
1724 static_cast<WebContentsImpl*>(shell()->web_contents())
1725 ->GetPrimaryFrameTree()
1726 .GetSessionStorageKey(dt_third_party));
1727 // Other origins can still get partitioned storage keys.
1728 EXPECT_EQ(random_third_party,
1729 static_cast<WebContentsImpl*>(shell()->web_contents())
1730 ->GetPrimaryFrameTree()
1731 .GetSessionStorageKey(random_third_party));
1732}
[email protected]5f96f5a62014-01-10 00:05:111733} // namespace content