blob: bdcff19d9483750b3450e54be0033c53a153c04b [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
avib7348942015-12-25 20:57:105#include "base/macros.h"
6#include "build/build_config.h"
[email protected]5f96f5a62014-01-10 00:05:117#include "content/browser/frame_host/frame_tree.h"
8#include "content/browser/frame_host/frame_tree_node.h"
9#include "content/browser/renderer_host/render_view_host_impl.h"
10#include "content/browser/web_contents/web_contents_impl.h"
11#include "content/public/browser/notification_service.h"
12#include "content/public/browser/notification_types.h"
nickdb193a12016-09-09 23:09:2313#include "content/public/common/content_switches.h"
[email protected]5f96f5a62014-01-10 00:05:1114#include "content/public/common/url_constants.h"
15#include "content/public/test/browser_test_utils.h"
[email protected]6e9def12014-03-27 20:23:2816#include "content/public/test/content_browser_test.h"
17#include "content/public/test/content_browser_test_utils.h"
[email protected]5f96f5a62014-01-10 00:05:1118#include "content/public/test/test_navigation_observer.h"
19#include "content/public/test/test_utils.h"
20#include "content/shell/browser/shell.h"
nickdb193a12016-09-09 23:09:2321#include "content/shell/common/shell_switches.h"
[email protected]82307f6b2014-08-07 03:30:1222#include "content/test/content_browser_test_utils_internal.h"
nick9f34e2892016-01-12 21:01:0723#include "content/test/test_frame_navigation_observer.h"
[email protected]5f96f5a62014-01-10 00:05:1124#include "net/dns/mock_host_resolver.h"
alexmos478dcbb2014-12-10 21:24:4625#include "net/test/embedded_test_server/embedded_test_server.h"
dcheng5f60abb2015-05-28 01:39:3626#include "third_party/WebKit/public/web/WebSandboxFlags.h"
nick1466c842015-11-25 20:08:0627#include "url/url_constants.h"
[email protected]5f96f5a62014-01-10 00:05:1128
kjellander4badba22015-03-19 11:47:0729// For fine-grained suppression on flaky tests.
30#if defined(OS_WIN)
31#include "base/win/windows_version.h"
32#endif
33
[email protected]5f96f5a62014-01-10 00:05:1134namespace content {
35
nickdb193a12016-09-09 23:09:2336namespace {
37
38std::string GetOriginFromRenderer(FrameTreeNode* node) {
39 std::string origin;
40 EXPECT_TRUE(ExecuteScriptAndExtractString(
41 node, "window.domAutomationController.send(document.origin);", &origin));
42 return origin;
43}
44
45} // namespace
46
[email protected]5f96f5a62014-01-10 00:05:1147class FrameTreeBrowserTest : public ContentBrowserTest {
48 public:
49 FrameTreeBrowserTest() {}
50
alexmos478dcbb2014-12-10 21:24:4651 void SetUpOnMainThread() override {
52 host_resolver()->AddRule("*", "127.0.0.1");
alexmos478dcbb2014-12-10 21:24:4653 SetupCrossSiteRedirector(embedded_test_server());
martijn12d2dad2016-11-11 10:59:2754 ASSERT_TRUE(embedded_test_server()->Start());
alexmos478dcbb2014-12-10 21:24:4655 }
56
[email protected]5f96f5a62014-01-10 00:05:1157 private:
58 DISALLOW_COPY_AND_ASSIGN(FrameTreeBrowserTest);
59};
60
61// Ensures FrameTree correctly reflects page structure during navigations.
62IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape) {
alexmos478dcbb2014-12-10 21:24:4663 GURL base_url = embedded_test_server()->GetURL("A.com", "/site_isolation/");
[email protected]5f96f5a62014-01-10 00:05:1164
65 // Load doc without iframes. Verify FrameTree just has root.
66 // Frame tree:
67 // Site-A Root
68 NavigateToURL(shell(), base_url.Resolve("blank.html"));
69 FrameTreeNode* root =
70 static_cast<WebContentsImpl*>(shell()->web_contents())->
71 GetFrameTree()->root();
72 EXPECT_EQ(0U, root->child_count());
73
74 // Add 2 same-site frames. Verify 3 nodes in tree with proper names.
75 // Frame tree:
76 // Site-A Root -- Site-A frame1
77 // \-- Site-A frame2
78 WindowedNotificationObserver observer1(
79 content::NOTIFICATION_LOAD_STOP,
80 content::Source<NavigationController>(
81 &shell()->web_contents()->GetController()));
82 NavigateToURL(shell(), base_url.Resolve("frames-X-X.html"));
83 observer1.Wait();
84 ASSERT_EQ(2U, root->child_count());
85 EXPECT_EQ(0U, root->child_at(0)->child_count());
86 EXPECT_EQ(0U, root->child_at(1)->child_count());
87}
88
89// TODO(ajwong): Talk with nasko and merge this functionality with
90// FrameTreeShape.
91IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape2) {
[email protected]5f96f5a62014-01-10 00:05:1192 NavigateToURL(shell(),
alexmos478dcbb2014-12-10 21:24:4693 embedded_test_server()->GetURL("/frame_tree/top.html"));
[email protected]5f96f5a62014-01-10 00:05:1194
95 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
[email protected]5f96f5a62014-01-10 00:05:1196 FrameTreeNode* root = wc->GetFrameTree()->root();
97
[email protected]58faf942014-02-20 21:03:5898 // Check that the root node is properly created.
[email protected]5f96f5a62014-01-10 00:05:1199 ASSERT_EQ(3UL, root->child_count());
100 EXPECT_EQ(std::string(), root->frame_name());
[email protected]5f96f5a62014-01-10 00:05:11101
102 ASSERT_EQ(2UL, root->child_at(0)->child_count());
103 EXPECT_STREQ("1-1-name", root->child_at(0)->frame_name().c_str());
104
105 // Verify the deepest node exists and has the right name.
106 ASSERT_EQ(2UL, root->child_at(2)->child_count());
107 EXPECT_EQ(1UL, root->child_at(2)->child_at(1)->child_count());
108 EXPECT_EQ(0UL, root->child_at(2)->child_at(1)->child_at(0)->child_count());
[email protected]b0cd7a952014-03-08 11:44:06109 EXPECT_STREQ("3-1-name",
[email protected]5f96f5a62014-01-10 00:05:11110 root->child_at(2)->child_at(1)->child_at(0)->frame_name().c_str());
111
112 // Navigate to about:blank, which should leave only the root node of the frame
113 // tree in the browser process.
alexmos478dcbb2014-12-10 21:24:46114 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) {
[email protected]5f96f5a62014-01-10 00:05:11124 NavigateToURL(shell(),
alexmos478dcbb2014-12-10 21:24:46125 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();
129 RenderFrameHostImpl* rfh =
130 static_cast<RenderFrameHostImpl*>(rvh->GetMainFrame());
131 EXPECT_TRUE(rvh->IsRenderViewLive());
132 EXPECT_TRUE(rfh->IsRenderFrameLive());
133
[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);
138 NavigateToURL(shell(), GURL(kChromeUICrashURL));
139 crash_observer.Wait();
140
[email protected]58faf942014-02-20 21:03:58141 // The frame tree should be cleared.
[email protected]5f96f5a62014-01-10 00:05:11142 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
[email protected]5f96f5a62014-01-10 00:05:11143 FrameTreeNode* root = wc->GetFrameTree()->root();
144 EXPECT_EQ(0UL, root->child_count());
[email protected]5f96f5a62014-01-10 00:05:11145
creise42f2a52014-09-18 18:14:57146 // Ensure the view and frame aren't live anymore.
147 EXPECT_FALSE(rvh->IsRenderViewLive());
148 EXPECT_FALSE(rfh->IsRenderFrameLive());
149
[email protected]5f96f5a62014-01-10 00:05:11150 // Navigate to a new URL.
alexmos478dcbb2014-12-10 21:24:46151 GURL url(embedded_test_server()->GetURL("/title1.html"));
[email protected]58faf942014-02-20 21:03:58152 NavigateToURL(shell(), url);
[email protected]5f96f5a62014-01-10 00:05:11153 EXPECT_EQ(0UL, root->child_count());
[email protected]58faf942014-02-20 21:03:58154 EXPECT_EQ(url, root->current_url());
creise42f2a52014-09-18 18:14:57155
156 // Ensure the view and frame are live again.
157 EXPECT_TRUE(rvh->IsRenderViewLive());
158 EXPECT_TRUE(rfh->IsRenderFrameLive());
[email protected]5f96f5a62014-01-10 00:05:11159}
160
161// Test that we can navigate away if the previous renderer doesn't clean up its
162// child frames.
pauljensen58ee2ea22015-01-26 17:45:53163// Flaky on Mac. http://crbug.com/452018
164#if defined(OS_MACOSX)
165#define MAYBE_NavigateWithLeftoverFrames DISABLED_NavigateWithLeftoverFrames
166#else
167#define MAYBE_NavigateWithLeftoverFrames NavigateWithLeftoverFrames
168#endif
169IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, MAYBE_NavigateWithLeftoverFrames) {
kjellander4badba22015-03-19 11:47:07170#if defined(OS_WIN)
171 // Flaky on XP bot http://crbug.com/468713
172 if (base::win::GetVersion() <= base::win::VERSION_XP)
173 return;
174#endif
alexmos478dcbb2014-12-10 21:24:46175 GURL base_url = embedded_test_server()->GetURL("A.com", "/site_isolation/");
[email protected]5f96f5a62014-01-10 00:05:11176
177 NavigateToURL(shell(),
alexmos478dcbb2014-12-10 21:24:46178 embedded_test_server()->GetURL("/frame_tree/top.html"));
[email protected]5f96f5a62014-01-10 00:05:11179
180 // Hang the renderer so that it doesn't send any FrameDetached messages.
181 // (This navigation will never complete, so don't wait for it.)
182 shell()->LoadURL(GURL(kChromeUIHangURL));
183
184 // Check that the frame tree still has children.
185 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
186 FrameTreeNode* root = wc->GetFrameTree()->root();
187 ASSERT_EQ(3UL, root->child_count());
188
189 // Navigate to a new URL. We use LoadURL because NavigateToURL will try to
190 // wait for the previous navigation to stop.
191 TestNavigationObserver tab_observer(wc, 1);
192 shell()->LoadURL(base_url.Resolve("blank.html"));
193 tab_observer.Wait();
194
[email protected]58faf942014-02-20 21:03:58195 // The frame tree should now be cleared.
[email protected]5f96f5a62014-01-10 00:05:11196 EXPECT_EQ(0UL, root->child_count());
[email protected]5f96f5a62014-01-10 00:05:11197}
198
creise42f2a52014-09-18 18:14:57199// Ensure that IsRenderFrameLive is true for main frames and same-site iframes.
200IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, IsRenderFrameLive) {
alexmos478dcbb2014-12-10 21:24:46201 GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
creise42f2a52014-09-18 18:14:57202 NavigateToURL(shell(), main_url);
203
204 // It is safe to obtain the root frame tree node here, as it doesn't change.
205 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
206 ->GetFrameTree()->root();
207
208 // The root and subframe should each have a live RenderFrame.
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 // Load a same-site page into iframe and it should still be live.
alexmos478dcbb2014-12-10 21:24:46215 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
creise42f2a52014-09-18 18:14:57216 NavigateFrameToURL(root->child_at(0), http_url);
217 EXPECT_TRUE(
218 root->current_frame_host()->render_view_host()->IsRenderViewLive());
219 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
220 EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
221}
222
alexmosbc7eafa2014-12-06 01:38:09223// Ensure that origins are correctly set on navigations.
224IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, OriginSetOnNavigation) {
nick1466c842015-11-25 20:08:06225 GURL about_blank(url::kAboutBlankURL);
226 GURL main_url(
227 embedded_test_server()->GetURL("a.com", "/frame_tree/top.html"));
alexmosbc7eafa2014-12-06 01:38:09228 EXPECT_TRUE(NavigateToURL(shell(), main_url));
nick1466c842015-11-25 20:08:06229 WebContents* contents = shell()->web_contents();
alexmosbc7eafa2014-12-06 01:38:09230
231 // It is safe to obtain the root frame tree node here, as it doesn't change.
nick1466c842015-11-25 20:08:06232 FrameTreeNode* root =
233 static_cast<WebContentsImpl*>(contents)->GetFrameTree()->root();
alexmosbc7eafa2014-12-06 01:38:09234
235 // Extra '/' is added because the replicated origin is serialized in RFC 6454
236 // format, which dictates no trailing '/', whereas GURL::GetOrigin does put a
237 // '/' at the end.
nick1466c842015-11-25 20:08:06238 EXPECT_EQ(main_url.GetOrigin().spec(),
239 root->current_origin().Serialize() + '/');
240 EXPECT_EQ(
241 main_url.GetOrigin().spec(),
242 root->current_frame_host()->GetLastCommittedOrigin().Serialize() + '/');
alexmosbc7eafa2014-12-06 01:38:09243
nick1466c842015-11-25 20:08:06244 // The iframe is inititially same-origin.
245 EXPECT_TRUE(
246 root->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
247 root->child_at(0)->current_frame_host()->GetLastCommittedOrigin()));
248 EXPECT_EQ(root->current_origin().Serialize(), GetOriginFromRenderer(root));
249 EXPECT_EQ(root->child_at(0)->current_origin().Serialize(),
250 GetOriginFromRenderer(root->child_at(0)));
251
252 // Navigate the iframe cross-origin.
253 GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
alexmosbc7eafa2014-12-06 01:38:09254 NavigateFrameToURL(root->child_at(0), frame_url);
nick1466c842015-11-25 20:08:06255 EXPECT_EQ(frame_url, root->child_at(0)->current_url());
256 EXPECT_EQ(frame_url.GetOrigin().spec(),
257 root->child_at(0)->current_origin().Serialize() + '/');
258 EXPECT_FALSE(
259 root->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
260 root->child_at(0)->current_frame_host()->GetLastCommittedOrigin()));
261 EXPECT_EQ(root->current_origin().Serialize(), GetOriginFromRenderer(root));
262 EXPECT_EQ(root->child_at(0)->current_origin().Serialize(),
263 GetOriginFromRenderer(root->child_at(0)));
alexmosbc7eafa2014-12-06 01:38:09264
nick1466c842015-11-25 20:08:06265 // Parent-initiated about:blank navigation should inherit the parent's a.com
266 // origin.
267 NavigateIframeToURL(contents, "1-1-id", about_blank);
268 EXPECT_EQ(about_blank, root->child_at(0)->current_url());
269 EXPECT_EQ(main_url.GetOrigin().spec(),
270 root->child_at(0)->current_origin().Serialize() + '/');
271 EXPECT_EQ(root->current_frame_host()->GetLastCommittedOrigin().Serialize(),
272 root->child_at(0)
273 ->current_frame_host()
274 ->GetLastCommittedOrigin()
275 .Serialize());
276 EXPECT_TRUE(
277 root->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
278 root->child_at(0)->current_frame_host()->GetLastCommittedOrigin()));
279 EXPECT_EQ(root->current_origin().Serialize(), GetOriginFromRenderer(root));
280 EXPECT_EQ(root->child_at(0)->current_origin().Serialize(),
281 GetOriginFromRenderer(root->child_at(0)));
alexmosbc7eafa2014-12-06 01:38:09282
283 GURL data_url("data:text/html,foo");
284 EXPECT_TRUE(NavigateToURL(shell(), data_url));
285
286 // Navigating to a data URL should set a unique origin. This is represented
287 // as "null" per RFC 6454.
nick1466c842015-11-25 20:08:06288 EXPECT_EQ("null", root->current_origin().Serialize());
289 EXPECT_TRUE(contents->GetMainFrame()->GetLastCommittedOrigin().unique());
290 EXPECT_EQ("null", GetOriginFromRenderer(root));
alexmosbc7eafa2014-12-06 01:38:09291
292 // Re-navigating to a normal URL should update the origin.
293 EXPECT_TRUE(NavigateToURL(shell(), main_url));
nick1466c842015-11-25 20:08:06294 EXPECT_EQ(main_url.GetOrigin().spec(),
295 root->current_origin().Serialize() + '/');
296 EXPECT_EQ(
297 main_url.GetOrigin().spec(),
298 contents->GetMainFrame()->GetLastCommittedOrigin().Serialize() + '/');
299 EXPECT_FALSE(contents->GetMainFrame()->GetLastCommittedOrigin().unique());
300 EXPECT_EQ(root->current_origin().Serialize(), GetOriginFromRenderer(root));
alexmosbc7eafa2014-12-06 01:38:09301}
302
nick9f34e2892016-01-12 21:01:07303// Tests a cross-origin navigation to a blob URL. The main frame initiates this
304// navigation on its grandchild. It should wind up in the main frame's process.
305IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, NavigateGrandchildToBlob) {
306 WebContents* contents = shell()->web_contents();
307 FrameTreeNode* root =
308 static_cast<WebContentsImpl*>(contents)->GetFrameTree()->root();
309
310 // First, snapshot the FrameTree for a normal A(B(A)) case where all frames
311 // are served over http. The blob test should result in the same structure.
312 EXPECT_TRUE(NavigateToURL(
313 shell(), embedded_test_server()->GetURL(
314 "a.com", "/cross_site_iframe_factory.html?a(b(a))")));
315 std::string reference_tree = FrameTreeVisualizer().DepictFrameTree(root);
316
317 GURL main_url(embedded_test_server()->GetURL(
318 "a.com", "/cross_site_iframe_factory.html?a(b(c))"));
319 EXPECT_TRUE(NavigateToURL(shell(), main_url));
320
321 // The root node will initiate the navigation; its grandchild node will be the
322 // target of the navigation.
323 FrameTreeNode* target = root->child_at(0)->child_at(0);
324
325 std::string blob_url_string;
creisb2d5f1f32016-11-07 23:25:05326 RenderFrameDeletedObserver deleted_observer(target->current_frame_host());
nick9f34e2892016-01-12 21:01:07327 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:54328 root,
nick9f34e2892016-01-12 21:01:07329 "function receiveMessage(event) {"
330 " document.body.appendChild(document.createTextNode(event.data));"
331 " domAutomationController.send(event.source.location.href);"
332 "}"
333 "window.addEventListener('message', receiveMessage, false);"
334 "var blob = new Blob(["
335 " '<html><body><div>This is blob content.</div><script>"
336 " window.parent.parent.postMessage(\"HI\", document.origin);"
337 " </script></body></html>'], {type: 'text/html'});"
338 "var blob_url = URL.createObjectURL(blob);"
339 "frames[0][0].location.href = blob_url;",
340 &blob_url_string));
creisb2d5f1f32016-11-07 23:25:05341 // Wait for the RenderFrame to go away, if this will be cross-process.
342 if (AreAllSitesIsolatedForTesting())
343 deleted_observer.WaitUntilDeleted();
nick9f34e2892016-01-12 21:01:07344 EXPECT_EQ(GURL(blob_url_string), target->current_url());
345 EXPECT_EQ(url::kBlobScheme, target->current_url().scheme());
346 EXPECT_FALSE(target->current_origin().unique());
347 EXPECT_EQ("a.com", target->current_origin().host());
348 EXPECT_EQ(url::kHttpScheme, target->current_origin().scheme());
349
350 std::string document_body;
351 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:54352 target,
nick9f34e2892016-01-12 21:01:07353 "domAutomationController.send(document.body.children[0].innerHTML);",
354 &document_body));
355 EXPECT_EQ("This is blob content.", document_body);
356 EXPECT_EQ(reference_tree, FrameTreeVisualizer().DepictFrameTree(root));
357}
358
359IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, NavigateChildToAboutBlank) {
360 GURL main_url(embedded_test_server()->GetURL(
361 "a.com", "/cross_site_iframe_factory.html?a(b(c))"));
362 EXPECT_TRUE(NavigateToURL(shell(), main_url));
363 WebContentsImpl* contents =
364 static_cast<WebContentsImpl*>(shell()->web_contents());
365
366 // The leaf node (c.com) will be navigated. Its parent node (b.com) will
367 // initiate the navigation.
368 FrameTreeNode* target =
369 contents->GetFrameTree()->root()->child_at(0)->child_at(0);
370 FrameTreeNode* initiator = target->parent();
371
372 // Give the target a name.
nickadef4a52016-06-09 18:45:54373 EXPECT_TRUE(ExecuteScript(target, "window.name = 'target';"));
nick9f34e2892016-01-12 21:01:07374
375 // Use window.open(about:blank), then poll the document for access.
376 std::string about_blank_origin;
377 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:54378 initiator,
nick9f34e2892016-01-12 21:01:07379 "var didNavigate = false;"
380 "var intervalID = setInterval(function() {"
381 " if (!didNavigate) {"
382 " didNavigate = true;"
383 " window.open('about:blank', 'target');"
384 " }"
385 " // Poll the document until it doesn't throw a SecurityError.\n"
386 " try {"
387 " frames[0].document.write('Hi from ' + document.domain);"
388 " } catch (e) { return; }"
389 " clearInterval(intervalID);"
390 " domAutomationController.send(frames[0].document.origin);"
391 "}, 16);",
392 &about_blank_origin));
393 EXPECT_EQ(GURL(url::kAboutBlankURL), target->current_url());
394 EXPECT_EQ(url::kAboutScheme, target->current_url().scheme());
395 EXPECT_FALSE(target->current_origin().unique());
396 EXPECT_EQ("b.com", target->current_origin().host());
397 EXPECT_EQ(url::kHttpScheme, target->current_origin().scheme());
398 EXPECT_EQ(target->current_origin().Serialize(), about_blank_origin);
399
400 std::string document_body;
401 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:54402 target, "domAutomationController.send(document.body.innerHTML);",
nick9f34e2892016-01-12 21:01:07403 &document_body));
404 EXPECT_EQ("Hi from b.com", document_body);
405}
406
407// Nested iframes, three origins: A(B(C)). Frame A navigates C to about:blank
408// (via window.open). This should wind up in A's origin per the spec. Test fails
409// because of http://crbug.com/564292
410IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest,
411 DISABLED_NavigateGrandchildToAboutBlank) {
412 GURL main_url(embedded_test_server()->GetURL(
413 "a.com", "/cross_site_iframe_factory.html?a(b(c))"));
414 EXPECT_TRUE(NavigateToURL(shell(), main_url));
415 WebContentsImpl* contents =
416 static_cast<WebContentsImpl*>(shell()->web_contents());
417
418 // The leaf node (c.com) will be navigated. Its grandparent node (a.com) will
419 // initiate the navigation.
420 FrameTreeNode* target =
421 contents->GetFrameTree()->root()->child_at(0)->child_at(0);
422 FrameTreeNode* initiator = target->parent()->parent();
423
424 // Give the target a name.
nickadef4a52016-06-09 18:45:54425 EXPECT_TRUE(ExecuteScript(target, "window.name = 'target';"));
nick9f34e2892016-01-12 21:01:07426
427 // Use window.open(about:blank), then poll the document for access.
428 std::string about_blank_origin;
429 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:54430 initiator,
nick9f34e2892016-01-12 21:01:07431 "var didNavigate = false;"
432 "var intervalID = setInterval(function() {"
433 " if (!didNavigate) {"
434 " didNavigate = true;"
435 " window.open('about:blank', 'target');"
436 " }"
437 " // May raise a SecurityError, that's expected.\n"
438 " frames[0][0].document.write('Hi from ' + document.domain);"
439 " clearInterval(intervalID);"
440 " domAutomationController.send(frames[0][0].document.origin);"
441 "}, 16);",
442 &about_blank_origin));
443 EXPECT_EQ(GURL(url::kAboutBlankURL), target->current_url());
444 EXPECT_EQ(url::kAboutScheme, target->current_url().scheme());
445 EXPECT_FALSE(target->current_origin().unique());
446 EXPECT_EQ("a.com", target->current_origin().host());
447 EXPECT_EQ(url::kHttpScheme, target->current_origin().scheme());
448 EXPECT_EQ(target->current_origin().Serialize(), about_blank_origin);
449
450 std::string document_body;
451 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:54452 target, "domAutomationController.send(document.body.innerHTML);",
nick9f34e2892016-01-12 21:01:07453 &document_body));
454 EXPECT_EQ("Hi from a.com", document_body);
455}
456
naskofaa01fb2016-04-30 01:04:17457// Ensures that iframe with srcdoc is always put in the same origin as its
458// parent frame.
459IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, ChildFrameWithSrcdoc) {
460 GURL main_url(embedded_test_server()->GetURL(
461 "a.com", "/cross_site_iframe_factory.html?a(b)"));
462 EXPECT_TRUE(NavigateToURL(shell(), main_url));
463 WebContentsImpl* contents =
464 static_cast<WebContentsImpl*>(shell()->web_contents());
465 FrameTreeNode* root = contents->GetFrameTree()->root();
466 EXPECT_EQ(1U, root->child_count());
467
468 FrameTreeNode* child = root->child_at(0);
469 std::string frame_origin;
470 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:54471 child, "domAutomationController.send(document.origin);", &frame_origin));
naskofaa01fb2016-04-30 01:04:17472 EXPECT_TRUE(
473 child->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
474 url::Origin(GURL(frame_origin))));
475 EXPECT_FALSE(
476 root->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
477 url::Origin(GURL(frame_origin))));
478
479 // Create a new iframe with srcdoc and add it to the main frame. It should
480 // be created in the same SiteInstance as the parent.
481 {
482 std::string script("var f = document.createElement('iframe');"
483 "f.srcdoc = 'some content';"
484 "document.body.appendChild(f)");
485 TestNavigationObserver observer(shell()->web_contents());
nickadef4a52016-06-09 18:45:54486 EXPECT_TRUE(ExecuteScript(root, script));
naskofaa01fb2016-04-30 01:04:17487 EXPECT_EQ(2U, root->child_count());
488 observer.Wait();
489
490 EXPECT_EQ(GURL(url::kAboutBlankURL), root->child_at(1)->current_url());
491 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:54492 root->child_at(1), "domAutomationController.send(document.origin);",
493 &frame_origin));
naskofaa01fb2016-04-30 01:04:17494 EXPECT_EQ(root->current_frame_host()->GetLastCommittedURL().GetOrigin(),
495 GURL(frame_origin));
496 EXPECT_NE(child->current_frame_host()->GetLastCommittedURL().GetOrigin(),
497 GURL(frame_origin));
498 }
499
500 // Set srcdoc on the existing cross-site frame. It should navigate the frame
501 // back to the origin of the parent.
502 {
503 std::string script("var f = document.getElementById('child-0');"
504 "f.srcdoc = 'some content';");
505 TestNavigationObserver observer(shell()->web_contents());
nickadef4a52016-06-09 18:45:54506 EXPECT_TRUE(ExecuteScript(root, script));
naskofaa01fb2016-04-30 01:04:17507 observer.Wait();
508
509 EXPECT_EQ(GURL(url::kAboutBlankURL), child->current_url());
510 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:54511 child, "domAutomationController.send(document.origin);",
512 &frame_origin));
naskofaa01fb2016-04-30 01:04:17513 EXPECT_EQ(root->current_frame_host()->GetLastCommittedURL().GetOrigin(),
514 GURL(frame_origin));
515 }
516}
517
alexmosf832a2f2015-01-27 22:44:03518// Ensure that sandbox flags are correctly set when child frames are created.
519IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, SandboxFlagsSetForChildFrames) {
520 GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
521 EXPECT_TRUE(NavigateToURL(shell(), main_url));
522
523 // It is safe to obtain the root frame tree node here, as it doesn't change.
524 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
525 ->GetFrameTree()->root();
526
527 // Verify that sandbox flags are set properly for all FrameTreeNodes.
528 // First frame is completely sandboxed; second frame uses "allow-scripts",
529 // which resets both SandboxFlags::Scripts and
530 // SandboxFlags::AutomaticFeatures bits per blink::parseSandboxPolicy(), and
531 // third frame has "allow-scripts allow-same-origin".
alexmos6e940102016-01-19 22:47:25532 EXPECT_EQ(blink::WebSandboxFlags::None, root->effective_sandbox_flags());
533 EXPECT_EQ(blink::WebSandboxFlags::All,
534 root->child_at(0)->effective_sandbox_flags());
535 EXPECT_EQ(blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
536 ~blink::WebSandboxFlags::AutomaticFeatures,
537 root->child_at(1)->effective_sandbox_flags());
538 EXPECT_EQ(blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
dcheng5f60abb2015-05-28 01:39:36539 ~blink::WebSandboxFlags::AutomaticFeatures &
alexmos6e940102016-01-19 22:47:25540 ~blink::WebSandboxFlags::Origin,
541 root->child_at(2)->effective_sandbox_flags());
alexmosf832a2f2015-01-27 22:44:03542
543 // Sandboxed frames should set a unique origin unless they have the
544 // "allow-same-origin" directive.
alexmos6e940102016-01-19 22:47:25545 EXPECT_EQ("null", root->child_at(0)->current_origin().Serialize());
546 EXPECT_EQ("null", root->child_at(1)->current_origin().Serialize());
547 EXPECT_EQ(main_url.GetOrigin().spec(),
548 root->child_at(2)->current_origin().Serialize() + "/");
alexmosf832a2f2015-01-27 22:44:03549
550 // Navigating to a different URL should not clear sandbox flags.
551 GURL frame_url(embedded_test_server()->GetURL("/title1.html"));
552 NavigateFrameToURL(root->child_at(0), frame_url);
alexmos6e940102016-01-19 22:47:25553 EXPECT_EQ(blink::WebSandboxFlags::All,
554 root->child_at(0)->effective_sandbox_flags());
alexmosf832a2f2015-01-27 22:44:03555}
556
alexmose201c7cd2015-06-10 17:14:21557// Ensure that a popup opened from a subframe sets its opener to the subframe's
558// FrameTreeNode, and that the opener is cleared if the subframe is destroyed.
559IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, SubframeOpenerSetForNewWindow) {
560 GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
561 EXPECT_TRUE(NavigateToURL(shell(), main_url));
562
563 // It is safe to obtain the root frame tree node here, as it doesn't change.
564 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
565 ->GetFrameTree()
566 ->root();
567
568 // Open a new window from a subframe.
569 ShellAddedObserver new_shell_observer;
570 GURL popup_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
nickadef4a52016-06-09 18:45:54571 EXPECT_TRUE(ExecuteScript(root->child_at(0),
alexmose201c7cd2015-06-10 17:14:21572 "window.open('" + popup_url.spec() + "');"));
573 Shell* new_shell = new_shell_observer.GetShell();
574 WebContents* new_contents = new_shell->web_contents();
575 WaitForLoadStop(new_contents);
576
577 // Check that the new window's opener points to the correct subframe on
578 // original window.
579 FrameTreeNode* popup_root =
580 static_cast<WebContentsImpl*>(new_contents)->GetFrameTree()->root();
581 EXPECT_EQ(root->child_at(0), popup_root->opener());
582
583 // Close the original window. This should clear the new window's opener.
584 shell()->Close();
585 EXPECT_EQ(nullptr, popup_root->opener());
586}
587
[email protected]82307f6b2014-08-07 03:30:12588class CrossProcessFrameTreeBrowserTest : public ContentBrowserTest {
589 public:
590 CrossProcessFrameTreeBrowserTest() {}
591
dchengc2282aa2014-10-21 12:07:58592 void SetUpCommandLine(base::CommandLine* command_line) override {
nickd30fd962015-07-27 21:51:08593 IsolateAllSitesForTesting(command_line);
[email protected]82307f6b2014-08-07 03:30:12594 }
595
alexmos478dcbb2014-12-10 21:24:46596 void SetUpOnMainThread() override {
597 host_resolver()->AddRule("*", "127.0.0.1");
alexmos478dcbb2014-12-10 21:24:46598 SetupCrossSiteRedirector(embedded_test_server());
martijn12d2dad2016-11-11 10:59:27599 ASSERT_TRUE(embedded_test_server()->Start());
alexmos478dcbb2014-12-10 21:24:46600 }
601
[email protected]82307f6b2014-08-07 03:30:12602 private:
603 DISALLOW_COPY_AND_ASSIGN(CrossProcessFrameTreeBrowserTest);
604};
605
606// Ensure that we can complete a cross-process subframe navigation.
[email protected]82307f6b2014-08-07 03:30:12607IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
nasko83fe5dc2015-07-01 16:34:19608 CreateCrossProcessSubframeProxies) {
alexmos478dcbb2014-12-10 21:24:46609 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
[email protected]82307f6b2014-08-07 03:30:12610 NavigateToURL(shell(), main_url);
611
612 // It is safe to obtain the root frame tree node here, as it doesn't change.
613 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
614 ->GetFrameTree()->root();
615
[email protected]14522ce42014-08-08 18:56:16616 // There should not be a proxy for the root's own SiteInstance.
617 SiteInstance* root_instance = root->current_frame_host()->GetSiteInstance();
618 EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(root_instance));
619
[email protected]82307f6b2014-08-07 03:30:12620 // Load same-site page into iframe.
alexmos478dcbb2014-12-10 21:24:46621 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
[email protected]82307f6b2014-08-07 03:30:12622 NavigateFrameToURL(root->child_at(0), http_url);
623
[email protected]82307f6b2014-08-07 03:30:12624 // Load cross-site page into iframe.
alexmos478dcbb2014-12-10 21:24:46625 GURL cross_site_url(
626 embedded_test_server()->GetURL("foo.com", "/title2.html"));
[email protected]82307f6b2014-08-07 03:30:12627 NavigateFrameToURL(root->child_at(0), cross_site_url);
628
629 // Ensure that we have created a new process for the subframe.
naskoe6edde32014-10-17 15:36:48630 ASSERT_EQ(2U, root->child_count());
[email protected]82307f6b2014-08-07 03:30:12631 FrameTreeNode* child = root->child_at(0);
[email protected]14522ce42014-08-08 18:56:16632 SiteInstance* child_instance = child->current_frame_host()->GetSiteInstance();
[email protected]82307f6b2014-08-07 03:30:12633 RenderViewHost* rvh = child->current_frame_host()->render_view_host();
634 RenderProcessHost* rph = child->current_frame_host()->GetProcess();
635
636 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
[email protected]14522ce42014-08-08 18:56:16637 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), child_instance);
[email protected]82307f6b2014-08-07 03:30:12638 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph);
639
640 // Ensure that the root node has a proxy for the child node's SiteInstance.
[email protected]14522ce42014-08-08 18:56:16641 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(child_instance));
[email protected]82307f6b2014-08-07 03:30:12642
643 // Also ensure that the child has a proxy for the root node's SiteInstance.
[email protected]14522ce42014-08-08 18:56:16644 EXPECT_TRUE(child->render_manager()->GetRenderFrameProxyHost(root_instance));
645
646 // The nodes should not have proxies for their own SiteInstance.
647 EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(root_instance));
648 EXPECT_FALSE(
649 child->render_manager()->GetRenderFrameProxyHost(child_instance));
creise42f2a52014-09-18 18:14:57650
651 // Ensure that the RenderViews and RenderFrames are all live.
652 EXPECT_TRUE(
653 root->current_frame_host()->render_view_host()->IsRenderViewLive());
654 EXPECT_TRUE(
655 child->current_frame_host()->render_view_host()->IsRenderViewLive());
656 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
657 EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
[email protected]82307f6b2014-08-07 03:30:12658}
659
alexmosbc7eafa2014-12-06 01:38:09660IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
661 OriginSetOnCrossProcessNavigations) {
alexmos478dcbb2014-12-10 21:24:46662 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
alexmosbc7eafa2014-12-06 01:38:09663 EXPECT_TRUE(NavigateToURL(shell(), main_url));
664
665 // It is safe to obtain the root frame tree node here, as it doesn't change.
666 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
667 ->GetFrameTree()->root();
668
creisabdd2bd62015-11-21 01:14:58669 EXPECT_EQ(root->current_origin().Serialize() + '/',
alexmosbc7eafa2014-12-06 01:38:09670 main_url.GetOrigin().spec());
671
672 // First frame is an about:blank frame. Check that its origin is correctly
673 // inherited from the parent.
creisabdd2bd62015-11-21 01:14:58674 EXPECT_EQ(root->child_at(0)->current_origin().Serialize() + '/',
675 main_url.GetOrigin().spec());
alexmosbc7eafa2014-12-06 01:38:09676
677 // Second frame loads a same-site page. Its origin should also be the same
678 // as the parent.
creisabdd2bd62015-11-21 01:14:58679 EXPECT_EQ(root->child_at(1)->current_origin().Serialize() + '/',
680 main_url.GetOrigin().spec());
alexmosbc7eafa2014-12-06 01:38:09681
alexmosbc7eafa2014-12-06 01:38:09682 // Load cross-site page into the first frame.
alexmos478dcbb2014-12-10 21:24:46683 GURL cross_site_url(
684 embedded_test_server()->GetURL("foo.com", "/title2.html"));
alexmosbc7eafa2014-12-06 01:38:09685 NavigateFrameToURL(root->child_at(0), cross_site_url);
686
creisabdd2bd62015-11-21 01:14:58687 EXPECT_EQ(root->child_at(0)->current_origin().Serialize() + '/',
688 cross_site_url.GetOrigin().spec());
alexmosbc7eafa2014-12-06 01:38:09689
690 // The root's origin shouldn't have changed.
creisabdd2bd62015-11-21 01:14:58691 EXPECT_EQ(root->current_origin().Serialize() + '/',
alexmosbc7eafa2014-12-06 01:38:09692 main_url.GetOrigin().spec());
693
694 GURL data_url("data:text/html,foo");
695 NavigateFrameToURL(root->child_at(1), data_url);
696
697 // Navigating to a data URL should set a unique origin. This is represented
698 // as "null" per RFC 6454.
creisabdd2bd62015-11-21 01:14:58699 EXPECT_EQ(root->child_at(1)->current_origin().Serialize(), "null");
alexmosbc7eafa2014-12-06 01:38:09700}
701
nickdb193a12016-09-09 23:09:23702// FrameTreeBrowserTest variant where we isolate http://*.is, Iceland's top
703// level domain. This is an analogue to --isolate-extensions that we use inside
704// of content_browsertests, where extensions don't exist. Iceland, like an
705// extension process, is a special place with magical powers; we want to protect
706// it from outsiders.
707class IsolateIcelandFrameTreeBrowserTest : public ContentBrowserTest {
708 public:
709 IsolateIcelandFrameTreeBrowserTest() {}
710
711 void SetUpCommandLine(base::CommandLine* command_line) override {
712 command_line->AppendSwitchASCII(switches::kIsolateSitesForTesting, "*.is");
713 }
714
715 void SetUpOnMainThread() override {
716 host_resolver()->AddRule("*", "127.0.0.1");
nickdb193a12016-09-09 23:09:23717 SetupCrossSiteRedirector(embedded_test_server());
martijn12d2dad2016-11-11 10:59:27718 ASSERT_TRUE(embedded_test_server()->Start());
nickdb193a12016-09-09 23:09:23719 }
720
721 private:
722 DISALLOW_COPY_AND_ASSIGN(IsolateIcelandFrameTreeBrowserTest);
723};
724
725// Regression test for https://crbug.com/644966
726IN_PROC_BROWSER_TEST_F(IsolateIcelandFrameTreeBrowserTest,
727 ProcessSwitchForIsolatedBlob) {
728 // blink suppresses navigations to blob URLs of origins different from the
729 // frame initiating the navigation. We disable those checks for this test, to
730 // test what happens in a compromise scenario.
731 base::CommandLine::ForCurrentProcess()->AppendSwitch(
732 switches::kDisableWebSecurity);
733
734 // Set up an iframe.
735 WebContents* contents = shell()->web_contents();
736 FrameTreeNode* root =
737 static_cast<WebContentsImpl*>(contents)->GetFrameTree()->root();
738 GURL main_url(embedded_test_server()->GetURL(
nick07fd7e12016-09-12 18:54:06739 "a.com", "/cross_site_iframe_factory.html?a(a)"));
nickdb193a12016-09-09 23:09:23740 EXPECT_TRUE(NavigateToURL(shell(), main_url));
741
742 // The navigation targets an invalid blob url; that's intentional to trigger
743 // an error response. The response should commit in a process dedicated to
744 // http://b.is.
745 std::string result;
746 EXPECT_TRUE(ExecuteScriptAndExtractString(
747 root,
748 "var iframe_element = document.getElementsByTagName('iframe')[0];"
749 "iframe_element.onload = () => {"
750 " domAutomationController.send('done');"
751 "};"
752 "iframe_element.src = 'blob:http://b.is:2932/';",
753 &result));
754 WaitForLoadStop(contents);
755
756 // Make sure we did a process transfer back to "b.is".
757 EXPECT_EQ(
758 " Site A ------------ proxies for B\n"
759 " +--Site B ------- proxies for A\n"
760 "Where A = http://a.com/\n"
761 " B = http://b.is/",
762 FrameTreeVisualizer().DepictFrameTree(root));
763}
764
[email protected]5f96f5a62014-01-10 00:05:11765} // namespace content