blob: 3feccf79374ccf7d516e20d99dfa436a54221917 [file] [log] [blame]
[email protected]5f96f5a62014-01-10 00:05:111// Copyright 2014 The Chromium Authors. All rights reserved.
2// 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"
avib7348942015-12-25 20:57:106#include "base/macros.h"
Aaron Colwelle953e562019-07-24 16:47:367#include "base/strings/stringprintf.h"
Lan Wei3c2cbad2019-03-29 21:53:538#include "base/test/scoped_feature_list.h"
avib7348942015-12-25 20:57:109#include "build/build_config.h"
[email protected]5f96f5a62014-01-10 00:05:1110#include "content/browser/frame_host/frame_tree.h"
11#include "content/browser/frame_host/frame_tree_node.h"
Lukasz Anforowicz9e0ce4e2017-09-28 19:09:1512#include "content/browser/frame_host/render_frame_host_impl.h"
[email protected]5f96f5a62014-01-10 00:05:1113#include "content/browser/renderer_host/render_view_host_impl.h"
14#include "content/browser/web_contents/web_contents_impl.h"
15#include "content/public/browser/notification_service.h"
16#include "content/public/browser/notification_types.h"
Annie Sullivan35977ad2019-04-30 21:04:2817#include "content/public/common/content_features.h"
nickdb193a12016-09-09 23:09:2318#include "content/public/common/content_switches.h"
Nasko Oskov039121012019-01-11 00:21:3219#include "content/public/common/origin_util.h"
[email protected]5f96f5a62014-01-10 00:05:1120#include "content/public/common/url_constants.h"
21#include "content/public/test/browser_test_utils.h"
[email protected]6e9def12014-03-27 20:23:2822#include "content/public/test/content_browser_test.h"
23#include "content/public/test/content_browser_test_utils.h"
John Abd-El-Malek3fea4c42019-01-10 01:15:4224#include "content/public/test/test_frame_navigation_observer.h"
[email protected]5f96f5a62014-01-10 00:05:1125#include "content/public/test/test_navigation_observer.h"
26#include "content/public/test/test_utils.h"
27#include "content/shell/browser/shell.h"
nickdb193a12016-09-09 23:09:2328#include "content/shell/common/shell_switches.h"
[email protected]82307f6b2014-08-07 03:30:1229#include "content/test/content_browser_test_utils_internal.h"
[email protected]5f96f5a62014-01-10 00:05:1130#include "net/dns/mock_host_resolver.h"
alexmos478dcbb2014-12-10 21:24:4631#include "net/test/embedded_test_server/embedded_test_server.h"
Blink Reformata30d4232018-04-07 15:31:0632#include "third_party/blink/public/common/frame/sandbox_flags.h"
nick1466c842015-11-25 20:08:0633#include "url/url_constants.h"
[email protected]5f96f5a62014-01-10 00:05:1134
35namespace content {
36
nickdb193a12016-09-09 23:09:2337namespace {
38
Nick Carterb7e71312018-08-03 23:36:1339EvalJsResult GetOriginFromRenderer(FrameTreeNode* node) {
Philip Jägenstedt67302a22018-09-14 09:58:0540 return EvalJs(node, "self.origin");
nickdb193a12016-09-09 23:09:2341}
42
43} // namespace
44
[email protected]5f96f5a62014-01-10 00:05:1145class FrameTreeBrowserTest : public ContentBrowserTest {
46 public:
47 FrameTreeBrowserTest() {}
48
alexmos478dcbb2014-12-10 21:24:4649 void SetUpOnMainThread() override {
50 host_resolver()->AddRule("*", "127.0.0.1");
alexmos478dcbb2014-12-10 21:24:4651 SetupCrossSiteRedirector(embedded_test_server());
martijn12d2dad2016-11-11 10:59:2752 ASSERT_TRUE(embedded_test_server()->Start());
alexmos478dcbb2014-12-10 21:24:4653 }
54
[email protected]5f96f5a62014-01-10 00:05:1155 private:
56 DISALLOW_COPY_AND_ASSIGN(FrameTreeBrowserTest);
57};
58
59// Ensures FrameTree correctly reflects page structure during navigations.
60IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape) {
alexmos478dcbb2014-12-10 21:24:4661 GURL base_url = embedded_test_server()->GetURL("A.com", "/site_isolation/");
[email protected]5f96f5a62014-01-10 00:05:1162
63 // Load doc without iframes. Verify FrameTree just has root.
64 // Frame tree:
65 // Site-A Root
Alex Moshchukaa95adf52019-08-13 00:02:0266 EXPECT_TRUE(NavigateToURL(shell(), base_url.Resolve("blank.html")));
Aran Gilman37d11632019-10-08 23:07:1567 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
68 ->GetFrameTree()
69 ->root();
[email protected]5f96f5a62014-01-10 00:05:1170 EXPECT_EQ(0U, root->child_count());
71
72 // Add 2 same-site frames. Verify 3 nodes in tree with proper names.
73 // Frame tree:
74 // Site-A Root -- Site-A frame1
75 // \-- Site-A frame2
76 WindowedNotificationObserver observer1(
77 content::NOTIFICATION_LOAD_STOP,
78 content::Source<NavigationController>(
79 &shell()->web_contents()->GetController()));
Alex Moshchukaa95adf52019-08-13 00:02:0280 EXPECT_TRUE(NavigateToURL(shell(), base_url.Resolve("frames-X-X.html")));
[email protected]5f96f5a62014-01-10 00:05:1181 observer1.Wait();
82 ASSERT_EQ(2U, root->child_count());
83 EXPECT_EQ(0U, root->child_at(0)->child_count());
84 EXPECT_EQ(0U, root->child_at(1)->child_count());
85}
86
87// TODO(ajwong): Talk with nasko and merge this functionality with
88// FrameTreeShape.
89IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape2) {
Alex Moshchukaa95adf52019-08-13 00:02:0290 EXPECT_TRUE(NavigateToURL(
91 shell(), embedded_test_server()->GetURL("/frame_tree/top.html")));
[email protected]5f96f5a62014-01-10 00:05:1192
93 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
[email protected]5f96f5a62014-01-10 00:05:1194 FrameTreeNode* root = wc->GetFrameTree()->root();
95
[email protected]58faf942014-02-20 21:03:5896 // Check that the root node is properly created.
[email protected]5f96f5a62014-01-10 00:05:1197 ASSERT_EQ(3UL, root->child_count());
98 EXPECT_EQ(std::string(), root->frame_name());
[email protected]5f96f5a62014-01-10 00:05:1199
100 ASSERT_EQ(2UL, root->child_at(0)->child_count());
101 EXPECT_STREQ("1-1-name", root->child_at(0)->frame_name().c_str());
102
103 // Verify the deepest node exists and has the right name.
104 ASSERT_EQ(2UL, root->child_at(2)->child_count());
105 EXPECT_EQ(1UL, root->child_at(2)->child_at(1)->child_count());
106 EXPECT_EQ(0UL, root->child_at(2)->child_at(1)->child_at(0)->child_count());
Aran Gilman37d11632019-10-08 23:07:15107 EXPECT_STREQ(
108 "3-1-name",
[email protected]5f96f5a62014-01-10 00:05:11109 root->child_at(2)->child_at(1)->child_at(0)->frame_name().c_str());
110
111 // Navigate to about:blank, which should leave only the root node of the frame
112 // tree in the browser process.
Alex Moshchukaa95adf52019-08-13 00:02:02113 EXPECT_TRUE(
114 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
[email protected]5f96f5a62014-01-10 00:05:11115
116 root = wc->GetFrameTree()->root();
117 EXPECT_EQ(0UL, root->child_count());
118 EXPECT_EQ(std::string(), root->frame_name());
[email protected]5f96f5a62014-01-10 00:05:11119}
120
121// Test that we can navigate away if the previous renderer doesn't clean up its
122// child frames.
123IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeAfterCrash) {
Alex Moshchukaa95adf52019-08-13 00:02:02124 EXPECT_TRUE(NavigateToURL(
125 shell(), embedded_test_server()->GetURL("/frame_tree/top.html")));
[email protected]5f96f5a62014-01-10 00:05:11126
creise42f2a52014-09-18 18:14:57127 // Ensure the view and frame are live.
128 RenderViewHost* rvh = shell()->web_contents()->GetRenderViewHost();
arthursonzognif4c4a4a2019-08-08 18:54:44129 RenderFrameHostImpl* rfh1 =
creise42f2a52014-09-18 18:14:57130 static_cast<RenderFrameHostImpl*>(rvh->GetMainFrame());
131 EXPECT_TRUE(rvh->IsRenderViewLive());
arthursonzognif4c4a4a2019-08-08 18:54:44132 EXPECT_TRUE(rfh1->IsRenderFrameLive());
creise42f2a52014-09-18 18:14:57133
[email protected]5f96f5a62014-01-10 00:05:11134 // Crash the renderer so that it doesn't send any FrameDetached messages.
135 RenderProcessHostWatcher crash_observer(
136 shell()->web_contents(),
137 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
Wez0abfbf512018-03-03 01:54:45138 ASSERT_TRUE(
139 shell()->web_contents()->GetMainFrame()->GetProcess()->Shutdown(0));
[email protected]5f96f5a62014-01-10 00:05:11140 crash_observer.Wait();
141
[email protected]58faf942014-02-20 21:03:58142 // The frame tree should be cleared.
[email protected]5f96f5a62014-01-10 00:05:11143 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
[email protected]5f96f5a62014-01-10 00:05:11144 FrameTreeNode* root = wc->GetFrameTree()->root();
145 EXPECT_EQ(0UL, root->child_count());
[email protected]5f96f5a62014-01-10 00:05:11146
creise42f2a52014-09-18 18:14:57147 // Ensure the view and frame aren't live anymore.
148 EXPECT_FALSE(rvh->IsRenderViewLive());
arthursonzognif4c4a4a2019-08-08 18:54:44149 EXPECT_FALSE(rfh1->IsRenderFrameLive());
creise42f2a52014-09-18 18:14:57150
[email protected]5f96f5a62014-01-10 00:05:11151 // Navigate to a new URL.
alexmos478dcbb2014-12-10 21:24:46152 GURL url(embedded_test_server()->GetURL("/title1.html"));
Alex Moshchukaa95adf52019-08-13 00:02:02153 EXPECT_TRUE(NavigateToURL(shell(), url));
[email protected]5f96f5a62014-01-10 00:05:11154 EXPECT_EQ(0UL, root->child_count());
[email protected]58faf942014-02-20 21:03:58155 EXPECT_EQ(url, root->current_url());
creise42f2a52014-09-18 18:14:57156
arthursonzognif4c4a4a2019-08-08 18:54:44157 RenderFrameHostImpl* rfh2 = root->current_frame_host();
creise42f2a52014-09-18 18:14:57158 // Ensure the view and frame are live again.
159 EXPECT_TRUE(rvh->IsRenderViewLive());
arthursonzognif4c4a4a2019-08-08 18:54:44160 EXPECT_TRUE(rfh2->IsRenderFrameLive());
[email protected]5f96f5a62014-01-10 00:05:11161}
162
163// Test that we can navigate away if the previous renderer doesn't clean up its
164// child frames.
Nasko Oskov31c45ff2019-10-16 01:15:19165IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, NavigateWithLeftoverFrames) {
alexmos478dcbb2014-12-10 21:24:46166 GURL base_url = embedded_test_server()->GetURL("A.com", "/site_isolation/");
[email protected]5f96f5a62014-01-10 00:05:11167
Alex Moshchukaa95adf52019-08-13 00:02:02168 EXPECT_TRUE(NavigateToURL(
169 shell(), embedded_test_server()->GetURL("/frame_tree/top.html")));
[email protected]5f96f5a62014-01-10 00:05:11170
171 // Hang the renderer so that it doesn't send any FrameDetached messages.
172 // (This navigation will never complete, so don't wait for it.)
173 shell()->LoadURL(GURL(kChromeUIHangURL));
174
175 // Check that the frame tree still has children.
176 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
177 FrameTreeNode* root = wc->GetFrameTree()->root();
178 ASSERT_EQ(3UL, root->child_count());
179
180 // Navigate to a new URL. We use LoadURL because NavigateToURL will try to
181 // wait for the previous navigation to stop.
182 TestNavigationObserver tab_observer(wc, 1);
183 shell()->LoadURL(base_url.Resolve("blank.html"));
184 tab_observer.Wait();
185
[email protected]58faf942014-02-20 21:03:58186 // The frame tree should now be cleared.
[email protected]5f96f5a62014-01-10 00:05:11187 EXPECT_EQ(0UL, root->child_count());
[email protected]5f96f5a62014-01-10 00:05:11188}
189
creise42f2a52014-09-18 18:14:57190// Ensure that IsRenderFrameLive is true for main frames and same-site iframes.
191IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, IsRenderFrameLive) {
alexmos478dcbb2014-12-10 21:24:46192 GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
Alex Moshchukaa95adf52019-08-13 00:02:02193 EXPECT_TRUE(NavigateToURL(shell(), main_url));
creise42f2a52014-09-18 18:14:57194
195 // It is safe to obtain the root frame tree node here, as it doesn't change.
196 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
Aran Gilman37d11632019-10-08 23:07:15197 ->GetFrameTree()
198 ->root();
creise42f2a52014-09-18 18:14:57199
200 // The root and subframe should each have a live RenderFrame.
201 EXPECT_TRUE(
202 root->current_frame_host()->render_view_host()->IsRenderViewLive());
203 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
204 EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
205
206 // Load a same-site page into iframe and it should still be live.
alexmos478dcbb2014-12-10 21:24:46207 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
creise42f2a52014-09-18 18:14:57208 NavigateFrameToURL(root->child_at(0), http_url);
209 EXPECT_TRUE(
210 root->current_frame_host()->render_view_host()->IsRenderViewLive());
211 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
212 EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
213}
214
alexmosbc7eafa2014-12-06 01:38:09215// Ensure that origins are correctly set on navigations.
216IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, OriginSetOnNavigation) {
nick1466c842015-11-25 20:08:06217 GURL about_blank(url::kAboutBlankURL);
218 GURL main_url(
219 embedded_test_server()->GetURL("a.com", "/frame_tree/top.html"));
alexmosbc7eafa2014-12-06 01:38:09220 EXPECT_TRUE(NavigateToURL(shell(), main_url));
nick1466c842015-11-25 20:08:06221 WebContents* contents = shell()->web_contents();
alexmosbc7eafa2014-12-06 01:38:09222
223 // It is safe to obtain the root frame tree node here, as it doesn't change.
nick1466c842015-11-25 20:08:06224 FrameTreeNode* root =
225 static_cast<WebContentsImpl*>(contents)->GetFrameTree()->root();
alexmosbc7eafa2014-12-06 01:38:09226
227 // Extra '/' is added because the replicated origin is serialized in RFC 6454
228 // format, which dictates no trailing '/', whereas GURL::GetOrigin does put a
229 // '/' at the end.
nick1466c842015-11-25 20:08:06230 EXPECT_EQ(main_url.GetOrigin().spec(),
231 root->current_origin().Serialize() + '/');
232 EXPECT_EQ(
233 main_url.GetOrigin().spec(),
234 root->current_frame_host()->GetLastCommittedOrigin().Serialize() + '/');
alexmosbc7eafa2014-12-06 01:38:09235
nick1466c842015-11-25 20:08:06236 // The iframe is inititially same-origin.
237 EXPECT_TRUE(
238 root->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
239 root->child_at(0)->current_frame_host()->GetLastCommittedOrigin()));
240 EXPECT_EQ(root->current_origin().Serialize(), GetOriginFromRenderer(root));
241 EXPECT_EQ(root->child_at(0)->current_origin().Serialize(),
242 GetOriginFromRenderer(root->child_at(0)));
243
244 // Navigate the iframe cross-origin.
245 GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
alexmosbc7eafa2014-12-06 01:38:09246 NavigateFrameToURL(root->child_at(0), frame_url);
nick1466c842015-11-25 20:08:06247 EXPECT_EQ(frame_url, root->child_at(0)->current_url());
248 EXPECT_EQ(frame_url.GetOrigin().spec(),
249 root->child_at(0)->current_origin().Serialize() + '/');
250 EXPECT_FALSE(
251 root->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
252 root->child_at(0)->current_frame_host()->GetLastCommittedOrigin()));
253 EXPECT_EQ(root->current_origin().Serialize(), GetOriginFromRenderer(root));
254 EXPECT_EQ(root->child_at(0)->current_origin().Serialize(),
255 GetOriginFromRenderer(root->child_at(0)));
alexmosbc7eafa2014-12-06 01:38:09256
nick1466c842015-11-25 20:08:06257 // Parent-initiated about:blank navigation should inherit the parent's a.com
258 // origin.
259 NavigateIframeToURL(contents, "1-1-id", about_blank);
260 EXPECT_EQ(about_blank, root->child_at(0)->current_url());
261 EXPECT_EQ(main_url.GetOrigin().spec(),
262 root->child_at(0)->current_origin().Serialize() + '/');
263 EXPECT_EQ(root->current_frame_host()->GetLastCommittedOrigin().Serialize(),
264 root->child_at(0)
265 ->current_frame_host()
266 ->GetLastCommittedOrigin()
267 .Serialize());
268 EXPECT_TRUE(
269 root->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
270 root->child_at(0)->current_frame_host()->GetLastCommittedOrigin()));
271 EXPECT_EQ(root->current_origin().Serialize(), GetOriginFromRenderer(root));
272 EXPECT_EQ(root->child_at(0)->current_origin().Serialize(),
273 GetOriginFromRenderer(root->child_at(0)));
alexmosbc7eafa2014-12-06 01:38:09274
275 GURL data_url("data:text/html,foo");
276 EXPECT_TRUE(NavigateToURL(shell(), data_url));
277
278 // Navigating to a data URL should set a unique origin. This is represented
279 // as "null" per RFC 6454.
nick1466c842015-11-25 20:08:06280 EXPECT_EQ("null", root->current_origin().Serialize());
Chris Palmerab5e5b52018-09-28 19:19:30281 EXPECT_TRUE(contents->GetMainFrame()->GetLastCommittedOrigin().opaque());
nick1466c842015-11-25 20:08:06282 EXPECT_EQ("null", GetOriginFromRenderer(root));
alexmosbc7eafa2014-12-06 01:38:09283
284 // Re-navigating to a normal URL should update the origin.
285 EXPECT_TRUE(NavigateToURL(shell(), main_url));
nick1466c842015-11-25 20:08:06286 EXPECT_EQ(main_url.GetOrigin().spec(),
287 root->current_origin().Serialize() + '/');
288 EXPECT_EQ(
289 main_url.GetOrigin().spec(),
290 contents->GetMainFrame()->GetLastCommittedOrigin().Serialize() + '/');
Chris Palmerab5e5b52018-09-28 19:19:30291 EXPECT_FALSE(contents->GetMainFrame()->GetLastCommittedOrigin().opaque());
nick1466c842015-11-25 20:08:06292 EXPECT_EQ(root->current_origin().Serialize(), GetOriginFromRenderer(root));
alexmosbc7eafa2014-12-06 01:38:09293}
294
nick9f34e2892016-01-12 21:01:07295// Tests a cross-origin navigation to a blob URL. The main frame initiates this
296// navigation on its grandchild. It should wind up in the main frame's process.
297IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, NavigateGrandchildToBlob) {
298 WebContents* contents = shell()->web_contents();
299 FrameTreeNode* root =
300 static_cast<WebContentsImpl*>(contents)->GetFrameTree()->root();
301
302 // First, snapshot the FrameTree for a normal A(B(A)) case where all frames
303 // are served over http. The blob test should result in the same structure.
304 EXPECT_TRUE(NavigateToURL(
305 shell(), embedded_test_server()->GetURL(
306 "a.com", "/cross_site_iframe_factory.html?a(b(a))")));
307 std::string reference_tree = FrameTreeVisualizer().DepictFrameTree(root);
308
309 GURL main_url(embedded_test_server()->GetURL(
310 "a.com", "/cross_site_iframe_factory.html?a(b(c))"));
311 EXPECT_TRUE(NavigateToURL(shell(), main_url));
312
313 // The root node will initiate the navigation; its grandchild node will be the
314 // target of the navigation.
315 FrameTreeNode* target = root->child_at(0)->child_at(0);
316
creisb2d5f1f32016-11-07 23:25:05317 RenderFrameDeletedObserver deleted_observer(target->current_frame_host());
Nick Carterb7e71312018-08-03 23:36:13318 std::string html =
319 "<html><body><div>This is blob content.</div>"
320 "<script>"
Philip Jägenstedt67302a22018-09-14 09:58:05321 "window.parent.parent.postMessage('HI', self.origin);"
Nick Carterb7e71312018-08-03 23:36:13322 "</script></body></html>";
323 std::string script = JsReplace(
324 "new Promise((resolve) => {"
325 " window.addEventListener('message', resolve, false);"
326 " var blob = new Blob([$1], {type: 'text/html'});"
327 " var blob_url = URL.createObjectURL(blob);"
328 " frames[0][0].location.href = blob_url;"
329 "}).then((event) => {"
nick9f34e2892016-01-12 21:01:07330 " document.body.appendChild(document.createTextNode(event.data));"
Nick Carterb7e71312018-08-03 23:36:13331 " return event.source.location.href;"
332 "});",
333 html);
334 std::string blob_url_string = EvalJs(root, script).ExtractString();
creisb2d5f1f32016-11-07 23:25:05335 // Wait for the RenderFrame to go away, if this will be cross-process.
336 if (AreAllSitesIsolatedForTesting())
337 deleted_observer.WaitUntilDeleted();
nick9f34e2892016-01-12 21:01:07338 EXPECT_EQ(GURL(blob_url_string), target->current_url());
339 EXPECT_EQ(url::kBlobScheme, target->current_url().scheme());
Chris Palmerab5e5b52018-09-28 19:19:30340 EXPECT_FALSE(target->current_origin().opaque());
nick9f34e2892016-01-12 21:01:07341 EXPECT_EQ("a.com", target->current_origin().host());
342 EXPECT_EQ(url::kHttpScheme, target->current_origin().scheme());
Nick Carterb7e71312018-08-03 23:36:13343 EXPECT_EQ("This is blob content.",
344 EvalJs(target, "document.body.children[0].innerHTML"));
nick9f34e2892016-01-12 21:01:07345 EXPECT_EQ(reference_tree, FrameTreeVisualizer().DepictFrameTree(root));
346}
347
348IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, NavigateChildToAboutBlank) {
349 GURL main_url(embedded_test_server()->GetURL(
350 "a.com", "/cross_site_iframe_factory.html?a(b(c))"));
351 EXPECT_TRUE(NavigateToURL(shell(), main_url));
352 WebContentsImpl* contents =
353 static_cast<WebContentsImpl*>(shell()->web_contents());
354
355 // The leaf node (c.com) will be navigated. Its parent node (b.com) will
356 // initiate the navigation.
357 FrameTreeNode* target =
358 contents->GetFrameTree()->root()->child_at(0)->child_at(0);
359 FrameTreeNode* initiator = target->parent();
360
361 // Give the target a name.
Nick Carterb7e71312018-08-03 23:36:13362 EXPECT_TRUE(ExecJs(target, "window.name = 'target';"));
nick9f34e2892016-01-12 21:01:07363
364 // Use window.open(about:blank), then poll the document for access.
Nick Carterb7e71312018-08-03 23:36:13365 EvalJsResult about_blank_origin = EvalJs(
nickadef4a52016-06-09 18:45:54366 initiator,
Nick Carterb7e71312018-08-03 23:36:13367 "new Promise(resolve => {"
368 " var didNavigate = false;"
369 " var intervalID = setInterval(function() {"
370 " if (!didNavigate) {"
371 " didNavigate = true;"
372 " window.open('about:blank', 'target');"
373 " }"
374 " // Poll the document until it doesn't throw a SecurityError.\n"
375 " try {"
376 " frames[0].document.write('Hi from ' + document.domain);"
377 " } catch (e) { return; }"
378 " clearInterval(intervalID);"
Philip Jägenstedt67302a22018-09-14 09:58:05379 " resolve(frames[0].self.origin);"
Nick Carterb7e71312018-08-03 23:36:13380 " }, 16);"
381 "});");
382 EXPECT_EQ(target->current_origin(), about_blank_origin);
nick9f34e2892016-01-12 21:01:07383 EXPECT_EQ(GURL(url::kAboutBlankURL), target->current_url());
384 EXPECT_EQ(url::kAboutScheme, target->current_url().scheme());
Chris Palmerab5e5b52018-09-28 19:19:30385 EXPECT_FALSE(target->current_origin().opaque());
nick9f34e2892016-01-12 21:01:07386 EXPECT_EQ("b.com", target->current_origin().host());
387 EXPECT_EQ(url::kHttpScheme, target->current_origin().scheme());
nick9f34e2892016-01-12 21:01:07388
Nick Carterb7e71312018-08-03 23:36:13389 EXPECT_EQ("Hi from b.com", EvalJs(target, "document.body.innerHTML"));
nick9f34e2892016-01-12 21:01:07390}
391
392// Nested iframes, three origins: A(B(C)). Frame A navigates C to about:blank
393// (via window.open). This should wind up in A's origin per the spec. Test fails
394// because of http://crbug.com/564292
395IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest,
396 DISABLED_NavigateGrandchildToAboutBlank) {
397 GURL main_url(embedded_test_server()->GetURL(
398 "a.com", "/cross_site_iframe_factory.html?a(b(c))"));
399 EXPECT_TRUE(NavigateToURL(shell(), main_url));
400 WebContentsImpl* contents =
401 static_cast<WebContentsImpl*>(shell()->web_contents());
402
403 // The leaf node (c.com) will be navigated. Its grandparent node (a.com) will
404 // initiate the navigation.
405 FrameTreeNode* target =
406 contents->GetFrameTree()->root()->child_at(0)->child_at(0);
407 FrameTreeNode* initiator = target->parent()->parent();
408
409 // Give the target a name.
Nick Carterb7e71312018-08-03 23:36:13410 EXPECT_TRUE(ExecJs(target, "window.name = 'target';"));
nick9f34e2892016-01-12 21:01:07411
412 // Use window.open(about:blank), then poll the document for access.
Nick Carterb7e71312018-08-03 23:36:13413 EvalJsResult about_blank_origin =
414 EvalJs(initiator,
415 "new Promise((resolve) => {"
416 " var didNavigate = false;"
417 " var intervalID = setInterval(() => {"
418 " if (!didNavigate) {"
419 " didNavigate = true;"
420 " window.open('about:blank', 'target');"
421 " }"
422 " // May raise a SecurityError, that's expected.\n"
423 " try {"
424 " frames[0][0].document.write('Hi from ' + document.domain);"
425 " } catch (e) { return; }"
426 " clearInterval(intervalID);"
Philip Jägenstedt67302a22018-09-14 09:58:05427 " resolve(frames[0][0].self.origin);"
Nick Carterb7e71312018-08-03 23:36:13428 " }, 16);"
429 "});");
430 EXPECT_EQ(target->current_origin(), about_blank_origin);
nick9f34e2892016-01-12 21:01:07431 EXPECT_EQ(GURL(url::kAboutBlankURL), target->current_url());
432 EXPECT_EQ(url::kAboutScheme, target->current_url().scheme());
Chris Palmerab5e5b52018-09-28 19:19:30433 EXPECT_FALSE(target->current_origin().opaque());
nick9f34e2892016-01-12 21:01:07434 EXPECT_EQ("a.com", target->current_origin().host());
435 EXPECT_EQ(url::kHttpScheme, target->current_origin().scheme());
nick9f34e2892016-01-12 21:01:07436
Nick Carterb7e71312018-08-03 23:36:13437 EXPECT_EQ("Hi from a.com", EvalJs(target, "document.body.innerHTML"));
nick9f34e2892016-01-12 21:01:07438}
439
Nasko Oskov039121012019-01-11 00:21:32440// Tests a cross-origin navigation to a data: URL. The main frame initiates this
441// navigation on its grandchild. It should wind up in the main frame's process
442// and have precursor origin of the main frame origin.
443IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, NavigateGrandchildToDataUrl) {
444 GURL main_url(embedded_test_server()->GetURL(
445 "a.com", "/cross_site_iframe_factory.html?a(b(c))"));
446 EXPECT_TRUE(NavigateToURL(shell(), main_url));
447 WebContentsImpl* contents =
448 static_cast<WebContentsImpl*>(shell()->web_contents());
449
450 // The leaf node (c.com) will be navigated. Its grandparent node (a.com) will
451 // initiate the navigation.
452 FrameTreeNode* target =
453 contents->GetFrameTree()->root()->child_at(0)->child_at(0);
454 FrameTreeNode* initiator = target->parent()->parent();
455
456 // Give the target a name.
457 EXPECT_TRUE(ExecJs(target, "window.name = 'target';"));
458
459 // Navigate the target frame through the initiator frame.
460 {
461 TestFrameNavigationObserver observer(target);
462 EXPECT_TRUE(
463 ExecJs(initiator, "window.open('data:text/html,content', 'target');"));
464 observer.Wait();
465 }
466
467 url::Origin original_target_origin =
468 target->current_frame_host()->GetLastCommittedOrigin();
469 EXPECT_TRUE(original_target_origin.opaque());
470 EXPECT_EQ(original_target_origin.GetTupleOrPrecursorTupleIfOpaque(),
471 url::SchemeHostPort(main_url));
472
473 // Navigate the grandchild frame again cross-process to foo.com, then
474 // go back in session history. The origin for the data: URL must be preserved.
475 {
476 TestFrameNavigationObserver observer(target);
477 EXPECT_TRUE(ExecJs(target, JsReplace("window.location = $1",
478 embedded_test_server()->GetURL(
479 "foo.com", "/title2.html"))));
480 observer.Wait();
481 }
482 EXPECT_NE(original_target_origin,
483 target->current_frame_host()->GetLastCommittedOrigin());
484 {
485 TestFrameNavigationObserver observer(target);
486 contents->GetController().GoBack();
487 observer.Wait();
488 }
489
490 url::Origin target_origin =
491 target->current_frame_host()->GetLastCommittedOrigin();
492 EXPECT_TRUE(target_origin.opaque());
493 EXPECT_EQ(target_origin.GetTupleOrPrecursorTupleIfOpaque(),
494 url::SchemeHostPort(main_url));
495 EXPECT_EQ(target_origin, original_target_origin);
496}
497
naskofaa01fb2016-04-30 01:04:17498// Ensures that iframe with srcdoc is always put in the same origin as its
499// parent frame.
500IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, ChildFrameWithSrcdoc) {
501 GURL main_url(embedded_test_server()->GetURL(
502 "a.com", "/cross_site_iframe_factory.html?a(b)"));
503 EXPECT_TRUE(NavigateToURL(shell(), main_url));
504 WebContentsImpl* contents =
505 static_cast<WebContentsImpl*>(shell()->web_contents());
506 FrameTreeNode* root = contents->GetFrameTree()->root();
507 EXPECT_EQ(1U, root->child_count());
508
509 FrameTreeNode* child = root->child_at(0);
Philip Jägenstedt67302a22018-09-14 09:58:05510 std::string frame_origin = EvalJs(child, "self.origin;").ExtractString();
naskofaa01fb2016-04-30 01:04:17511 EXPECT_TRUE(
512 child->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
Daniel Cheng88186bd52017-10-20 08:14:46513 url::Origin::Create(GURL(frame_origin))));
naskofaa01fb2016-04-30 01:04:17514 EXPECT_FALSE(
515 root->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
Daniel Cheng88186bd52017-10-20 08:14:46516 url::Origin::Create(GURL(frame_origin))));
naskofaa01fb2016-04-30 01:04:17517
518 // Create a new iframe with srcdoc and add it to the main frame. It should
519 // be created in the same SiteInstance as the parent.
520 {
Aran Gilman37d11632019-10-08 23:07:15521 std::string script(
522 "var f = document.createElement('iframe');"
523 "f.srcdoc = 'some content';"
524 "document.body.appendChild(f)");
naskofaa01fb2016-04-30 01:04:17525 TestNavigationObserver observer(shell()->web_contents());
Nick Carterb7e71312018-08-03 23:36:13526 EXPECT_TRUE(ExecJs(root, script));
naskofaa01fb2016-04-30 01:04:17527 EXPECT_EQ(2U, root->child_count());
528 observer.Wait();
529
Lukasz Anforowicz42d3d07f2019-06-19 01:06:42530 EXPECT_TRUE(root->child_at(1)->current_url().IsAboutSrcdoc());
Philip Jägenstedt67302a22018-09-14 09:58:05531 EvalJsResult frame_origin = EvalJs(root->child_at(1), "self.origin");
naskofaa01fb2016-04-30 01:04:17532 EXPECT_EQ(root->current_frame_host()->GetLastCommittedURL().GetOrigin(),
Nick Carterb7e71312018-08-03 23:36:13533 GURL(frame_origin.ExtractString()));
naskofaa01fb2016-04-30 01:04:17534 EXPECT_NE(child->current_frame_host()->GetLastCommittedURL().GetOrigin(),
Nick Carterb7e71312018-08-03 23:36:13535 GURL(frame_origin.ExtractString()));
naskofaa01fb2016-04-30 01:04:17536 }
537
538 // Set srcdoc on the existing cross-site frame. It should navigate the frame
539 // back to the origin of the parent.
540 {
Aran Gilman37d11632019-10-08 23:07:15541 std::string script(
542 "var f = document.getElementById('child-0');"
543 "f.srcdoc = 'some content';");
naskofaa01fb2016-04-30 01:04:17544 TestNavigationObserver observer(shell()->web_contents());
Nick Carterb7e71312018-08-03 23:36:13545 EXPECT_TRUE(ExecJs(root, script));
naskofaa01fb2016-04-30 01:04:17546 observer.Wait();
547
Lukasz Anforowicz42d3d07f2019-06-19 01:06:42548 EXPECT_TRUE(child->current_url().IsAboutSrcdoc());
Nick Carterb7e71312018-08-03 23:36:13549 EXPECT_EQ(
550 url::Origin::Create(root->current_frame_host()->GetLastCommittedURL())
551 .Serialize(),
Philip Jägenstedt67302a22018-09-14 09:58:05552 EvalJs(child, "self.origin"));
naskofaa01fb2016-04-30 01:04:17553 }
554}
555
Ian Clelland5cbaaf82017-11-27 22:00:03556// Ensure that sandbox flags are correctly set in the main frame when set by
557// Content-Security-Policy header.
558IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, SandboxFlagsSetForMainFrame) {
559 GURL main_url(embedded_test_server()->GetURL("/csp_sandboxed_frame.html"));
560 EXPECT_TRUE(NavigateToURL(shell(), main_url));
561
562 // It is safe to obtain the root frame tree node here, as it doesn't change.
563 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
564 ->GetFrameTree()
565 ->root();
566
567 // Verify that sandbox flags are set properly for the root FrameTreeNode and
568 // RenderFrameHost. Root frame is sandboxed with "allow-scripts".
569 EXPECT_EQ(blink::WebSandboxFlags::kNone,
570 root->effective_frame_policy().sandbox_flags);
571 EXPECT_EQ(blink::WebSandboxFlags::kAll & ~blink::WebSandboxFlags::kScripts &
572 ~blink::WebSandboxFlags::kAutomaticFeatures,
573 root->active_sandbox_flags());
574 EXPECT_EQ(root->active_sandbox_flags(),
575 root->current_frame_host()->active_sandbox_flags());
576
577 // Verify that child frames inherit sandbox flags from the root. First frame
578 // has no explicitly set flags of its own, and should inherit those from the
579 // root. Second frame is completely sandboxed.
580 EXPECT_EQ(blink::WebSandboxFlags::kAll & ~blink::WebSandboxFlags::kScripts &
581 ~blink::WebSandboxFlags::kAutomaticFeatures,
582 root->child_at(0)->effective_frame_policy().sandbox_flags);
583 EXPECT_EQ(blink::WebSandboxFlags::kAll & ~blink::WebSandboxFlags::kScripts &
584 ~blink::WebSandboxFlags::kAutomaticFeatures,
585 root->child_at(0)->active_sandbox_flags());
586 EXPECT_EQ(root->child_at(0)->active_sandbox_flags(),
587 root->child_at(0)->current_frame_host()->active_sandbox_flags());
588 EXPECT_EQ(blink::WebSandboxFlags::kAll,
589 root->child_at(1)->effective_frame_policy().sandbox_flags);
590 EXPECT_EQ(blink::WebSandboxFlags::kAll,
591 root->child_at(1)->active_sandbox_flags());
592 EXPECT_EQ(root->child_at(1)->active_sandbox_flags(),
593 root->child_at(1)->current_frame_host()->active_sandbox_flags());
594
595 // Navigating the main frame to a different URL should clear sandbox flags.
596 GURL unsandboxed_url(embedded_test_server()->GetURL("/title1.html"));
597 NavigateFrameToURL(root, unsandboxed_url);
598
599 // Verify that sandbox flags are cleared properly for the root FrameTreeNode
600 // and RenderFrameHost.
601 EXPECT_EQ(blink::WebSandboxFlags::kNone,
602 root->effective_frame_policy().sandbox_flags);
603 EXPECT_EQ(blink::WebSandboxFlags::kNone, root->active_sandbox_flags());
604 EXPECT_EQ(blink::WebSandboxFlags::kNone,
605 root->current_frame_host()->active_sandbox_flags());
606}
607
alexmosf832a2f2015-01-27 22:44:03608// Ensure that sandbox flags are correctly set when child frames are created.
609IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, SandboxFlagsSetForChildFrames) {
610 GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
611 EXPECT_TRUE(NavigateToURL(shell(), main_url));
612
613 // It is safe to obtain the root frame tree node here, as it doesn't change.
614 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
Aran Gilman37d11632019-10-08 23:07:15615 ->GetFrameTree()
616 ->root();
alexmosf832a2f2015-01-27 22:44:03617
618 // Verify that sandbox flags are set properly for all FrameTreeNodes.
619 // First frame is completely sandboxed; second frame uses "allow-scripts",
620 // which resets both SandboxFlags::Scripts and
621 // SandboxFlags::AutomaticFeatures bits per blink::parseSandboxPolicy(), and
622 // third frame has "allow-scripts allow-same-origin".
Ian Clellandcdc4f312017-10-13 22:24:12623 EXPECT_EQ(blink::WebSandboxFlags::kNone,
624 root->effective_frame_policy().sandbox_flags);
Blink Reformat1c4d759e2017-04-09 16:34:54625 EXPECT_EQ(blink::WebSandboxFlags::kAll,
Ian Clellandcdc4f312017-10-13 22:24:12626 root->child_at(0)->effective_frame_policy().sandbox_flags);
Blink Reformat1c4d759e2017-04-09 16:34:54627 EXPECT_EQ(blink::WebSandboxFlags::kAll & ~blink::WebSandboxFlags::kScripts &
628 ~blink::WebSandboxFlags::kAutomaticFeatures,
Ian Clellandcdc4f312017-10-13 22:24:12629 root->child_at(1)->effective_frame_policy().sandbox_flags);
Blink Reformat1c4d759e2017-04-09 16:34:54630 EXPECT_EQ(blink::WebSandboxFlags::kAll & ~blink::WebSandboxFlags::kScripts &
631 ~blink::WebSandboxFlags::kAutomaticFeatures &
632 ~blink::WebSandboxFlags::kOrigin,
Ian Clellandcdc4f312017-10-13 22:24:12633 root->child_at(2)->effective_frame_policy().sandbox_flags);
alexmosf832a2f2015-01-27 22:44:03634
635 // Sandboxed frames should set a unique origin unless they have the
636 // "allow-same-origin" directive.
alexmos6e940102016-01-19 22:47:25637 EXPECT_EQ("null", root->child_at(0)->current_origin().Serialize());
638 EXPECT_EQ("null", root->child_at(1)->current_origin().Serialize());
639 EXPECT_EQ(main_url.GetOrigin().spec(),
640 root->child_at(2)->current_origin().Serialize() + "/");
alexmosf832a2f2015-01-27 22:44:03641
642 // Navigating to a different URL should not clear sandbox flags.
643 GURL frame_url(embedded_test_server()->GetURL("/title1.html"));
644 NavigateFrameToURL(root->child_at(0), frame_url);
Blink Reformat1c4d759e2017-04-09 16:34:54645 EXPECT_EQ(blink::WebSandboxFlags::kAll,
Ian Clellandcdc4f312017-10-13 22:24:12646 root->child_at(0)->effective_frame_policy().sandbox_flags);
alexmosf832a2f2015-01-27 22:44:03647}
648
Ian Clelland5cbaaf82017-11-27 22:00:03649// Ensure that sandbox flags are correctly set in the child frames when set by
650// Content-Security-Policy header, and in combination with the sandbox iframe
651// attribute.
652IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest,
653 SandboxFlagsSetByCSPForChildFrames) {
654 GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames_csp.html"));
655 EXPECT_TRUE(NavigateToURL(shell(), main_url));
656
657 // It is safe to obtain the root frame tree node here, as it doesn't change.
658 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
659 ->GetFrameTree()
660 ->root();
661
662 // Verify that sandbox flags are set properly for all FrameTreeNodes.
663 // First frame has no iframe sandbox flags, but the framed document is served
664 // with a CSP header which sets "allow-scripts", "allow-popups" and
665 // "allow-pointer-lock".
666 // Second frame is sandboxed with "allow-scripts", "allow-pointer-lock" and
667 // "allow-orientation-lock", and the framed document is also served with a CSP
668 // header which uses "allow-popups" and "allow-pointer-lock". The resulting
669 // sandbox for the frame should only have "allow-pointer-lock".
670 EXPECT_EQ(blink::WebSandboxFlags::kNone,
671 root->effective_frame_policy().sandbox_flags);
672 EXPECT_EQ(blink::WebSandboxFlags::kNone, root->active_sandbox_flags());
673 EXPECT_EQ(root->active_sandbox_flags(),
674 root->current_frame_host()->active_sandbox_flags());
675 EXPECT_EQ(blink::WebSandboxFlags::kNone,
676 root->child_at(0)->effective_frame_policy().sandbox_flags);
677 EXPECT_EQ(blink::WebSandboxFlags::kAll & ~blink::WebSandboxFlags::kScripts &
678 ~blink::WebSandboxFlags::kAutomaticFeatures &
679 ~blink::WebSandboxFlags::kPopups &
680 ~blink::WebSandboxFlags::kPointerLock,
681 root->child_at(0)->active_sandbox_flags());
682 EXPECT_EQ(root->child_at(0)->active_sandbox_flags(),
683 root->child_at(0)->current_frame_host()->active_sandbox_flags());
684 EXPECT_EQ(blink::WebSandboxFlags::kAll & ~blink::WebSandboxFlags::kScripts &
685 ~blink::WebSandboxFlags::kAutomaticFeatures &
686 ~blink::WebSandboxFlags::kPointerLock &
687 ~blink::WebSandboxFlags::kOrientationLock,
688 root->child_at(1)->effective_frame_policy().sandbox_flags);
689 EXPECT_EQ(blink::WebSandboxFlags::kAll & ~blink::WebSandboxFlags::kScripts &
690 ~blink::WebSandboxFlags::kAutomaticFeatures &
691 ~blink::WebSandboxFlags::kPointerLock,
692 root->child_at(1)->active_sandbox_flags());
693 EXPECT_EQ(root->child_at(1)->active_sandbox_flags(),
694 root->child_at(1)->current_frame_host()->active_sandbox_flags());
695
696 // Navigating to a different URL *should* clear CSP-set sandbox flags, but
697 // should retain those flags set by the frame owner.
698 GURL frame_url(embedded_test_server()->GetURL("/title1.html"));
699
700 NavigateFrameToURL(root->child_at(0), frame_url);
701 EXPECT_EQ(blink::WebSandboxFlags::kNone,
702 root->child_at(0)->effective_frame_policy().sandbox_flags);
703 EXPECT_EQ(blink::WebSandboxFlags::kNone,
704 root->child_at(0)->active_sandbox_flags());
705 EXPECT_EQ(root->child_at(0)->active_sandbox_flags(),
706 root->child_at(0)->current_frame_host()->active_sandbox_flags());
707
708 NavigateFrameToURL(root->child_at(1), frame_url);
709 EXPECT_EQ(blink::WebSandboxFlags::kAll & ~blink::WebSandboxFlags::kScripts &
710 ~blink::WebSandboxFlags::kAutomaticFeatures &
711 ~blink::WebSandboxFlags::kPointerLock &
712 ~blink::WebSandboxFlags::kOrientationLock,
713 root->child_at(1)->effective_frame_policy().sandbox_flags);
714 EXPECT_EQ(blink::WebSandboxFlags::kAll & ~blink::WebSandboxFlags::kScripts &
715 ~blink::WebSandboxFlags::kAutomaticFeatures &
716 ~blink::WebSandboxFlags::kPointerLock &
717 ~blink::WebSandboxFlags::kOrientationLock,
718 root->child_at(1)->active_sandbox_flags());
719 EXPECT_EQ(root->child_at(1)->active_sandbox_flags(),
720 root->child_at(1)->current_frame_host()->active_sandbox_flags());
721}
722
alexmose201c7cd2015-06-10 17:14:21723// Ensure that a popup opened from a subframe sets its opener to the subframe's
724// FrameTreeNode, and that the opener is cleared if the subframe is destroyed.
725IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, SubframeOpenerSetForNewWindow) {
726 GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
727 EXPECT_TRUE(NavigateToURL(shell(), main_url));
728
729 // It is safe to obtain the root frame tree node here, as it doesn't change.
730 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
731 ->GetFrameTree()
732 ->root();
733
734 // Open a new window from a subframe.
735 ShellAddedObserver new_shell_observer;
736 GURL popup_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
Nick Carterb7e71312018-08-03 23:36:13737 EXPECT_TRUE(
738 ExecJs(root->child_at(0), JsReplace("window.open($1);", popup_url)));
alexmose201c7cd2015-06-10 17:14:21739 Shell* new_shell = new_shell_observer.GetShell();
740 WebContents* new_contents = new_shell->web_contents();
741 WaitForLoadStop(new_contents);
742
743 // Check that the new window's opener points to the correct subframe on
744 // original window.
745 FrameTreeNode* popup_root =
746 static_cast<WebContentsImpl*>(new_contents)->GetFrameTree()->root();
747 EXPECT_EQ(root->child_at(0), popup_root->opener());
748
749 // Close the original window. This should clear the new window's opener.
750 shell()->Close();
751 EXPECT_EQ(nullptr, popup_root->opener());
752}
753
Shivani Sharmac4f561582018-11-15 15:58:39754// Tests that the user activation bits get cleared when a same-site document is
755// installed in the frame.
756IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest,
757 ClearUserActivationForNewDocument) {
758 GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
759 EXPECT_TRUE(NavigateToURL(shell(), main_url));
760
761 // It is safe to obtain the root frame tree node here, as it doesn't change.
762 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
763 ->GetFrameTree()
764 ->root();
765
Mustaq Ahmed4baa9a6e82019-12-20 23:43:46766 EXPECT_FALSE(root->HasStickyUserActivation());
Shivani Sharmac4f561582018-11-15 15:58:39767 EXPECT_FALSE(root->HasTransientUserActivation());
768
769 // Set the user activation bits.
770 root->UpdateUserActivationState(
771 blink::UserActivationUpdateType::kNotifyActivation);
Mustaq Ahmed4baa9a6e82019-12-20 23:43:46772 EXPECT_TRUE(root->HasStickyUserActivation());
Shivani Sharmac4f561582018-11-15 15:58:39773 EXPECT_TRUE(root->HasTransientUserActivation());
774
775 // Install a new same-site document to check the clearing of user activation
776 // bits.
777 GURL url(embedded_test_server()->GetURL("/title1.html"));
778 EXPECT_TRUE(NavigateToURL(shell(), url));
779
Mustaq Ahmed4baa9a6e82019-12-20 23:43:46780 EXPECT_FALSE(root->HasStickyUserActivation());
Shivani Sharmac4f561582018-11-15 15:58:39781 EXPECT_FALSE(root->HasTransientUserActivation());
782}
783
[email protected]82307f6b2014-08-07 03:30:12784class CrossProcessFrameTreeBrowserTest : public ContentBrowserTest {
785 public:
786 CrossProcessFrameTreeBrowserTest() {}
787
dchengc2282aa2014-10-21 12:07:58788 void SetUpCommandLine(base::CommandLine* command_line) override {
nickd30fd962015-07-27 21:51:08789 IsolateAllSitesForTesting(command_line);
[email protected]82307f6b2014-08-07 03:30:12790 }
791
alexmos478dcbb2014-12-10 21:24:46792 void SetUpOnMainThread() override {
793 host_resolver()->AddRule("*", "127.0.0.1");
alexmos478dcbb2014-12-10 21:24:46794 SetupCrossSiteRedirector(embedded_test_server());
martijn12d2dad2016-11-11 10:59:27795 ASSERT_TRUE(embedded_test_server()->Start());
alexmos478dcbb2014-12-10 21:24:46796 }
797
[email protected]82307f6b2014-08-07 03:30:12798 private:
799 DISALLOW_COPY_AND_ASSIGN(CrossProcessFrameTreeBrowserTest);
800};
801
802// Ensure that we can complete a cross-process subframe navigation.
[email protected]82307f6b2014-08-07 03:30:12803IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
nasko83fe5dc2015-07-01 16:34:19804 CreateCrossProcessSubframeProxies) {
alexmos478dcbb2014-12-10 21:24:46805 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
Alex Moshchukaa95adf52019-08-13 00:02:02806 EXPECT_TRUE(NavigateToURL(shell(), main_url));
[email protected]82307f6b2014-08-07 03:30:12807
808 // It is safe to obtain the root frame tree node here, as it doesn't change.
809 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
Aran Gilman37d11632019-10-08 23:07:15810 ->GetFrameTree()
811 ->root();
[email protected]82307f6b2014-08-07 03:30:12812
[email protected]14522ce42014-08-08 18:56:16813 // There should not be a proxy for the root's own SiteInstance.
814 SiteInstance* root_instance = root->current_frame_host()->GetSiteInstance();
815 EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(root_instance));
816
[email protected]82307f6b2014-08-07 03:30:12817 // Load same-site page into iframe.
alexmos478dcbb2014-12-10 21:24:46818 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
[email protected]82307f6b2014-08-07 03:30:12819 NavigateFrameToURL(root->child_at(0), http_url);
820
[email protected]82307f6b2014-08-07 03:30:12821 // Load cross-site page into iframe.
alexmos478dcbb2014-12-10 21:24:46822 GURL cross_site_url(
823 embedded_test_server()->GetURL("foo.com", "/title2.html"));
[email protected]82307f6b2014-08-07 03:30:12824 NavigateFrameToURL(root->child_at(0), cross_site_url);
825
826 // Ensure that we have created a new process for the subframe.
naskoe6edde32014-10-17 15:36:48827 ASSERT_EQ(2U, root->child_count());
[email protected]82307f6b2014-08-07 03:30:12828 FrameTreeNode* child = root->child_at(0);
[email protected]14522ce42014-08-08 18:56:16829 SiteInstance* child_instance = child->current_frame_host()->GetSiteInstance();
[email protected]82307f6b2014-08-07 03:30:12830 RenderViewHost* rvh = child->current_frame_host()->render_view_host();
831 RenderProcessHost* rph = child->current_frame_host()->GetProcess();
832
833 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
[email protected]14522ce42014-08-08 18:56:16834 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), child_instance);
Lukasz Anforowicz9e0ce4e2017-09-28 19:09:15835 EXPECT_NE(shell()->web_contents()->GetMainFrame()->GetProcess(), rph);
[email protected]82307f6b2014-08-07 03:30:12836
837 // Ensure that the root node has a proxy for the child node's SiteInstance.
[email protected]14522ce42014-08-08 18:56:16838 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(child_instance));
[email protected]82307f6b2014-08-07 03:30:12839
840 // Also ensure that the child has a proxy for the root node's SiteInstance.
[email protected]14522ce42014-08-08 18:56:16841 EXPECT_TRUE(child->render_manager()->GetRenderFrameProxyHost(root_instance));
842
843 // The nodes should not have proxies for their own SiteInstance.
844 EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(root_instance));
845 EXPECT_FALSE(
846 child->render_manager()->GetRenderFrameProxyHost(child_instance));
creise42f2a52014-09-18 18:14:57847
848 // Ensure that the RenderViews and RenderFrames are all live.
849 EXPECT_TRUE(
850 root->current_frame_host()->render_view_host()->IsRenderViewLive());
851 EXPECT_TRUE(
852 child->current_frame_host()->render_view_host()->IsRenderViewLive());
853 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
854 EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
[email protected]82307f6b2014-08-07 03:30:12855}
856
alexmosbc7eafa2014-12-06 01:38:09857IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
Nasko Oskov039121012019-01-11 00:21:32858 OriginSetOnNavigations) {
alexmos478dcbb2014-12-10 21:24:46859 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
alexmosbc7eafa2014-12-06 01:38:09860 EXPECT_TRUE(NavigateToURL(shell(), main_url));
861
862 // It is safe to obtain the root frame tree node here, as it doesn't change.
863 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
Aran Gilman37d11632019-10-08 23:07:15864 ->GetFrameTree()
865 ->root();
alexmosbc7eafa2014-12-06 01:38:09866
creisabdd2bd62015-11-21 01:14:58867 EXPECT_EQ(root->current_origin().Serialize() + '/',
alexmosbc7eafa2014-12-06 01:38:09868 main_url.GetOrigin().spec());
869
870 // First frame is an about:blank frame. Check that its origin is correctly
871 // inherited from the parent.
creisabdd2bd62015-11-21 01:14:58872 EXPECT_EQ(root->child_at(0)->current_origin().Serialize() + '/',
873 main_url.GetOrigin().spec());
alexmosbc7eafa2014-12-06 01:38:09874
875 // Second frame loads a same-site page. Its origin should also be the same
876 // as the parent.
creisabdd2bd62015-11-21 01:14:58877 EXPECT_EQ(root->child_at(1)->current_origin().Serialize() + '/',
878 main_url.GetOrigin().spec());
alexmosbc7eafa2014-12-06 01:38:09879
alexmosbc7eafa2014-12-06 01:38:09880 // Load cross-site page into the first frame.
alexmos478dcbb2014-12-10 21:24:46881 GURL cross_site_url(
882 embedded_test_server()->GetURL("foo.com", "/title2.html"));
alexmosbc7eafa2014-12-06 01:38:09883 NavigateFrameToURL(root->child_at(0), cross_site_url);
884
creisabdd2bd62015-11-21 01:14:58885 EXPECT_EQ(root->child_at(0)->current_origin().Serialize() + '/',
886 cross_site_url.GetOrigin().spec());
alexmosbc7eafa2014-12-06 01:38:09887
888 // The root's origin shouldn't have changed.
creisabdd2bd62015-11-21 01:14:58889 EXPECT_EQ(root->current_origin().Serialize() + '/',
alexmosbc7eafa2014-12-06 01:38:09890 main_url.GetOrigin().spec());
891
Nasko Oskov039121012019-01-11 00:21:32892 {
893 GURL data_url("data:text/html,foo");
894 TestNavigationObserver observer(shell()->web_contents());
895 EXPECT_TRUE(
896 ExecJs(root->child_at(1), JsReplace("window.location = $1", data_url)));
897 observer.Wait();
898 }
alexmosbc7eafa2014-12-06 01:38:09899
900 // Navigating to a data URL should set a unique origin. This is represented
Nasko Oskov039121012019-01-11 00:21:32901 // as "null" per RFC 6454. A frame navigating itself to a data: URL does not
902 // require a process transfer, but should retain the original origin
903 // as its precursor.
creisabdd2bd62015-11-21 01:14:58904 EXPECT_EQ(root->child_at(1)->current_origin().Serialize(), "null");
Nasko Oskov039121012019-01-11 00:21:32905 EXPECT_TRUE(root->child_at(1)->current_origin().opaque());
906 ASSERT_EQ(
907 url::SchemeHostPort(main_url),
908 root->child_at(1)->current_origin().GetTupleOrPrecursorTupleIfOpaque())
909 << "Expected the precursor origin to be preserved; should be the "
910 "initiator of a data: navigation.";
911
912 // Adding an <iframe sandbox srcdoc=> frame should result in a unique origin
913 // that is different-origin from its data: URL parent.
914 {
915 TestNavigationObserver observer(shell()->web_contents());
916
917 ASSERT_EQ(0U, root->child_at(1)->child_count());
918 EXPECT_TRUE(
919 ExecJs(root->child_at(1), JsReplace(
920 R"(
921 var iframe = document.createElement('iframe');
922 iframe.setAttribute('sandbox', 'allow-scripts');
923 iframe.srcdoc = $1;
924 document.body.appendChild(iframe);
925 )",
926 "<html><body>This sandboxed doc should "
927 "be different-origin.</body></html>")));
928 observer.Wait();
929 ASSERT_EQ(1U, root->child_at(1)->child_count());
930 }
931
932 url::Origin root_origin = root->current_origin();
933 url::Origin child_1 = root->child_at(1)->current_origin();
934 url::Origin child_1_0 = root->child_at(1)->child_at(0)->current_origin();
935 EXPECT_FALSE(root_origin.opaque());
936 EXPECT_TRUE(child_1.opaque());
937 EXPECT_TRUE(child_1_0.opaque());
938 EXPECT_NE(child_1, child_1_0);
939 EXPECT_EQ(url::SchemeHostPort(main_url),
940 root_origin.GetTupleOrPrecursorTupleIfOpaque());
941 EXPECT_EQ(url::SchemeHostPort(main_url),
942 child_1.GetTupleOrPrecursorTupleIfOpaque());
943 EXPECT_EQ(url::SchemeHostPort(main_url),
944 child_1_0.GetTupleOrPrecursorTupleIfOpaque());
945
946 {
947 TestNavigationObserver observer(shell()->web_contents());
948
949 ASSERT_EQ(1U, root->child_at(1)->child_count());
950 EXPECT_TRUE(
951 ExecJs(root->child_at(1), JsReplace(
952 R"(
953 var iframe = document.createElement('iframe');
954 iframe.srcdoc = $1;
955 document.body.appendChild(iframe);
956 )",
957 "<html><body>This srcdoc document should "
958 "be same-origin.</body></html>")));
959 observer.Wait();
960 ASSERT_EQ(2U, root->child_at(1)->child_count());
961 }
962 EXPECT_EQ(root_origin, root->current_origin());
963 EXPECT_EQ(child_1, root->child_at(1)->current_origin());
964 EXPECT_EQ(child_1_0, root->child_at(1)->child_at(0)->current_origin());
965 url::Origin child_1_1 = root->child_at(1)->child_at(1)->current_origin();
966 EXPECT_EQ(child_1, child_1_1);
967 EXPECT_NE(child_1_0, child_1_1);
968
969 {
970 TestNavigationObserver observer(shell()->web_contents());
971
972 ASSERT_EQ(2U, root->child_at(1)->child_count());
973 EXPECT_TRUE(
974 ExecJs(root->child_at(1), JsReplace(
975 R"(
976 var iframe = document.createElement('iframe');
977 iframe.src = 'data:text/html;base64,' + btoa($1);
978 document.body.appendChild(iframe);
979 )",
980 "<html><body>This data: doc should be "
981 "different-origin.</body></html>")));
982 observer.Wait();
983 ASSERT_EQ(3U, root->child_at(1)->child_count());
984 }
985 EXPECT_EQ(root_origin, root->current_origin());
986 EXPECT_EQ(child_1, root->child_at(1)->current_origin());
987 EXPECT_EQ(child_1_0, root->child_at(1)->child_at(0)->current_origin());
988 EXPECT_EQ(child_1_1, root->child_at(1)->child_at(1)->current_origin());
989 url::Origin child_1_2 = root->child_at(1)->child_at(2)->current_origin();
990 EXPECT_NE(child_1, child_1_2);
991 EXPECT_NE(child_1_0, child_1_2);
992 EXPECT_NE(child_1_1, child_1_2);
993 EXPECT_EQ(url::SchemeHostPort(main_url),
994 child_1_2.GetTupleOrPrecursorTupleIfOpaque());
995
996 // If the parent navigates its child to a data URL, it should transfer
997 // to the parent's process, and the precursor origin should track the
998 // parent's origin.
999 {
1000 GURL data_url("data:text/html,foo2");
1001 TestNavigationObserver observer(shell()->web_contents());
1002 EXPECT_TRUE(ExecJs(root, JsReplace("frames[0].location = $1", data_url)));
1003 observer.Wait();
1004 EXPECT_EQ(data_url, root->child_at(0)->current_url());
1005 }
1006
1007 EXPECT_EQ(root->child_at(0)->current_origin().Serialize(), "null");
1008 EXPECT_TRUE(root->child_at(0)->current_origin().opaque());
1009 EXPECT_EQ(
1010 url::SchemeHostPort(main_url),
1011 root->child_at(0)->current_origin().GetTupleOrPrecursorTupleIfOpaque());
1012 EXPECT_EQ(root->current_frame_host()->GetProcess(),
1013 root->child_at(0)->current_frame_host()->GetProcess());
1014}
1015
1016// Test to verify that a blob: URL that is created by a unique opaque origin
1017// will correctly set the origin_to_commit on a session history navigation.
1018IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
1019 OriginForBlobUrlsFromUniqueOpaqueOrigin) {
1020 // Start off with a navigation to data: URL in the main frame. It should
1021 // result in a unique opaque origin without any precursor information.
1022 GURL data_url("data:text/html,foo<iframe id='child' src='" +
1023 embedded_test_server()->GetURL("/title1.html").spec() +
1024 "'></iframe>");
1025 EXPECT_TRUE(NavigateToURL(shell(), data_url));
1026
1027 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1028 ->GetFrameTree()
1029 ->root();
1030 EXPECT_TRUE(root->current_origin().opaque());
1031 EXPECT_TRUE(
1032 root->current_origin().GetTupleOrPrecursorTupleIfOpaque().IsInvalid());
1033 EXPECT_EQ(1UL, root->child_count());
1034 FrameTreeNode* child = root->child_at(0);
1035
1036 // Create a blob: URL and navigate the child frame to it.
1037 std::string html = "<html><body>This is blob content.</body></html>";
1038 std::string script = JsReplace(
1039 "var blob = new Blob([$1], {type: 'text/html'});"
1040 "var blob_url = URL.createObjectURL(blob);"
1041 "document.getElementById('child').src = blob_url;"
1042 "blob_url;",
1043 html);
1044 GURL blob_url;
1045 {
1046 TestFrameNavigationObserver observer(child);
1047 blob_url = GURL(EvalJs(root, script).ExtractString());
1048 observer.Wait();
1049 EXPECT_EQ(blob_url, child->current_frame_host()->GetLastCommittedURL());
1050 }
1051
1052 // We expect the frame to have committed in an opaque origin which contains
1053 // the same precursor information - none.
1054 url::Origin blob_origin = child->current_origin();
1055 EXPECT_TRUE(blob_origin.opaque());
1056 EXPECT_EQ(root->current_origin().GetTupleOrPrecursorTupleIfOpaque(),
1057 blob_origin.GetTupleOrPrecursorTupleIfOpaque());
1058
1059 // Navigate the frame away to any web URL.
1060 {
1061 GURL url(embedded_test_server()->GetURL("/title2.html"));
1062 TestFrameNavigationObserver observer(child);
1063 EXPECT_TRUE(ExecJs(child, JsReplace("window.location = $1", url)));
1064 observer.Wait();
1065 EXPECT_EQ(url, child->current_frame_host()->GetLastCommittedURL());
1066 }
1067 EXPECT_FALSE(child->current_origin().opaque());
1068 EXPECT_TRUE(shell()->web_contents()->GetController().CanGoBack());
1069 EXPECT_EQ(3, shell()->web_contents()->GetController().GetEntryCount());
1070 EXPECT_EQ(
1071 2, shell()->web_contents()->GetController().GetLastCommittedEntryIndex());
1072
1073 // Verify the blob URL still exists in the main frame, which keeps it alive
1074 // allowing a session history navigation back to succeed.
1075 EXPECT_EQ(blob_url, GURL(EvalJs(root, "blob_url;").ExtractString()));
1076
1077 // Now navigate back in session history. It should successfully go back to
1078 // the blob: URL.
1079 {
1080 TestFrameNavigationObserver observer(child);
1081 shell()->web_contents()->GetController().GoBack();
1082 observer.Wait();
1083 }
1084 EXPECT_EQ(blob_url, child->current_frame_host()->GetLastCommittedURL());
1085 EXPECT_TRUE(child->current_origin().opaque());
1086 EXPECT_EQ(blob_origin, child->current_origin());
1087 EXPECT_EQ(root->current_origin().GetTupleOrPrecursorTupleIfOpaque(),
1088 child->current_origin().GetTupleOrPrecursorTupleIfOpaque());
1089}
1090
1091// Test to verify that about:blank iframe, which is a child of a sandboxed
1092// iframe is not considered same origin, but precursor information is preserved
1093// in its origin.
1094IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
1095 AboutBlankSubframeInSandboxedFrame) {
1096 // Start off by navigating to a page with sandboxed iframe, which allows
1097 // script execution.
1098 GURL main_url(
1099 embedded_test_server()->GetURL("/sandboxed_main_frame_script.html"));
1100 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1101
1102 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1103 ->GetFrameTree()
1104 ->root();
1105 EXPECT_EQ(1UL, root->child_count());
1106 FrameTreeNode* child = root->child_at(0);
1107
1108 // Navigate the frame to data: URL to cause it to have an opaque origin that
1109 // is derived from the |main_url| origin.
1110 GURL data_url("data:text/html,<html><body>foo</body></html>");
1111 {
1112 TestFrameNavigationObserver observer(child);
1113 EXPECT_TRUE(ExecJs(root, JsReplace("frames[0].location = $1", data_url)));
1114 observer.Wait();
1115 EXPECT_EQ(data_url, child->current_frame_host()->GetLastCommittedURL());
1116 }
1117
1118 // Add an about:blank iframe to the data: frame, which should not inherit the
1119 // origin, but should preserve the precursor information.
1120 {
1121 EXPECT_TRUE(ExecJs(child,
1122 "var f = document.createElement('iframe');"
1123 "document.body.appendChild(f);"));
1124 }
1125 EXPECT_EQ(1UL, child->child_count());
1126 FrameTreeNode* grandchild = child->child_at(0);
1127
1128 EXPECT_TRUE(grandchild->current_origin().opaque());
1129 EXPECT_EQ(GURL(url::kAboutBlankURL),
1130 grandchild->current_frame_host()->GetLastCommittedURL());
1131
1132 // The origin of the data: document should have precursor information matching
1133 // the main frame origin.
1134 EXPECT_EQ(root->current_origin().GetTupleOrPrecursorTupleIfOpaque(),
1135 child->current_origin().GetTupleOrPrecursorTupleIfOpaque());
1136
1137 // The same should hold also for the about:blank subframe of the data: frame.
1138 EXPECT_EQ(root->current_origin().GetTupleOrPrecursorTupleIfOpaque(),
1139 grandchild->current_origin().GetTupleOrPrecursorTupleIfOpaque());
1140
1141 // The about:blank document should not be able to access its parent, as they
1142 // are considered cross origin due to the sandbox flags on the parent.
1143 EXPECT_FALSE(ExecJs(grandchild, "window.parent.foo = 'bar';"));
1144 EXPECT_NE(child->current_origin(), grandchild->current_origin());
alexmosbc7eafa2014-12-06 01:38:091145}
1146
Ian Clelland5cbaaf82017-11-27 22:00:031147// Ensure that a popup opened from a sandboxed main frame inherits sandbox flags
1148// from its opener.
1149IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
1150 SandboxFlagsSetForNewWindow) {
1151 GURL main_url(
1152 embedded_test_server()->GetURL("/sandboxed_main_frame_script.html"));
1153 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1154
1155 // It is safe to obtain the root frame tree node here, as it doesn't change.
1156 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1157 ->GetFrameTree()
1158 ->root();
1159
1160 // Open a new window from the main frame.
1161 GURL popup_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
1162 Shell* new_shell = OpenPopup(root->current_frame_host(), popup_url, "");
1163 EXPECT_TRUE(new_shell);
1164 WebContents* new_contents = new_shell->web_contents();
1165
1166 // Check that the new window's sandbox flags correctly reflect the opener's
1167 // flags. Main frame sets allow-popups, allow-pointer-lock and allow-scripts.
1168 FrameTreeNode* popup_root =
1169 static_cast<WebContentsImpl*>(new_contents)->GetFrameTree()->root();
1170 blink::WebSandboxFlags main_frame_sandbox_flags =
1171 root->current_frame_host()->active_sandbox_flags();
1172 EXPECT_EQ(blink::WebSandboxFlags::kAll & ~blink::WebSandboxFlags::kPopups &
1173 ~blink::WebSandboxFlags::kPointerLock &
1174 ~blink::WebSandboxFlags::kScripts &
1175 ~blink::WebSandboxFlags::kAutomaticFeatures,
1176 main_frame_sandbox_flags);
1177
1178 EXPECT_EQ(main_frame_sandbox_flags,
1179 popup_root->effective_frame_policy().sandbox_flags);
1180 EXPECT_EQ(main_frame_sandbox_flags, popup_root->active_sandbox_flags());
1181 EXPECT_EQ(main_frame_sandbox_flags,
1182 popup_root->current_frame_host()->active_sandbox_flags());
1183}
1184
Shivani Sharmac4f561582018-11-15 15:58:391185// Tests that the user activation bits get cleared when a cross-site document is
1186// installed in the frame.
1187IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
1188 ClearUserActivationForNewDocument) {
1189 GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
1190 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1191
1192 // It is safe to obtain the root frame tree node here, as it doesn't change.
1193 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1194 ->GetFrameTree()
1195 ->root();
1196
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461197 EXPECT_FALSE(root->HasStickyUserActivation());
Shivani Sharmac4f561582018-11-15 15:58:391198 EXPECT_FALSE(root->HasTransientUserActivation());
1199
1200 // Set the user activation bits.
1201 root->UpdateUserActivationState(
1202 blink::UserActivationUpdateType::kNotifyActivation);
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461203 EXPECT_TRUE(root->HasStickyUserActivation());
Shivani Sharmac4f561582018-11-15 15:58:391204 EXPECT_TRUE(root->HasTransientUserActivation());
1205
1206 // Install a new cross-site document to check the clearing of user activation
1207 // bits.
1208 GURL cross_site_url(
1209 embedded_test_server()->GetURL("foo.com", "/title2.html"));
1210 EXPECT_TRUE(NavigateToURL(shell(), cross_site_url));
1211
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461212 EXPECT_FALSE(root->HasStickyUserActivation());
Shivani Sharmac4f561582018-11-15 15:58:391213 EXPECT_FALSE(root->HasTransientUserActivation());
1214}
1215
nickdb193a12016-09-09 23:09:231216// FrameTreeBrowserTest variant where we isolate http://*.is, Iceland's top
naskoabed2a52017-05-03 05:10:171217// level domain. This is an analogue to isolating extensions, which we can use
1218// inside content_browsertests, where extensions don't exist. Iceland, like an
nickdb193a12016-09-09 23:09:231219// extension process, is a special place with magical powers; we want to protect
1220// it from outsiders.
1221class IsolateIcelandFrameTreeBrowserTest : public ContentBrowserTest {
1222 public:
1223 IsolateIcelandFrameTreeBrowserTest() {}
1224
1225 void SetUpCommandLine(base::CommandLine* command_line) override {
Lukasz Anforowicze7c87d12018-11-03 02:53:341226 // Blink suppresses navigations to blob URLs of origins different from the
alexis.menard83f1b6d2017-05-17 19:37:331227 // frame initiating the navigation. We disable those checks for this test,
1228 // to test what happens in a compromise scenario.
1229 command_line->AppendSwitch(switches::kDisableWebSecurity);
Lukasz Anforowicze7c87d12018-11-03 02:53:341230
1231 // ProcessSwitchForIsolatedBlob test below requires that one of URLs used in
Lukasz Anforowicz25420932018-12-18 20:59:221232 // the test (blob:http://b.is/) belongs to an isolated origin.
1233 command_line->AppendSwitchASCII(switches::kIsolateOrigins, "http://b.is/");
nickdb193a12016-09-09 23:09:231234 }
1235
1236 void SetUpOnMainThread() override {
1237 host_resolver()->AddRule("*", "127.0.0.1");
nickdb193a12016-09-09 23:09:231238 SetupCrossSiteRedirector(embedded_test_server());
martijn12d2dad2016-11-11 10:59:271239 ASSERT_TRUE(embedded_test_server()->Start());
nickdb193a12016-09-09 23:09:231240 }
1241
1242 private:
1243 DISALLOW_COPY_AND_ASSIGN(IsolateIcelandFrameTreeBrowserTest);
1244};
1245
1246// Regression test for https://crbug.com/644966
1247IN_PROC_BROWSER_TEST_F(IsolateIcelandFrameTreeBrowserTest,
1248 ProcessSwitchForIsolatedBlob) {
nickdb193a12016-09-09 23:09:231249 // Set up an iframe.
1250 WebContents* contents = shell()->web_contents();
1251 FrameTreeNode* root =
1252 static_cast<WebContentsImpl*>(contents)->GetFrameTree()->root();
1253 GURL main_url(embedded_test_server()->GetURL(
nick07fd7e12016-09-12 18:54:061254 "a.com", "/cross_site_iframe_factory.html?a(a)"));
nickdb193a12016-09-09 23:09:231255 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1256
1257 // The navigation targets an invalid blob url; that's intentional to trigger
1258 // an error response. The response should commit in a process dedicated to
Lukasz Anforowicz25420932018-12-18 20:59:221259 // http://b.is.
Nick Carterb7e71312018-08-03 23:36:131260 EXPECT_EQ(
1261 "done",
1262 EvalJs(
1263 root,
1264 "new Promise((resolve) => {"
1265 " var iframe_element = document.getElementsByTagName('iframe')[0];"
1266 " iframe_element.onload = () => resolve('done');"
Lukasz Anforowicz25420932018-12-18 20:59:221267 " iframe_element.src = 'blob:http://b.is/';"
Nick Carterb7e71312018-08-03 23:36:131268 "});"));
nickdb193a12016-09-09 23:09:231269 WaitForLoadStop(contents);
1270
1271 // Make sure we did a process transfer back to "b.is".
Aaron Colwelle953e562019-07-24 16:47:361272 const std::string kExpectedSiteURL =
1273 AreDefaultSiteInstancesEnabled()
1274 ? SiteInstanceImpl::GetDefaultSiteURL().spec()
1275 : "http://a.com/";
1276 EXPECT_EQ(base::StringPrintf(" Site A ------------ proxies for B\n"
1277 " +--Site B ------- proxies for A\n"
1278 "Where A = %s\n"
1279 " B = http://b.is/",
1280 kExpectedSiteURL.c_str()),
1281 FrameTreeVisualizer().DepictFrameTree(root));
nickdb193a12016-09-09 23:09:231282}
1283
Lan Wei3c2cbad2019-03-29 21:53:531284#if !defined(OS_ANDROID)
1285// Test transferring the user activation state between nodes in the frame tree.
1286class TransferUserActivationFrameTreeBrowserTest : public ContentBrowserTest {
1287 public:
1288 TransferUserActivationFrameTreeBrowserTest() {}
1289
1290 void SetUpCommandLine(base::CommandLine* command_line) override {
1291 feature_list_.InitWithFeatures(
1292 {features::kUserActivationPostMessageTransfer,
Mustaq Ahmede5f12562019-10-30 18:02:031293 features::kUserActivationSameOriginVisibility},
Lan Wei3c2cbad2019-03-29 21:53:531294 {});
1295 }
1296
1297 void SetUpOnMainThread() override {
1298 host_resolver()->AddRule("*", "127.0.0.1");
1299 SetupCrossSiteRedirector(embedded_test_server());
1300 ASSERT_TRUE(embedded_test_server()->Start());
1301 }
1302
1303 private:
1304 base::test::ScopedFeatureList feature_list_;
1305
1306 DISALLOW_COPY_AND_ASSIGN(TransferUserActivationFrameTreeBrowserTest);
1307};
1308
1309IN_PROC_BROWSER_TEST_F(TransferUserActivationFrameTreeBrowserTest,
Lan Weic927a412019-05-09 18:37:381310 PostMessageTransferActivationCrossOrigin) {
Lan Wei3c2cbad2019-03-29 21:53:531311 GURL main_url(embedded_test_server()->GetURL(
1312 "a.com", "/cross_site_iframe_factory.html?a(b,c)"));
1313 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1314
1315 WebContentsImpl* contents =
1316 static_cast<WebContentsImpl*>(shell()->web_contents());
1317 FrameTreeNode* root = contents->GetFrameTree()->root();
1318 FrameTreeNode* child1 = root->child_at(0);
1319 FrameTreeNode* child2 = root->child_at(1);
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461320 EXPECT_FALSE(root->HasStickyUserActivation());
Lan Wei3c2cbad2019-03-29 21:53:531321 EXPECT_FALSE(root->HasTransientUserActivation());
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461322 EXPECT_FALSE(child1->HasStickyUserActivation());
Lan Wei3c2cbad2019-03-29 21:53:531323 EXPECT_FALSE(child1->HasTransientUserActivation());
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461324 EXPECT_FALSE(child2->HasStickyUserActivation());
Lan Wei3c2cbad2019-03-29 21:53:531325 EXPECT_FALSE(child2->HasTransientUserActivation());
1326
1327 // Activate the root frame.
1328 EXPECT_TRUE(ExecuteScript(shell(), ""));
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461329 EXPECT_TRUE(root->HasStickyUserActivation());
Lan Wei3c2cbad2019-03-29 21:53:531330 EXPECT_TRUE(root->HasTransientUserActivation());
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461331 EXPECT_FALSE(child1->HasStickyUserActivation());
Lan Wei3c2cbad2019-03-29 21:53:531332 EXPECT_FALSE(child1->HasTransientUserActivation());
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461333 EXPECT_FALSE(child2->HasStickyUserActivation());
Lan Wei3c2cbad2019-03-29 21:53:531334 EXPECT_FALSE(child2->HasTransientUserActivation());
1335
1336 // Post a message from the root frame to the child frame with
1337 // |transferUserActivation| true to transfer the user activation state from
1338 // root to child.
1339 EXPECT_TRUE(ExecuteScriptWithoutUserGesture(
1340 child1->current_frame_host(),
1341 "window.addEventListener('message', function(event) {\n"
1342 " domAutomationController.send('done-' + event.data);\n"
1343 "});"));
1344 DOMMessageQueue msg_queue;
1345 std::string actual_test_reply;
1346 EXPECT_TRUE(ExecuteScriptWithoutUserGesture(
1347 shell(),
1348 "window.frames[0].postMessage('Hello', "
1349 "{targetOrigin: '*', transferUserActivation: "
1350 "true})"));
1351 while (msg_queue.WaitForMessage(&actual_test_reply)) {
1352 if (actual_test_reply == "\"done-Hello\"")
1353 break;
1354 }
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461355 EXPECT_FALSE(root->HasStickyUserActivation());
Lan Wei3c2cbad2019-03-29 21:53:531356 EXPECT_FALSE(root->HasTransientUserActivation());
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461357 EXPECT_TRUE(child1->HasStickyUserActivation());
Lan Wei3c2cbad2019-03-29 21:53:531358 EXPECT_TRUE(child1->HasTransientUserActivation());
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461359 EXPECT_FALSE(child2->HasStickyUserActivation());
Lan Wei3c2cbad2019-03-29 21:53:531360 EXPECT_FALSE(child2->HasTransientUserActivation());
1361
1362 // Post a message from one child to another child in a different origin with
1363 // |transferUserActivation| true to transfer the user activation state from
1364 // one child to another child node in the frame tree.
1365 EXPECT_TRUE(ExecuteScriptWithoutUserGesture(
1366 child2->current_frame_host(),
1367 "window.addEventListener('message', function(event) {\n"
1368 " domAutomationController.send('done-' + event.data);\n"
1369 "});"));
1370 EXPECT_TRUE(ExecuteScriptWithoutUserGesture(
1371 child1->current_frame_host(),
1372 "window.parent.frames[1].postMessage('Hey', "
1373 "{targetOrigin: '*', transferUserActivation: "
1374 "true})"));
1375 while (msg_queue.WaitForMessage(&actual_test_reply)) {
1376 if (actual_test_reply == "\"done-Hey\"")
1377 break;
1378 }
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461379 EXPECT_FALSE(root->HasStickyUserActivation());
Lan Wei3c2cbad2019-03-29 21:53:531380 EXPECT_FALSE(root->HasTransientUserActivation());
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461381 EXPECT_FALSE(child1->HasStickyUserActivation());
Lan Wei3c2cbad2019-03-29 21:53:531382 EXPECT_FALSE(child1->HasTransientUserActivation());
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461383 EXPECT_TRUE(child2->HasStickyUserActivation());
Lan Wei3c2cbad2019-03-29 21:53:531384 EXPECT_TRUE(child2->HasTransientUserActivation());
1385}
Lan Weic927a412019-05-09 18:37:381386
1387IN_PROC_BROWSER_TEST_F(TransferUserActivationFrameTreeBrowserTest,
1388 PostMessageTransferActivationSameOrigin) {
1389 GURL main_url(embedded_test_server()->GetURL(
1390 "a.com", "/cross_site_iframe_factory.html?a(b(b))"));
1391 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1392
1393 WebContentsImpl* contents =
1394 static_cast<WebContentsImpl*>(shell()->web_contents());
1395 FrameTreeNode* root = contents->GetFrameTree()->root();
1396 FrameTreeNode* child1 = root->child_at(0);
1397 FrameTreeNode* child2 = child1->child_at(0);
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461398 EXPECT_FALSE(root->HasStickyUserActivation());
Lan Weic927a412019-05-09 18:37:381399 EXPECT_FALSE(root->HasTransientUserActivation());
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461400 EXPECT_FALSE(child1->HasStickyUserActivation());
Lan Weic927a412019-05-09 18:37:381401 EXPECT_FALSE(child1->HasTransientUserActivation());
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461402 EXPECT_FALSE(child2->HasStickyUserActivation());
Lan Weic927a412019-05-09 18:37:381403 EXPECT_FALSE(child2->HasTransientUserActivation());
1404
1405 // Activate the root frame and transfer the user activation state from root
1406 // to child1.
1407 std::string message_event_listener =
1408 "window.addEventListener('message', function(event) {\n"
1409 " domAutomationController.send('done-' + event.data);\n"
1410 "});";
1411 EXPECT_TRUE(ExecuteScript(shell(), ""));
1412 EXPECT_TRUE(ExecuteScriptWithoutUserGesture(child1->current_frame_host(),
1413 message_event_listener));
1414 DOMMessageQueue msg_queue;
1415 std::string actual_test_reply;
1416 EXPECT_TRUE(ExecuteScriptWithoutUserGesture(
1417 shell(),
1418 "window.frames[0].postMessage('Hello', "
1419 "{targetOrigin: '*', transferUserActivation: true})"));
1420 while (msg_queue.WaitForMessage(&actual_test_reply)) {
1421 if (actual_test_reply == "\"done-Hello\"")
1422 break;
1423 }
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461424 EXPECT_FALSE(root->HasStickyUserActivation());
Lan Weic927a412019-05-09 18:37:381425 EXPECT_FALSE(root->HasTransientUserActivation());
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461426 EXPECT_TRUE(child1->HasStickyUserActivation());
Lan Weic927a412019-05-09 18:37:381427 EXPECT_TRUE(child1->HasTransientUserActivation());
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461428 EXPECT_FALSE(child2->HasStickyUserActivation());
Lan Weic927a412019-05-09 18:37:381429 EXPECT_FALSE(child2->HasTransientUserActivation());
1430
1431 // Post a message from child1 to its child child2 in the same origin with
1432 // |transferUserActivation| true to transfer the user activation state from
1433 // one node to its child node in the frame tree.
1434 EXPECT_TRUE(ExecuteScriptWithoutUserGesture(child2->current_frame_host(),
1435 message_event_listener));
1436 EXPECT_TRUE(ExecuteScriptWithoutUserGesture(
1437 child1->current_frame_host(),
1438 "window.frames[0].postMessage('Hey', "
1439 "{targetOrigin: '*', transferUserActivation: true})"));
1440 while (msg_queue.WaitForMessage(&actual_test_reply)) {
1441 if (actual_test_reply == "\"done-Hey\"")
1442 break;
1443 }
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461444 EXPECT_FALSE(root->HasStickyUserActivation());
Lan Weic927a412019-05-09 18:37:381445 EXPECT_FALSE(root->HasTransientUserActivation());
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461446 EXPECT_FALSE(child1->HasStickyUserActivation());
Lan Weic927a412019-05-09 18:37:381447 EXPECT_FALSE(child1->HasTransientUserActivation());
Mustaq Ahmed4baa9a6e82019-12-20 23:43:461448 EXPECT_TRUE(child2->HasStickyUserActivation());
Lan Weic927a412019-05-09 18:37:381449 EXPECT_TRUE(child2->HasTransientUserActivation());
1450}
Lan Wei3c2cbad2019-03-29 21:53:531451#endif
1452
[email protected]5f96f5a62014-01-10 00:05:111453} // namespace content