1 // Copyright (c) 2012 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.
5 #include "content/browser/site_per_process_browsertest.h"
7 #include "base/command_line.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "content/browser/frame_host/cross_process_frame_connector.h"
11 #include "content/browser/frame_host/frame_tree.h"
12 #include "content/browser/frame_host/navigator.h"
13 #include "content/browser/frame_host/render_frame_proxy_host.h"
14 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
15 #include "content/browser/renderer_host/render_view_host_impl.h"
16 #include "content/browser/web_contents/web_contents_impl.h"
17 #include "content/public/browser/notification_observer.h"
18 #include "content/public/browser/notification_service.h"
19 #include "content/public/browser/notification_types.h"
20 #include "content/public/common/content_switches.h"
21 #include "content/public/test/browser_test_utils.h"
22 #include "content/public/test/content_browser_test_utils.h"
23 #include "content/public/test/test_navigation_observer.h"
24 #include "content/public/test/test_utils.h"
25 #include "content/shell/browser/shell.h"
26 #include "content/test/content_browser_test_utils_internal.h"
27 #include "content/test/test_frame_navigation_observer.h"
28 #include "net/dns/mock_host_resolver.h"
29 #include "net/test/embedded_test_server/embedded_test_server.h"
33 class RedirectNotificationObserver
: public NotificationObserver
{
35 // Register to listen for notifications of the given type from either a
36 // specific source, or from all sources if |source| is
37 // NotificationService::AllSources().
38 RedirectNotificationObserver(int notification_type
,
39 const NotificationSource
& source
);
40 ~RedirectNotificationObserver() override
;
42 // Wait until the specified notification occurs. If the notification was
43 // emitted between the construction of this object and this call then it
44 // returns immediately.
47 // Returns NotificationService::AllSources() if we haven't observed a
49 const NotificationSource
& source() const {
53 const NotificationDetails
& details() const {
57 // NotificationObserver:
58 void Observe(int type
,
59 const NotificationSource
& source
,
60 const NotificationDetails
& details
) override
;
66 NotificationRegistrar registrar_
;
68 NotificationSource source_
;
69 NotificationDetails details_
;
70 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
72 DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver
);
75 RedirectNotificationObserver::RedirectNotificationObserver(
76 int notification_type
,
77 const NotificationSource
& source
)
80 source_(NotificationService::AllSources()) {
81 registrar_
.Add(this, notification_type
, source
);
84 RedirectNotificationObserver::~RedirectNotificationObserver() {}
86 void RedirectNotificationObserver::Wait() {
87 if (seen_
&& seen_twice_
)
91 message_loop_runner_
= new MessageLoopRunner
;
92 message_loop_runner_
->Run();
96 void RedirectNotificationObserver::Observe(
98 const NotificationSource
& source
,
99 const NotificationDetails
& details
) {
107 message_loop_runner_
->Quit();
111 // This observer keeps track of the number of created RenderFrameHosts. Tests
112 // can use this to ensure that a certain number of child frames has been
113 // created after navigating.
114 class RenderFrameHostCreatedObserver
: public WebContentsObserver
{
116 RenderFrameHostCreatedObserver(WebContents
* web_contents
,
117 int expected_frame_count
)
118 : WebContentsObserver(web_contents
),
119 expected_frame_count_(expected_frame_count
),
121 message_loop_runner_(new MessageLoopRunner
) {}
123 ~RenderFrameHostCreatedObserver() override
;
125 // Runs a nested message loop and blocks until the expected number of
126 // RenderFrameHosts is created.
130 // WebContentsObserver
131 void RenderFrameCreated(RenderFrameHost
* render_frame_host
) override
;
133 // The number of RenderFrameHosts to wait for.
134 int expected_frame_count_
;
136 // The number of RenderFrameHosts that have been created.
139 // The MessageLoopRunner used to spin the message loop.
140 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
142 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver
);
145 RenderFrameHostCreatedObserver::~RenderFrameHostCreatedObserver() {
148 void RenderFrameHostCreatedObserver::Wait() {
149 message_loop_runner_
->Run();
152 void RenderFrameHostCreatedObserver::RenderFrameCreated(
153 RenderFrameHost
* render_frame_host
) {
155 if (frames_created_
== expected_frame_count_
) {
156 message_loop_runner_
->Quit();
161 // SitePerProcessBrowserTest
164 SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
167 void SitePerProcessBrowserTest::StartFrameAtDataURL() {
168 std::string data_url_script
=
169 "var iframes = document.getElementById('test');iframes.src="
170 "'data:text/html,dataurl';";
171 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script
));
174 void SitePerProcessBrowserTest::SetUpCommandLine(
175 base::CommandLine
* command_line
) {
176 command_line
->AppendSwitch(switches::kSitePerProcess
);
179 void SitePerProcessBrowserTest::SetUpOnMainThread() {
180 host_resolver()->AddRule("*", "127.0.0.1");
181 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
182 SetupCrossSiteRedirector(embedded_test_server());
185 // Ensure that navigating subframes in --site-per-process mode works and the
186 // correct documents are committed.
187 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, CrossSiteIframe
) {
188 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
189 NavigateToURL(shell(), main_url
);
191 // It is safe to obtain the root frame tree node here, as it doesn't change.
192 FrameTreeNode
* root
=
193 static_cast<WebContentsImpl
*>(shell()->web_contents())->
194 GetFrameTree()->root();
196 TestNavigationObserver
observer(shell()->web_contents());
198 // Load same-site page into iframe.
199 FrameTreeNode
* child
= root
->child_at(0);
200 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
201 NavigateFrameToURL(child
, http_url
);
202 EXPECT_EQ(http_url
, observer
.last_navigation_url());
203 EXPECT_TRUE(observer
.last_navigation_succeeded());
205 // There should be only one RenderWidgetHost when there are no
206 // cross-process iframes.
207 std::set
<RenderWidgetHostView
*> views_set
=
208 static_cast<WebContentsImpl
*>(shell()->web_contents())
209 ->GetRenderWidgetHostViewsInTree();
210 EXPECT_EQ(1U, views_set
.size());
212 RenderFrameProxyHost
* proxy_to_parent
=
213 child
->render_manager()->GetRenderFrameProxyHost(
214 shell()->web_contents()->GetSiteInstance());
215 EXPECT_FALSE(proxy_to_parent
);
217 // Load cross-site page into iframe.
218 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
219 NavigateFrameToURL(root
->child_at(0), url
);
220 // Verify that the navigation succeeded and the expected URL was loaded.
221 EXPECT_TRUE(observer
.last_navigation_succeeded());
222 EXPECT_EQ(url
, observer
.last_navigation_url());
224 // Ensure that we have created a new process for the subframe.
225 ASSERT_EQ(2U, root
->child_count());
226 SiteInstance
* site_instance
= child
->current_frame_host()->GetSiteInstance();
227 RenderViewHost
* rvh
= child
->current_frame_host()->render_view_host();
228 RenderProcessHost
* rph
= child
->current_frame_host()->GetProcess();
229 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh
);
230 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance
);
231 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph
);
233 // There should be now two RenderWidgetHosts, one for each process
234 // rendering a frame.
235 std::set
<RenderWidgetHostView
*> views_set
=
236 static_cast<WebContentsImpl
*>(shell()->web_contents())
237 ->GetRenderWidgetHostViewsInTree();
238 EXPECT_EQ(2U, views_set
.size());
240 proxy_to_parent
= child
->render_manager()->GetProxyToParent();
241 EXPECT_TRUE(proxy_to_parent
);
242 EXPECT_TRUE(proxy_to_parent
->cross_process_frame_connector());
243 // The out-of-process iframe should have its own RenderWidgetHost,
244 // independent of any RenderViewHost.
247 proxy_to_parent
->cross_process_frame_connector()->get_view_for_testing());
248 EXPECT_TRUE(child
->current_frame_host()->GetRenderWidgetHost());
250 // Load another cross-site page into the same iframe.
251 url
= embedded_test_server()->GetURL("bar.com", "/title3.html");
252 NavigateFrameToURL(root
->child_at(0), url
);
253 EXPECT_TRUE(observer
.last_navigation_succeeded());
254 EXPECT_EQ(url
, observer
.last_navigation_url());
256 // Check again that a new process is created and is different from the
257 // top level one and the previous one.
258 ASSERT_EQ(2U, root
->child_count());
259 child
= root
->child_at(0);
260 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
261 child
->current_frame_host()->render_view_host());
262 EXPECT_NE(rvh
, child
->current_frame_host()->render_view_host());
263 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
264 child
->current_frame_host()->GetSiteInstance());
265 EXPECT_NE(site_instance
,
266 child
->current_frame_host()->GetSiteInstance());
267 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
268 child
->current_frame_host()->GetProcess());
269 EXPECT_NE(rph
, child
->current_frame_host()->GetProcess());
271 std::set
<RenderWidgetHostView
*> views_set
=
272 static_cast<WebContentsImpl
*>(shell()->web_contents())
273 ->GetRenderWidgetHostViewsInTree();
274 EXPECT_EQ(2U, views_set
.size());
276 EXPECT_EQ(proxy_to_parent
, child
->render_manager()->GetProxyToParent());
277 EXPECT_TRUE(proxy_to_parent
->cross_process_frame_connector());
279 child
->current_frame_host()->render_view_host()->GetView(),
280 proxy_to_parent
->cross_process_frame_connector()->get_view_for_testing());
281 EXPECT_TRUE(child
->current_frame_host()->GetRenderWidgetHost());
284 // Disabled for flaky crashing: crbug.com/446575
285 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
286 DISABLED_NavigateRemoteFrame
) {
287 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
288 NavigateToURL(shell(), main_url
);
290 // It is safe to obtain the root frame tree node here, as it doesn't change.
291 FrameTreeNode
* root
=
292 static_cast<WebContentsImpl
*>(shell()->web_contents())->
293 GetFrameTree()->root();
295 TestNavigationObserver
observer(shell()->web_contents());
297 // Load same-site page into iframe.
298 FrameTreeNode
* child
= root
->child_at(0);
299 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
300 NavigateFrameToURL(child
, http_url
);
301 EXPECT_EQ(http_url
, observer
.last_navigation_url());
302 EXPECT_TRUE(observer
.last_navigation_succeeded());
304 // Load cross-site page into iframe.
305 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
306 NavigateFrameToURL(root
->child_at(0), url
);
307 EXPECT_TRUE(observer
.last_navigation_succeeded());
308 EXPECT_EQ(url
, observer
.last_navigation_url());
310 // Ensure that we have created a new process for the subframe.
311 ASSERT_EQ(2U, root
->child_count());
312 SiteInstance
* site_instance
= child
->current_frame_host()->GetSiteInstance();
313 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance
);
315 // Emulate the main frame changing the src of the iframe such that it
316 // navigates cross-site.
317 url
= embedded_test_server()->GetURL("bar.com", "/title3.html");
318 NavigateIframeToURL(shell()->web_contents(), "test", url
);
319 EXPECT_TRUE(observer
.last_navigation_succeeded());
320 EXPECT_EQ(url
, observer
.last_navigation_url());
322 // Check again that a new process is created and is different from the
323 // top level one and the previous one.
324 ASSERT_EQ(2U, root
->child_count());
325 child
= root
->child_at(0);
326 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
327 child
->current_frame_host()->GetSiteInstance());
328 EXPECT_NE(site_instance
,
329 child
->current_frame_host()->GetSiteInstance());
331 // Navigate back to the parent's origin and ensure we return to the
333 NavigateFrameToURL(child
, http_url
);
334 EXPECT_EQ(http_url
, observer
.last_navigation_url());
335 EXPECT_TRUE(observer
.last_navigation_succeeded());
336 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
337 child
->current_frame_host()->GetSiteInstance());
340 // This test checks that killing a renderer process of a remote frame
341 // and then navigating some other frame to the same SiteInstance of the killed
342 // process works properly.
343 // This can be illustrated as follows,
344 // where 1/2/3 are FrameTreeNode-s and A/B are processes and B* is the killed
348 // / \ -> / \ -> Kill B -> / \ -> Navigate 3 to B -> / \ .
351 // Initially, node1.proxy_hosts_ = {B}
352 // After we kill B, we make sure B stays in node1.proxy_hosts_, then we navigate
353 // 3 to B and we expect that to complete normally.
354 // See http://crbug.com/432107.
356 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
357 // site B and stays in not rendered state.
358 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
359 NavigateRemoteFrameToKilledProcess
) {
360 GURL
main_url(embedded_test_server()->GetURL(
361 "/frame_tree/page_with_two_frames.html"));
362 NavigateToURL(shell(), main_url
);
364 // It is safe to obtain the root frame tree node here, as it doesn't change.
365 FrameTreeNode
* root
=
366 static_cast<WebContentsImpl
*>(shell()->web_contents())->
367 GetFrameTree()->root();
369 TestNavigationObserver
observer(shell()->web_contents());
370 ASSERT_EQ(2U, root
->child_count());
372 // Make sure node2 points to the correct cross-site page.
373 GURL site_b_url
= embedded_test_server()->GetURL("bar.com", "/title1.html");
374 FrameTreeNode
* node2
= root
->child_at(0);
375 EXPECT_EQ(site_b_url
, node2
->current_url());
377 // Kill that cross-site renderer.
378 RenderProcessHost
* child_process
=
379 node2
->current_frame_host()->GetProcess();
380 RenderProcessHostWatcher
crash_observer(
381 child_process
, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
382 child_process
->Shutdown(0, false);
383 crash_observer
.Wait();
385 // Now navigate the second iframe (node3) to the same site as the node2.
386 FrameTreeNode
* node3
= root
->child_at(1);
387 NavigateFrameToURL(node3
, site_b_url
);
388 EXPECT_TRUE(observer
.last_navigation_succeeded());
389 EXPECT_EQ(site_b_url
, observer
.last_navigation_url());
392 // This test is similar to
393 // SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess with
394 // addition that node2 also has a cross-origin frame to site C.
398 // 2 3 -> B A -> Kill B -> B* A -> Navigate 3 -> B* B
402 // Initially, node1.proxy_hosts_ = {B, C}
403 // After we kill B, we make sure B stays in node1.proxy_hosts_, but
404 // C gets cleared from node1.proxy_hosts_.
406 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
407 // site B and stays in not rendered state.
408 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
409 NavigateRemoteFrameToKilledProcessWithSubtree
) {
411 embedded_test_server()->GetURL(
412 "/frame_tree/page_with_two_frames_nested.html"));
413 NavigateToURL(shell(), main_url
);
415 // It is safe to obtain the root frame tree node here, as it doesn't change.
416 FrameTreeNode
* root
=
417 static_cast<WebContentsImpl
*>(shell()->web_contents())->
418 GetFrameTree()->root();
419 TestNavigationObserver
observer(shell()->web_contents());
421 ASSERT_EQ(2U, root
->child_count());
424 embedded_test_server()->GetURL(
425 "bar.com", "/frame_tree/page_with_one_frame.html"));
426 // We can't use a TestNavigationObserver to verify the URL here,
427 // since the frame has children that may have clobbered it in the observer.
428 EXPECT_EQ(site_b_url
, root
->child_at(0)->current_url());
430 // Ensure that a new process is created for node2.
431 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
432 root
->child_at(0)->current_frame_host()->GetSiteInstance());
433 // Ensure that a new process is *not* created for node3.
434 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
435 root
->child_at(1)->current_frame_host()->GetSiteInstance());
437 ASSERT_EQ(1U, root
->child_at(0)->child_count());
439 // Make sure node4 points to the correct cross-site page.
440 FrameTreeNode
* node4
= root
->child_at(0)->child_at(0);
441 GURL
site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
442 EXPECT_EQ(site_c_url
, node4
->current_url());
444 // |site_instance_c| is expected to go away once we kill |child_process_b|
445 // below, so create a local scope so we can extend the lifetime of
446 // |site_instance_c| with a refptr.
448 SiteInstance
* site_instance_b
=
449 root
->child_at(0)->current_frame_host()->GetSiteInstance();
450 // |site_c| will go away, so extend its lifetime with a refptr.
451 scoped_refptr
<SiteInstanceImpl
> site_instance_c
=
452 node4
->current_frame_host()->GetSiteInstance();
454 // Initially proxies for both B and C will be present in the root and node3.
455 EXPECT_TRUE(root
->render_manager()->GetRenderFrameProxyHost(
457 EXPECT_TRUE(root
->render_manager()->GetRenderFrameProxyHost(
458 site_instance_c
.get()));
459 FrameTreeNode
* node3
= root
->child_at(1);
460 EXPECT_TRUE(node3
->render_manager()->GetRenderFrameProxyHost(
462 EXPECT_TRUE(node3
->render_manager()->GetRenderFrameProxyHost(
463 site_instance_c
.get()));
465 // Kill that cross-site renderer/process B.
466 RenderProcessHost
* child_process_b
=
467 root
->child_at(0)->current_frame_host()->GetProcess();
468 RenderProcessHostWatcher
crash_observer(
469 child_process_b
, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
470 child_process_b
->Shutdown(0, false);
471 crash_observer
.Wait();
473 // Make sure proxy B stays around in root and node3.
474 EXPECT_TRUE(root
->render_manager()->GetRenderFrameProxyHost(
476 EXPECT_TRUE(node3
->render_manager()->GetRenderFrameProxyHost(
478 // Make sure proxy C goes away from root and node3.
479 EXPECT_FALSE(root
->render_manager()->GetRenderFrameProxyHost(
480 site_instance_c
.get()));
481 EXPECT_FALSE(node3
->render_manager()->GetRenderFrameProxyHost(
482 site_instance_c
.get()));
485 // Now navigate the second iframe (node3) to the same site as the node2.
486 FrameTreeNode
* node3
= root
->child_at(1);
487 GURL url
= embedded_test_server()->GetURL("bar.com", "/title1.html");
488 NavigateFrameToURL(node3
, url
);
489 EXPECT_TRUE(observer
.last_navigation_succeeded());
490 EXPECT_EQ(url
, observer
.last_navigation_url());
493 // In A-embed-B-embed-C scenario, verify that killing process B clears proxies
494 // of C from the tree.
498 // 2 3 -> B A -> Kill B -> B* A
502 // node1 is the root.
503 // Initially, both node1.proxy_hosts_ and node3.proxy_hosts_ contain C.
504 // After we kill B, make sure proxies for C are cleared.
505 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
506 KillingRendererClearsDescendantProxies
) {
508 embedded_test_server()->GetURL(
509 "/frame_tree/page_with_two_frames_nested.html"));
510 NavigateToURL(shell(), main_url
);
512 // It is safe to obtain the root frame tree node here, as it doesn't change.
513 FrameTreeNode
* root
=
514 static_cast<WebContentsImpl
*>(shell()->web_contents())->
515 GetFrameTree()->root();
516 TestNavigationObserver
observer(shell()->web_contents());
518 ASSERT_EQ(2U, root
->child_count());
521 embedded_test_server()->GetURL(
522 "bar.com", "/frame_tree/page_with_one_frame.html"));
523 // We can't use a TestNavigationObserver to verify the URL here,
524 // since the frame has children that may have clobbered it in the observer.
525 EXPECT_EQ(site_b_url
, root
->child_at(0)->current_url());
527 // Ensure that a new process is created for node2.
528 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
529 root
->child_at(0)->current_frame_host()->GetSiteInstance());
530 // Ensure that a new process is *not* created for node3.
531 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
532 root
->child_at(1)->current_frame_host()->GetSiteInstance());
534 ASSERT_EQ(1U, root
->child_at(0)->child_count());
536 // Make sure node4 points to the correct cross-site-page.
537 FrameTreeNode
* node4
= root
->child_at(0)->child_at(0);
538 GURL
site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
539 EXPECT_EQ(site_c_url
, node4
->current_url());
541 // |site_instance_c| is expected to go away once we kill |child_process_b|
542 // below, so create a local scope so we can extend the lifetime of
543 // |site_instance_c| with a refptr.
545 SiteInstance
* site_instance_b
=
546 root
->child_at(0)->current_frame_host()->GetSiteInstance();
547 scoped_refptr
<SiteInstanceImpl
> site_instance_c
=
548 node4
->current_frame_host()->GetSiteInstance();
550 // Initially proxies for both B and C will be present in the root.
551 EXPECT_TRUE(root
->render_manager()->GetRenderFrameProxyHost(
553 EXPECT_TRUE(root
->render_manager()->GetRenderFrameProxyHost(
554 site_instance_c
.get()));
557 RenderProcessHost
* child_process_b
=
558 root
->child_at(0)->current_frame_host()->GetProcess();
559 RenderProcessHostWatcher
crash_observer(
560 child_process_b
, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
561 child_process_b
->Shutdown(0, false);
562 crash_observer
.Wait();
564 // Make sure proxy C has gone from root.
565 EXPECT_FALSE(root
->render_manager()->GetRenderFrameProxyHost(
566 site_instance_c
.get()));
567 // Make sure proxy C has gone from node3 as well.
568 EXPECT_FALSE(root
->child_at(1)->render_manager()->GetRenderFrameProxyHost(
569 site_instance_c
.get()));
570 // Make sure proxy B stays around in root and node3.
571 EXPECT_TRUE(root
->render_manager()->GetRenderFrameProxyHost(
573 EXPECT_TRUE(root
->child_at(1)->render_manager()->GetRenderFrameProxyHost(
578 // Crash a subframe and ensures its children are cleared from the FrameTree.
579 // See http://crbug.com/338508.
580 // TODO(creis): Disabled for flakiness; see http://crbug.com/405582.
581 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, DISABLED_CrashSubframe
) {
582 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
583 NavigateToURL(shell(), main_url
);
585 StartFrameAtDataURL();
587 // These must stay in scope with replace_host.
588 GURL::Replacements replace_host
;
589 std::string
foo_com("foo.com");
591 // Load cross-site page into iframe.
592 EXPECT_TRUE(NavigateIframeToURL(
593 shell()->web_contents(), "test",
594 embedded_test_server()->GetURL("/cross-site/foo.com/title2.html")));
596 // Check the subframe process.
597 FrameTreeNode
* root
=
598 static_cast<WebContentsImpl
*>(shell()->web_contents())->
599 GetFrameTree()->root();
600 ASSERT_EQ(2U, root
->child_count());
601 FrameTreeNode
* child
= root
->child_at(0);
602 EXPECT_EQ(main_url
, root
->current_url());
603 EXPECT_EQ("foo.com", child
->current_url().host());
604 EXPECT_EQ("/title2.html", child
->current_url().path());
607 child
->current_frame_host()->render_view_host()->IsRenderViewLive());
608 EXPECT_TRUE(child
->current_frame_host()->IsRenderFrameLive());
610 // Crash the subframe process.
611 RenderProcessHost
* root_process
= root
->current_frame_host()->GetProcess();
612 RenderProcessHost
* child_process
= child
->current_frame_host()->GetProcess();
614 RenderProcessHostWatcher
crash_observer(
616 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
617 child_process
->Shutdown(0, false);
618 crash_observer
.Wait();
621 // Ensure that the child frame still exists but has been cleared.
622 EXPECT_EQ(2U, root
->child_count());
623 EXPECT_EQ(main_url
, root
->current_url());
624 EXPECT_EQ(GURL(), child
->current_url());
627 child
->current_frame_host()->render_view_host()->IsRenderViewLive());
628 EXPECT_FALSE(child
->current_frame_host()->IsRenderFrameLive());
629 EXPECT_FALSE(child
->current_frame_host()->render_frame_created_
);
631 // Now crash the top-level page to clear the child frame.
633 RenderProcessHostWatcher
crash_observer(
635 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
636 root_process
->Shutdown(0, false);
637 crash_observer
.Wait();
639 EXPECT_EQ(0U, root
->child_count());
640 EXPECT_EQ(GURL(), root
->current_url());
643 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
644 // security checks are back in place.
645 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
646 // on Android (http://crbug.com/187570).
647 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
648 DISABLED_CrossSiteIframeRedirectOnce
) {
649 ASSERT_TRUE(test_server()->Start());
650 net::SpawnedTestServer
https_server(
651 net::SpawnedTestServer::TYPE_HTTPS
,
652 net::SpawnedTestServer::kLocalhost
,
653 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
654 ASSERT_TRUE(https_server
.Start());
656 GURL
main_url(test_server()->GetURL("files/site_per_process_main.html"));
657 GURL
http_url(test_server()->GetURL("files/title1.html"));
658 GURL
https_url(https_server
.GetURL("files/title1.html"));
660 NavigateToURL(shell(), main_url
);
662 TestNavigationObserver
observer(shell()->web_contents());
664 // Load cross-site client-redirect page into Iframe.
665 // Should be blocked.
666 GURL
client_redirect_https_url(https_server
.GetURL(
667 "client-redirect?files/title1.html"));
668 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
669 client_redirect_https_url
));
670 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
671 EXPECT_EQ(observer
.last_navigation_url(), client_redirect_https_url
);
672 EXPECT_FALSE(observer
.last_navigation_succeeded());
676 // Load cross-site server-redirect page into Iframe,
677 // which redirects to same-site page.
678 GURL
server_redirect_http_url(https_server
.GetURL(
679 "server-redirect?" + http_url
.spec()));
680 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
681 server_redirect_http_url
));
682 EXPECT_EQ(observer
.last_navigation_url(), http_url
);
683 EXPECT_TRUE(observer
.last_navigation_succeeded());
687 // Load cross-site server-redirect page into Iframe,
688 // which redirects to cross-site page.
689 GURL
server_redirect_http_url(https_server
.GetURL(
690 "server-redirect?files/title1.html"));
691 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
692 server_redirect_http_url
));
693 // DidFailProvisionalLoad when navigating to https_url.
694 EXPECT_EQ(observer
.last_navigation_url(), https_url
);
695 EXPECT_FALSE(observer
.last_navigation_succeeded());
699 // Load same-site server-redirect page into Iframe,
700 // which redirects to cross-site page.
701 GURL
server_redirect_http_url(test_server()->GetURL(
702 "server-redirect?" + https_url
.spec()));
703 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
704 server_redirect_http_url
));
706 EXPECT_EQ(observer
.last_navigation_url(), https_url
);
707 EXPECT_FALSE(observer
.last_navigation_succeeded());
711 // Load same-site client-redirect page into Iframe,
712 // which redirects to cross-site page.
713 GURL
client_redirect_http_url(test_server()->GetURL(
714 "client-redirect?" + https_url
.spec()));
716 RedirectNotificationObserver
load_observer2(
717 NOTIFICATION_LOAD_STOP
,
718 Source
<NavigationController
>(
719 &shell()->web_contents()->GetController()));
721 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
722 client_redirect_http_url
));
724 // Same-site Client-Redirect Page should be loaded successfully.
725 EXPECT_EQ(observer
.last_navigation_url(), client_redirect_http_url
);
726 EXPECT_TRUE(observer
.last_navigation_succeeded());
728 // Redirecting to Cross-site Page should be blocked.
729 load_observer2
.Wait();
730 EXPECT_EQ(observer
.last_navigation_url(), https_url
);
731 EXPECT_FALSE(observer
.last_navigation_succeeded());
735 // Load same-site server-redirect page into Iframe,
736 // which redirects to same-site page.
737 GURL
server_redirect_http_url(test_server()->GetURL(
738 "server-redirect?files/title1.html"));
739 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
740 server_redirect_http_url
));
741 EXPECT_EQ(observer
.last_navigation_url(), http_url
);
742 EXPECT_TRUE(observer
.last_navigation_succeeded());
746 // Load same-site client-redirect page into Iframe,
747 // which redirects to same-site page.
748 GURL
client_redirect_http_url(test_server()->GetURL(
749 "client-redirect?" + http_url
.spec()));
750 RedirectNotificationObserver
load_observer2(
751 NOTIFICATION_LOAD_STOP
,
752 Source
<NavigationController
>(
753 &shell()->web_contents()->GetController()));
755 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
756 client_redirect_http_url
));
758 // Same-site Client-Redirect Page should be loaded successfully.
759 EXPECT_EQ(observer
.last_navigation_url(), client_redirect_http_url
);
760 EXPECT_TRUE(observer
.last_navigation_succeeded());
762 // Redirecting to Same-site Page should be loaded successfully.
763 load_observer2
.Wait();
764 EXPECT_EQ(observer
.last_navigation_url(), http_url
);
765 EXPECT_TRUE(observer
.last_navigation_succeeded());
769 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
770 // security checks are back in place.
771 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
772 // on Android (http://crbug.com/187570).
773 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
774 DISABLED_CrossSiteIframeRedirectTwice
) {
775 ASSERT_TRUE(test_server()->Start());
776 net::SpawnedTestServer
https_server(
777 net::SpawnedTestServer::TYPE_HTTPS
,
778 net::SpawnedTestServer::kLocalhost
,
779 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
780 ASSERT_TRUE(https_server
.Start());
782 GURL
main_url(test_server()->GetURL("files/site_per_process_main.html"));
783 GURL
http_url(test_server()->GetURL("files/title1.html"));
784 GURL
https_url(https_server
.GetURL("files/title1.html"));
786 NavigateToURL(shell(), main_url
);
788 TestNavigationObserver
observer(shell()->web_contents());
790 // Load client-redirect page pointing to a cross-site client-redirect page,
791 // which eventually redirects back to same-site page.
792 GURL
client_redirect_https_url(https_server
.GetURL(
793 "client-redirect?" + http_url
.spec()));
794 GURL
client_redirect_http_url(test_server()->GetURL(
795 "client-redirect?" + client_redirect_https_url
.spec()));
797 // We should wait until second client redirect get cancelled.
798 RedirectNotificationObserver
load_observer2(
799 NOTIFICATION_LOAD_STOP
,
800 Source
<NavigationController
>(
801 &shell()->web_contents()->GetController()));
803 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
804 client_redirect_http_url
));
806 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
807 load_observer2
.Wait();
808 EXPECT_EQ(observer
.last_navigation_url(), client_redirect_https_url
);
809 EXPECT_FALSE(observer
.last_navigation_succeeded());
813 // Load server-redirect page pointing to a cross-site server-redirect page,
814 // which eventually redirect back to same-site page.
815 GURL
server_redirect_https_url(https_server
.GetURL(
816 "server-redirect?" + http_url
.spec()));
817 GURL
server_redirect_http_url(test_server()->GetURL(
818 "server-redirect?" + server_redirect_https_url
.spec()));
819 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
820 server_redirect_http_url
));
821 EXPECT_EQ(observer
.last_navigation_url(), http_url
);
822 EXPECT_TRUE(observer
.last_navigation_succeeded());
826 // Load server-redirect page pointing to a cross-site server-redirect page,
827 // which eventually redirects back to cross-site page.
828 GURL
server_redirect_https_url(https_server
.GetURL(
829 "server-redirect?" + https_url
.spec()));
830 GURL
server_redirect_http_url(test_server()->GetURL(
831 "server-redirect?" + server_redirect_https_url
.spec()));
832 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
833 server_redirect_http_url
));
835 // DidFailProvisionalLoad when navigating to https_url.
836 EXPECT_EQ(observer
.last_navigation_url(), https_url
);
837 EXPECT_FALSE(observer
.last_navigation_succeeded());
841 // Load server-redirect page pointing to a cross-site client-redirect page,
842 // which eventually redirects back to same-site page.
843 GURL
client_redirect_http_url(https_server
.GetURL(
844 "client-redirect?" + http_url
.spec()));
845 GURL
server_redirect_http_url(test_server()->GetURL(
846 "server-redirect?" + client_redirect_http_url
.spec()));
847 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
848 server_redirect_http_url
));
850 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
851 EXPECT_EQ(observer
.last_navigation_url(), client_redirect_http_url
);
852 EXPECT_FALSE(observer
.last_navigation_succeeded());
856 // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
857 // created in the FrameTree skipping the subtree of the navigating frame.
859 // Disabled on Mac due to flakiness on ASAN. http://crbug.com/425248
860 // Disabled on Windows due to flakiness on Win 7 bot. http://crbug.com/444563
861 #if defined(OS_MACOSX) || defined(OS_WIN)
862 #define MAYBE_ProxyCreationSkipsSubtree DISABLED_ProxyCreationSkipsSubtree
864 #define MAYBE_ProxyCreationSkipsSubtree ProxyCreationSkipsSubtree
866 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
867 MAYBE_ProxyCreationSkipsSubtree
) {
868 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
869 NavigateToURL(shell(), main_url
);
871 // It is safe to obtain the root frame tree node here, as it doesn't change.
872 FrameTreeNode
* root
=
873 static_cast<WebContentsImpl
*>(shell()->web_contents())->
874 GetFrameTree()->root();
876 EXPECT_TRUE(root
->child_at(1) != NULL
);
877 EXPECT_EQ(2U, root
->child_at(1)->child_count());
880 // Load same-site page into iframe.
881 TestNavigationObserver
observer(shell()->web_contents());
882 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
883 NavigateFrameToURL(root
->child_at(0), http_url
);
884 EXPECT_EQ(http_url
, observer
.last_navigation_url());
885 EXPECT_TRUE(observer
.last_navigation_succeeded());
886 RenderFrameProxyHost
* proxy_to_parent
=
887 root
->child_at(0)->render_manager()->GetRenderFrameProxyHost(
888 shell()->web_contents()->GetSiteInstance());
889 EXPECT_FALSE(proxy_to_parent
);
892 // Create the cross-site URL to navigate to.
893 GURL cross_site_url
=
894 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html");
896 // Load cross-site page into the second iframe without waiting for the
897 // navigation to complete. Once LoadURLWithParams returns, we would expect
898 // proxies to have been created in the frame tree, but children of the
899 // navigating frame to still be present. The reason is that we don't run the
900 // message loop, so no IPCs that alter the frame tree can be processed.
901 FrameTreeNode
* child
= root
->child_at(1);
902 SiteInstance
* site
= NULL
;
904 TestNavigationObserver
observer(shell()->web_contents());
905 TestFrameNavigationObserver
navigation_observer(child
);
906 NavigationController::LoadURLParams
params(cross_site_url
);
907 params
.transition_type
= PageTransitionFromInt(ui::PAGE_TRANSITION_LINK
);
908 params
.frame_tree_node_id
= child
->frame_tree_node_id();
909 child
->navigator()->GetController()->LoadURLWithParams(params
);
910 EXPECT_TRUE(child
->render_manager()->pending_frame_host());
912 site
= child
->render_manager()->pending_frame_host()->GetSiteInstance();
913 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site
);
915 EXPECT_TRUE(root
->render_manager()->GetRenderFrameProxyHost(site
));
917 root
->child_at(0)->render_manager()->GetRenderFrameProxyHost(site
));
918 EXPECT_FALSE(child
->render_manager()->GetRenderFrameProxyHost(site
));
919 for (size_t i
= 0; i
< child
->child_count(); ++i
) {
921 child
->child_at(i
)->render_manager()->GetRenderFrameProxyHost(site
));
923 // Now that the verification is done, run the message loop and wait for the
924 // navigation to complete.
925 navigation_observer
.Wait();
926 EXPECT_FALSE(child
->render_manager()->pending_frame_host());
927 EXPECT_TRUE(observer
.last_navigation_succeeded());
928 EXPECT_EQ(cross_site_url
, observer
.last_navigation_url());
931 // Load another cross-site page into the same iframe.
932 cross_site_url
= embedded_test_server()->GetURL("bar.com", "/title2.html");
934 // Perform the same checks as the first cross-site navigation, since
935 // there have been issues in subsequent cross-site navigations. Also ensure
936 // that the SiteInstance has properly changed.
937 // TODO(nasko): Once we have proper cleanup of resources, add code to
938 // verify that the intermediate SiteInstance/RenderFrameHost have been
939 // properly cleaned up.
940 TestNavigationObserver
observer(shell()->web_contents());
941 TestFrameNavigationObserver
navigation_observer(child
);
942 NavigationController::LoadURLParams
params(cross_site_url
);
943 params
.transition_type
= PageTransitionFromInt(ui::PAGE_TRANSITION_LINK
);
944 params
.frame_tree_node_id
= child
->frame_tree_node_id();
945 child
->navigator()->GetController()->LoadURLWithParams(params
);
946 EXPECT_TRUE(child
->render_manager()->pending_frame_host() != NULL
);
948 SiteInstance
* site2
=
949 child
->render_manager()->pending_frame_host()->GetSiteInstance();
950 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2
);
951 EXPECT_NE(site
, site2
);
953 EXPECT_TRUE(root
->render_manager()->GetRenderFrameProxyHost(site2
));
955 root
->child_at(0)->render_manager()->GetRenderFrameProxyHost(site2
));
956 EXPECT_FALSE(child
->render_manager()->GetRenderFrameProxyHost(site2
));
957 for (size_t i
= 0; i
< child
->child_count(); ++i
) {
959 child
->child_at(i
)->render_manager()->GetRenderFrameProxyHost(site2
));
962 navigation_observer
.Wait();
963 EXPECT_TRUE(observer
.last_navigation_succeeded());
964 EXPECT_EQ(cross_site_url
, observer
.last_navigation_url());
965 EXPECT_EQ(0U, child
->child_count());
969 // Verify that origin replication works for an A-embed-B-embed-C hierarchy.
970 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, OriginReplication
) {
971 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
972 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
974 // It is safe to obtain the root frame tree node here, as it doesn't change.
975 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
979 TestNavigationObserver
observer(shell()->web_contents());
981 // Navigate the first subframe to a cross-site page with two subframes.
982 // NavigateFrameToURL can't be used here because it doesn't guarantee that
983 // FrameTreeNodes will have been created for child frames when it returns.
984 RenderFrameHostCreatedObserver
frame_observer(shell()->web_contents(), 4);
986 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
987 NavigationController::LoadURLParams
params(foo_url
);
988 params
.transition_type
= ui::PAGE_TRANSITION_LINK
;
989 params
.frame_tree_node_id
= root
->child_at(0)->frame_tree_node_id();
990 root
->child_at(0)->navigator()->GetController()->LoadURLWithParams(params
);
991 frame_observer
.Wait();
993 // We can't use a TestNavigationObserver to verify the URL here,
994 // since the frame has children that may have clobbered it in the observer.
995 EXPECT_EQ(foo_url
, root
->child_at(0)->current_url());
997 // Ensure that a new process is created for the subframe.
998 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
999 root
->child_at(0)->current_frame_host()->GetSiteInstance());
1001 // Load cross-site page into subframe's subframe.
1002 ASSERT_EQ(2U, root
->child_at(0)->child_count());
1003 GURL
bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1004 NavigateFrameToURL(root
->child_at(0)->child_at(0), bar_url
);
1005 EXPECT_TRUE(observer
.last_navigation_succeeded());
1006 EXPECT_EQ(bar_url
, observer
.last_navigation_url());
1008 // Check that a new process is created and is different from the top one and
1010 FrameTreeNode
* bottom_child
= root
->child_at(0)->child_at(0);
1011 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1012 bottom_child
->current_frame_host()->GetSiteInstance());
1013 EXPECT_NE(root
->child_at(0)->current_frame_host()->GetSiteInstance(),
1014 bottom_child
->current_frame_host()->GetSiteInstance());
1016 // Check that foo.com frame's location.ancestorOrigins contains the correct
1017 // origin for the parent. The origin should have been replicated as part of
1018 // the ViewMsg_New message that created the parent's RenderFrameProxy in
1019 // foo.com's process.
1020 int ancestor_origins_length
= 0;
1021 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1022 root
->child_at(0)->current_frame_host(),
1023 "window.domAutomationController.send(location.ancestorOrigins.length);",
1024 &ancestor_origins_length
));
1025 EXPECT_EQ(1, ancestor_origins_length
);
1027 EXPECT_TRUE(ExecuteScriptAndExtractString(
1028 root
->child_at(0)->current_frame_host(),
1029 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1031 EXPECT_EQ(result
+ "/", main_url
.GetOrigin().spec());
1033 // Check that bar.com frame's location.ancestorOrigins contains the correct
1034 // origin for its two ancestors. The topmost parent origin should be
1035 // replicated as part of ViewMsg_New, and the middle frame (foo.com's) origin
1036 // should be replicated as part of FrameMsg_NewFrameProxy sent for foo.com's
1037 // frame in bar.com's process.
1038 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1039 bottom_child
->current_frame_host(),
1040 "window.domAutomationController.send(location.ancestorOrigins.length);",
1041 &ancestor_origins_length
));
1042 EXPECT_EQ(2, ancestor_origins_length
);
1043 EXPECT_TRUE(ExecuteScriptAndExtractString(
1044 bottom_child
->current_frame_host(),
1045 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1047 EXPECT_EQ(result
+ "/", foo_url
.GetOrigin().spec());
1048 EXPECT_TRUE(ExecuteScriptAndExtractString(
1049 bottom_child
->current_frame_host(),
1050 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1052 EXPECT_EQ(result
+ "/", main_url
.GetOrigin().spec());
1055 // Check that iframe sandbox flags are replicated correctly.
1056 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, SandboxFlagsReplication
) {
1057 GURL
main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
1058 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1060 // It is safe to obtain the root frame tree node here, as it doesn't change.
1061 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1065 TestNavigationObserver
observer(shell()->web_contents());
1067 // Navigate the second (sandboxed) subframe to a cross-site page with a
1068 // subframe. Use RenderFrameHostCreatedObserver to guarantee that all
1069 // FrameTreeNodes are created for child frames.
1070 RenderFrameHostCreatedObserver
frame_observer(shell()->web_contents(), 4);
1072 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1073 NavigateFrameToURL(root
->child_at(1), foo_url
);
1074 frame_observer
.Wait();
1076 // We can't use a TestNavigationObserver to verify the URL here,
1077 // since the frame has children that may have clobbered it in the observer.
1078 EXPECT_EQ(foo_url
, root
->child_at(1)->current_url());
1080 // Load cross-site page into subframe's subframe.
1081 ASSERT_EQ(2U, root
->child_at(1)->child_count());
1082 GURL
bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1083 NavigateFrameToURL(root
->child_at(1)->child_at(0), bar_url
);
1084 EXPECT_TRUE(observer
.last_navigation_succeeded());
1085 EXPECT_EQ(bar_url
, observer
.last_navigation_url());
1087 // Opening a popup in the sandboxed foo.com iframe should fail.
1088 bool success
= false;
1090 ExecuteScriptAndExtractBool(root
->child_at(1)->current_frame_host(),
1091 "window.domAutomationController.send("
1092 "!window.open('data:text/html,dataurl'));",
1094 EXPECT_TRUE(success
);
1095 EXPECT_EQ(Shell::windows().size(), 1u);
1097 // Opening a popup in a frame whose parent is sandboxed should also fail.
1098 // Here, bar.com frame's sandboxed parent frame is a remote frame in
1099 // bar.com's process.
1101 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1102 root
->child_at(1)->child_at(0)->current_frame_host(),
1103 "window.domAutomationController.send("
1104 "!window.open('data:text/html,dataurl'));",
1106 EXPECT_TRUE(success
);
1107 EXPECT_EQ(Shell::windows().size(), 1u);
1109 // Same, but now try the case where bar.com frame's sandboxed parent is a
1110 // local frame in bar.com's process.
1112 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1113 root
->child_at(2)->child_at(0)->current_frame_host(),
1114 "window.domAutomationController.send("
1115 "!window.open('data:text/html,dataurl'));",
1117 EXPECT_TRUE(success
);
1118 EXPECT_EQ(Shell::windows().size(), 1u);
1120 // Check that foo.com frame's location.ancestorOrigins contains the correct
1121 // origin for the parent, which should be unaffected by sandboxing.
1122 int ancestor_origins_length
= 0;
1123 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1124 root
->child_at(1)->current_frame_host(),
1125 "window.domAutomationController.send(location.ancestorOrigins.length);",
1126 &ancestor_origins_length
));
1127 EXPECT_EQ(1, ancestor_origins_length
);
1129 EXPECT_TRUE(ExecuteScriptAndExtractString(
1130 root
->child_at(1)->current_frame_host(),
1131 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1133 EXPECT_EQ(result
+ "/", main_url
.GetOrigin().spec());
1135 // Now check location.ancestorOrigins for the bar.com frame. The middle frame
1136 // (foo.com's) origin should be unique, since that frame is sandboxed, and
1137 // the top frame should match |main_url|.
1138 FrameTreeNode
* bottom_child
= root
->child_at(1)->child_at(0);
1139 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1140 bottom_child
->current_frame_host(),
1141 "window.domAutomationController.send(location.ancestorOrigins.length);",
1142 &ancestor_origins_length
));
1143 EXPECT_EQ(2, ancestor_origins_length
);
1144 EXPECT_TRUE(ExecuteScriptAndExtractString(
1145 bottom_child
->current_frame_host(),
1146 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1148 EXPECT_EQ(result
, "null");
1149 EXPECT_TRUE(ExecuteScriptAndExtractString(
1150 bottom_child
->current_frame_host(),
1151 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1153 EXPECT_EQ(result
+ "/", main_url
.GetOrigin().spec());
1156 // Verify that a child frame can retrieve the name property set by its parent.
1157 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, WindowNameReplication
) {
1158 GURL
main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
1159 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1161 // It is safe to obtain the root frame tree node here, as it doesn't change.
1162 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1166 TestNavigationObserver
observer(shell()->web_contents());
1168 // Load cross-site page into iframe.
1170 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
1171 NavigateFrameToURL(root
->child_at(0), frame_url
);
1172 EXPECT_TRUE(observer
.last_navigation_succeeded());
1173 EXPECT_EQ(frame_url
, observer
.last_navigation_url());
1175 // Ensure that a new process is created for the subframe.
1176 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1177 root
->child_at(0)->current_frame_host()->GetSiteInstance());
1179 // Check that the window.name seen by the frame matches the name attribute
1180 // specified by its parent in the iframe tag.
1182 EXPECT_TRUE(ExecuteScriptAndExtractString(
1183 root
->child_at(0)->current_frame_host(),
1184 "window.domAutomationController.send(window.name);", &result
));
1185 EXPECT_EQ(result
, "3-1-name");
1188 // TODO(lfg): Merge the test below with NavigateRemoteFrame test.
1189 // TODO(lfg): Disabled because this triggers http://crbug.com/433012, and since
1190 // the renderer process crashes, it causes the title watcher to never return.
1191 // Alternatively, this could also be fixed if we could use NavigateIframeToURL
1192 // and classified the navigation as MANUAL_SUBFRAME (http://crbug.com/441863) or
1193 // if we waited for DidStopLoading (currently broken -- see comment in
1194 // NavigateIframeToURL).
1195 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
1196 DISABLED_NavigateRemoteToDataURL
) {
1197 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1198 NavigateToURL(shell(), main_url
);
1200 // It is safe to obtain the root frame tree node here, as it doesn't change.
1201 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1205 TestNavigationObserver
observer(shell()->web_contents());
1207 // Load cross-site page into iframe.
1208 GURL url
= embedded_test_server()->GetURL("foo.com", "/title1.html");
1209 NavigateFrameToURL(root
->child_at(0), url
);
1210 EXPECT_TRUE(observer
.last_navigation_succeeded());
1211 EXPECT_EQ(url
, observer
.last_navigation_url());
1213 // Ensure that we have created a new process for the subframe.
1214 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1215 root
->child_at(0)->current_frame_host()->GetSiteInstance());
1217 // Navigate iframe to a data URL. The navigation happens from a script in the
1218 // parent frame, so the data URL should be committed in the same SiteInstance
1219 // as the parent frame.
1220 GURL
data_url("data:text/html,dataurl");
1221 std::string script
= base::StringPrintf(
1222 "setTimeout(function() {"
1223 "var iframe = document.getElementById('test');"
1224 "iframe.onload = function() { document.title = 'LOADED'; };"
1225 "iframe.src=\"%s\";"
1227 data_url
.spec().c_str());
1228 base::string16
passed_string(base::UTF8ToUTF16("LOADED"));
1229 TitleWatcher
title_watcher(shell()->web_contents(), passed_string
);
1230 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script
));
1231 EXPECT_EQ(title_watcher
.WaitAndGetTitle(), passed_string
);
1232 EXPECT_TRUE(observer
.last_navigation_succeeded());
1233 EXPECT_EQ(data_url
, observer
.last_navigation_url());
1235 // Ensure that we have navigated using the top level process.
1236 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
1237 root
->child_at(0)->current_frame_host()->GetSiteInstance());
1240 // TODO(lfg): Merge the test below with NavigateRemoteFrame test.
1241 // Disabled due to the same reason as NavigateRemoteToDataURL.
1242 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
1243 DISABLED_NavigateRemoteToBlankURL
) {
1244 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1245 NavigateToURL(shell(), main_url
);
1247 // It is safe to obtain the root frame tree node here, as it doesn't change.
1248 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1252 TestNavigationObserver
observer(shell()->web_contents());
1254 // Load cross-site page into iframe.
1255 GURL url
= embedded_test_server()->GetURL("foo.com", "/title1.html");
1256 NavigateFrameToURL(root
->child_at(0), url
);
1257 EXPECT_TRUE(observer
.last_navigation_succeeded());
1258 EXPECT_EQ(url
, observer
.last_navigation_url());
1260 // Ensure that we have created a new process for the subframe.
1261 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1262 root
->child_at(0)->current_frame_host()->GetSiteInstance());
1264 // Navigate iframe to about:blank. The navigation happens from a script in the
1265 // parent frame, so it should be committed in the same SiteInstance as the
1267 GURL
about_blank_url("about:blank");
1268 std::string script
= base::StringPrintf(
1269 "setTimeout(function() {"
1270 "var iframe = document.getElementById('test');"
1271 "iframe.onload = function() { document.title = 'LOADED'; };"
1272 "iframe.src=\"%s\";"
1274 about_blank_url
.spec().c_str());
1275 base::string16
passed_string(base::UTF8ToUTF16("LOADED"));
1276 TitleWatcher
title_watcher(shell()->web_contents(), passed_string
);
1277 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script
));
1278 EXPECT_EQ(title_watcher
.WaitAndGetTitle(), passed_string
);
1279 EXPECT_TRUE(observer
.last_navigation_succeeded());
1280 EXPECT_EQ(about_blank_url
, observer
.last_navigation_url());
1282 // Ensure that we have navigated using the top level process.
1283 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
1284 root
->child_at(0)->current_frame_host()->GetSiteInstance());
1287 // Ensure that navigating subframes in --site-per-process mode properly fires
1288 // the DidStopLoading event on WebContentsObserver.
1289 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, CrossSiteDidStopLoading
) {
1290 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1291 NavigateToURL(shell(), main_url
);
1293 // It is safe to obtain the root frame tree node here, as it doesn't change.
1294 FrameTreeNode
* root
=
1295 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1296 GetFrameTree()->root();
1298 TestNavigationObserver
observer(shell()->web_contents());
1300 // Load same-site page into iframe.
1301 FrameTreeNode
* child
= root
->child_at(0);
1302 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
1303 NavigateFrameToURL(child
, http_url
);
1304 EXPECT_EQ(http_url
, observer
.last_navigation_url());
1305 EXPECT_TRUE(observer
.last_navigation_succeeded());
1307 // Load cross-site page into iframe.
1308 TestNavigationObserver
nav_observer(shell()->web_contents(), 1);
1309 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
1310 NavigationController::LoadURLParams
params(url
);
1311 params
.transition_type
= ui::PAGE_TRANSITION_LINK
;
1312 params
.frame_tree_node_id
= child
->frame_tree_node_id();
1313 child
->navigator()->GetController()->LoadURLWithParams(params
);
1314 nav_observer
.Wait();
1316 // Verify that the navigation succeeded and the expected URL was loaded.
1317 EXPECT_TRUE(observer
.last_navigation_succeeded());
1318 EXPECT_EQ(url
, observer
.last_navigation_url());
1321 // Ensure that the renderer does not crash when navigating a frame that has a
1322 // sibling RemoteFrame. See https://crbug.com/426953.
1323 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
1324 NavigateWithSiblingRemoteFrame
) {
1326 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1327 NavigateToURL(shell(), main_url
);
1329 // It is safe to obtain the root frame tree node here, as it doesn't change.
1330 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1333 TestNavigationObserver
observer(shell()->web_contents());
1335 // Make sure the first frame is out of process.
1336 ASSERT_EQ(2U, root
->child_count());
1337 FrameTreeNode
* node2
= root
->child_at(0);
1338 EXPECT_NE(root
->current_frame_host()->GetSiteInstance(),
1339 node2
->current_frame_host()->GetSiteInstance());
1341 // Make sure the second frame is in the parent's process.
1342 FrameTreeNode
* node3
= root
->child_at(1);
1343 EXPECT_EQ(root
->current_frame_host()->GetSiteInstance(),
1344 node3
->current_frame_host()->GetSiteInstance());
1346 // Navigate the second iframe (node3) to a URL in its own process.
1347 GURL title_url
= embedded_test_server()->GetURL("/title2.html");
1348 NavigateFrameToURL(node3
, title_url
);
1349 EXPECT_TRUE(observer
.last_navigation_succeeded());
1350 EXPECT_EQ(title_url
, observer
.last_navigation_url());
1351 EXPECT_EQ(root
->current_frame_host()->GetSiteInstance(),
1352 node3
->current_frame_host()->GetSiteInstance());
1353 EXPECT_TRUE(node3
->current_frame_host()->IsRenderFrameLive());
1356 // Verify that load events for iframe elements work when the child frame is
1357 // out-of-process. In such cases, the load event is forwarded from the child
1358 // frame to the parent frame via the browser process.
1359 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, LoadEventForwarding
) {
1360 // Load a page with a cross-site frame. The parent page has an onload
1361 // handler in the iframe element that appends "LOADED" to the document title.
1364 embedded_test_server()->GetURL("/frame_with_load_event.html"));
1365 base::string16
expected_title(base::UTF8ToUTF16("LOADED"));
1366 TitleWatcher
title_watcher(shell()->web_contents(), expected_title
);
1367 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1368 EXPECT_EQ(title_watcher
.WaitAndGetTitle(), expected_title
);
1371 // It is safe to obtain the root frame tree node here, as it doesn't change.
1372 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1376 // Load another cross-site page into the iframe and check that the load event
1379 GURL
foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
1380 base::string16
expected_title(base::UTF8ToUTF16("LOADEDLOADED"));
1381 TitleWatcher
title_watcher(shell()->web_contents(), expected_title
);
1382 TestNavigationObserver
observer(shell()->web_contents());
1383 NavigateFrameToURL(root
->child_at(0), foo_url
);
1384 EXPECT_TRUE(observer
.last_navigation_succeeded());
1385 EXPECT_EQ(foo_url
, observer
.last_navigation_url());
1386 EXPECT_EQ(title_watcher
.WaitAndGetTitle(), expected_title
);
1390 } // namespace content