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"
10 #include "base/command_line.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "content/browser/frame_host/cross_process_frame_connector.h"
14 #include "content/browser/frame_host/frame_tree.h"
15 #include "content/browser/frame_host/navigator.h"
16 #include "content/browser/frame_host/render_frame_proxy_host.h"
17 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
18 #include "content/browser/renderer_host/render_view_host_impl.h"
19 #include "content/browser/web_contents/web_contents_impl.h"
20 #include "content/common/frame_messages.h"
21 #include "content/public/browser/notification_observer.h"
22 #include "content/public/browser/notification_service.h"
23 #include "content/public/browser/notification_types.h"
24 #include "content/public/common/content_switches.h"
25 #include "content/public/test/browser_test_utils.h"
26 #include "content/public/test/content_browser_test_utils.h"
27 #include "content/public/test/test_navigation_observer.h"
28 #include "content/public/test/test_utils.h"
29 #include "content/shell/browser/shell.h"
30 #include "content/test/content_browser_test_utils_internal.h"
31 #include "content/test/test_frame_navigation_observer.h"
32 #include "ipc/ipc_security_test_util.h"
33 #include "net/dns/mock_host_resolver.h"
34 #include "net/test/embedded_test_server/embedded_test_server.h"
40 // Helper function to send a postMessage and wait for a reply message. The
41 // |post_message_script| is executed on the |sender_ftn| frame, and the sender
42 // frame is expected to post |reply_status| from the DOMAutomationController
43 // when it receives a reply.
44 void PostMessageAndWaitForReply(FrameTreeNode
* sender_ftn
,
45 const std::string
& post_message_script
,
46 const std::string
& reply_status
) {
48 EXPECT_TRUE(ExecuteScriptAndExtractBool(
49 sender_ftn
->current_frame_host(),
50 "window.domAutomationController.send(" + post_message_script
+ ");",
54 content::DOMMessageQueue msg_queue
;
56 while (msg_queue
.WaitForMessage(&status
)) {
57 if (status
== reply_status
)
62 } // anonymous namespace
64 class RedirectNotificationObserver
: public NotificationObserver
{
66 // Register to listen for notifications of the given type from either a
67 // specific source, or from all sources if |source| is
68 // NotificationService::AllSources().
69 RedirectNotificationObserver(int notification_type
,
70 const NotificationSource
& source
);
71 ~RedirectNotificationObserver() override
;
73 // Wait until the specified notification occurs. If the notification was
74 // emitted between the construction of this object and this call then it
75 // returns immediately.
78 // Returns NotificationService::AllSources() if we haven't observed a
80 const NotificationSource
& source() const {
84 const NotificationDetails
& details() const {
88 // NotificationObserver:
89 void Observe(int type
,
90 const NotificationSource
& source
,
91 const NotificationDetails
& details
) override
;
97 NotificationRegistrar registrar_
;
99 NotificationSource source_
;
100 NotificationDetails details_
;
101 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
103 DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver
);
106 RedirectNotificationObserver::RedirectNotificationObserver(
107 int notification_type
,
108 const NotificationSource
& source
)
111 source_(NotificationService::AllSources()) {
112 registrar_
.Add(this, notification_type
, source
);
115 RedirectNotificationObserver::~RedirectNotificationObserver() {}
117 void RedirectNotificationObserver::Wait() {
118 if (seen_
&& seen_twice_
)
122 message_loop_runner_
= new MessageLoopRunner
;
123 message_loop_runner_
->Run();
127 void RedirectNotificationObserver::Observe(
129 const NotificationSource
& source
,
130 const NotificationDetails
& details
) {
138 message_loop_runner_
->Quit();
142 // This observer keeps track of the number of created RenderFrameHosts. Tests
143 // can use this to ensure that a certain number of child frames has been
144 // created after navigating.
145 class RenderFrameHostCreatedObserver
: public WebContentsObserver
{
147 RenderFrameHostCreatedObserver(WebContents
* web_contents
,
148 int expected_frame_count
)
149 : WebContentsObserver(web_contents
),
150 expected_frame_count_(expected_frame_count
),
152 message_loop_runner_(new MessageLoopRunner
) {}
154 ~RenderFrameHostCreatedObserver() override
;
156 // Runs a nested message loop and blocks until the expected number of
157 // RenderFrameHosts is created.
161 // WebContentsObserver
162 void RenderFrameCreated(RenderFrameHost
* render_frame_host
) override
;
164 // The number of RenderFrameHosts to wait for.
165 int expected_frame_count_
;
167 // The number of RenderFrameHosts that have been created.
170 // The MessageLoopRunner used to spin the message loop.
171 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
173 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver
);
176 RenderFrameHostCreatedObserver::~RenderFrameHostCreatedObserver() {
179 void RenderFrameHostCreatedObserver::Wait() {
180 message_loop_runner_
->Run();
183 void RenderFrameHostCreatedObserver::RenderFrameCreated(
184 RenderFrameHost
* render_frame_host
) {
186 if (frames_created_
== expected_frame_count_
) {
187 message_loop_runner_
->Quit();
191 // A WebContentsDelegate that catches messages sent to the console.
192 class ConsoleObserverDelegate
: public WebContentsDelegate
{
194 ConsoleObserverDelegate(WebContents
* web_contents
, const std::string
& filter
)
195 : web_contents_(web_contents
),
198 message_loop_runner_(new MessageLoopRunner
) {}
200 ~ConsoleObserverDelegate() override
{}
202 bool AddMessageToConsole(WebContents
* source
,
204 const base::string16
& message
,
206 const base::string16
& source_id
) override
;
208 std::string
message() { return message_
; }
213 WebContents
* web_contents_
;
215 std::string message_
;
217 // The MessageLoopRunner used to spin the message loop.
218 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
220 DISALLOW_COPY_AND_ASSIGN(ConsoleObserverDelegate
);
223 void ConsoleObserverDelegate::Wait() {
224 message_loop_runner_
->Run();
227 bool ConsoleObserverDelegate::AddMessageToConsole(
230 const base::string16
& message
,
232 const base::string16
& source_id
) {
233 DCHECK(source
== web_contents_
);
235 std::string ascii_message
= base::UTF16ToASCII(message
);
236 if (MatchPattern(ascii_message
, filter_
)) {
237 message_
= ascii_message
;
238 message_loop_runner_
->Quit();
244 // SitePerProcessBrowserTest
247 SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
250 std::string
SitePerProcessBrowserTest::DepictFrameTree(FrameTreeNode
* node
) {
251 return visualizer_
.DepictFrameTree(node
);
254 void SitePerProcessBrowserTest::StartFrameAtDataURL() {
255 std::string data_url_script
=
256 "var iframes = document.getElementById('test');iframes.src="
257 "'data:text/html,dataurl';";
258 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script
));
261 void SitePerProcessBrowserTest::SetUpCommandLine(
262 base::CommandLine
* command_line
) {
263 command_line
->AppendSwitch(switches::kSitePerProcess
);
266 void SitePerProcessBrowserTest::SetUpOnMainThread() {
267 host_resolver()->AddRule("*", "127.0.0.1");
268 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
269 SetupCrossSiteRedirector(embedded_test_server());
272 // Ensure that navigating subframes in --site-per-process mode works and the
273 // correct documents are committed.
274 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, CrossSiteIframe
) {
275 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
276 NavigateToURL(shell(), main_url
);
278 // It is safe to obtain the root frame tree node here, as it doesn't change.
279 FrameTreeNode
* root
=
280 static_cast<WebContentsImpl
*>(shell()->web_contents())->
281 GetFrameTree()->root();
283 TestNavigationObserver
observer(shell()->web_contents());
285 // Load same-site page into iframe.
286 FrameTreeNode
* child
= root
->child_at(0);
287 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
288 NavigateFrameToURL(child
, http_url
);
289 EXPECT_EQ(http_url
, observer
.last_navigation_url());
290 EXPECT_TRUE(observer
.last_navigation_succeeded());
292 // There should be only one RenderWidgetHost when there are no
293 // cross-process iframes.
294 std::set
<RenderWidgetHostView
*> views_set
=
295 static_cast<WebContentsImpl
*>(shell()->web_contents())
296 ->GetRenderWidgetHostViewsInTree();
297 EXPECT_EQ(1U, views_set
.size());
307 "Where A = http://127.0.0.1/",
308 DepictFrameTree(root
));
310 // Load cross-site page into iframe.
311 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
312 NavigateFrameToURL(root
->child_at(0), url
);
313 // Verify that the navigation succeeded and the expected URL was loaded.
314 EXPECT_TRUE(observer
.last_navigation_succeeded());
315 EXPECT_EQ(url
, observer
.last_navigation_url());
317 // Ensure that we have created a new process for the subframe.
318 ASSERT_EQ(2U, root
->child_count());
319 SiteInstance
* site_instance
= child
->current_frame_host()->GetSiteInstance();
320 RenderViewHost
* rvh
= child
->current_frame_host()->render_view_host();
321 RenderProcessHost
* rph
= child
->current_frame_host()->GetProcess();
322 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh
);
323 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance
);
324 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph
);
326 // There should be now two RenderWidgetHosts, one for each process
327 // rendering a frame.
328 std::set
<RenderWidgetHostView
*> views_set
=
329 static_cast<WebContentsImpl
*>(shell()->web_contents())
330 ->GetRenderWidgetHostViewsInTree();
331 EXPECT_EQ(2U, views_set
.size());
333 RenderFrameProxyHost
* proxy_to_parent
=
334 child
->render_manager()->GetProxyToParent();
335 EXPECT_TRUE(proxy_to_parent
);
336 EXPECT_TRUE(proxy_to_parent
->cross_process_frame_connector());
337 // The out-of-process iframe should have its own RenderWidgetHost,
338 // independent of any RenderViewHost.
341 proxy_to_parent
->cross_process_frame_connector()->get_view_for_testing());
342 EXPECT_TRUE(child
->current_frame_host()->GetRenderWidgetHost());
345 " Site A ------------ proxies for B\n"
346 " |--Site B ------- proxies for A\n"
347 " +--Site A ------- proxies for B\n"
348 " |--Site A -- proxies for B\n"
349 " +--Site A -- proxies for B\n"
350 " +--Site A -- proxies for B\n"
351 "Where A = http://127.0.0.1/\n"
352 " B = http://foo.com/",
353 DepictFrameTree(root
));
355 // Load another cross-site page into the same iframe.
356 url
= embedded_test_server()->GetURL("bar.com", "/title3.html");
357 NavigateFrameToURL(root
->child_at(0), url
);
358 EXPECT_TRUE(observer
.last_navigation_succeeded());
359 EXPECT_EQ(url
, observer
.last_navigation_url());
361 // Check again that a new process is created and is different from the
362 // top level one and the previous one.
363 ASSERT_EQ(2U, root
->child_count());
364 child
= root
->child_at(0);
365 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
366 child
->current_frame_host()->render_view_host());
367 EXPECT_NE(rvh
, child
->current_frame_host()->render_view_host());
368 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
369 child
->current_frame_host()->GetSiteInstance());
370 EXPECT_NE(site_instance
,
371 child
->current_frame_host()->GetSiteInstance());
372 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
373 child
->current_frame_host()->GetProcess());
374 EXPECT_NE(rph
, child
->current_frame_host()->GetProcess());
376 std::set
<RenderWidgetHostView
*> views_set
=
377 static_cast<WebContentsImpl
*>(shell()->web_contents())
378 ->GetRenderWidgetHostViewsInTree();
379 EXPECT_EQ(2U, views_set
.size());
381 EXPECT_EQ(proxy_to_parent
, child
->render_manager()->GetProxyToParent());
382 EXPECT_TRUE(proxy_to_parent
->cross_process_frame_connector());
384 child
->current_frame_host()->render_view_host()->GetView(),
385 proxy_to_parent
->cross_process_frame_connector()->get_view_for_testing());
386 EXPECT_TRUE(child
->current_frame_host()->GetRenderWidgetHost());
389 " Site A ------------ proxies for C\n"
390 " |--Site C ------- proxies for A\n"
391 " +--Site A ------- proxies for C\n"
392 " |--Site A -- proxies for C\n"
393 " +--Site A -- proxies for C\n"
394 " +--Site A -- proxies for C\n"
395 "Where A = http://127.0.0.1/\n"
396 " C = http://bar.com/",
397 DepictFrameTree(root
));
400 // Tests OOPIF rendering by checking that the RWH of the iframe generates
401 // OnSwapCompositorFrame message.
402 #if defined(OS_ANDROID)
403 // http://crbug.com/471850
404 #define MAYBE_CompositorFrameSwapped DISABLED_CompositorFrameSwapped
406 #define MAYBE_CompositorFrameSwapped CompositorFrameSwapped
408 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
409 MAYBE_CompositorFrameSwapped
) {
411 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
412 NavigateToURL(shell(), main_url
);
414 // It is safe to obtain the root frame tree node here, as it doesn't change.
415 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
418 ASSERT_EQ(1U, root
->child_count());
420 FrameTreeNode
* child_node
= root
->child_at(0);
421 GURL
site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
422 EXPECT_EQ(site_url
, child_node
->current_url());
423 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
424 child_node
->current_frame_host()->GetSiteInstance());
425 RenderWidgetHostViewBase
* rwhv_base
= static_cast<RenderWidgetHostViewBase
*>(
426 child_node
->current_frame_host()->GetRenderWidgetHost()->GetView());
428 // Wait for OnSwapCompositorFrame message.
429 while (rwhv_base
->RendererFrameNumber() <= 0) {
430 // TODO(lazyboy): Find a better way to avoid sleeping like this. See
431 // http://crbug.com/405282 for details.
432 base::RunLoop run_loop
;
433 base::MessageLoop::current()->PostDelayedTask(
434 FROM_HERE
, run_loop
.QuitClosure(),
435 base::TimeDelta::FromMilliseconds(10));
440 // Ensure that OOPIFs are deleted after navigating to a new main frame.
441 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, CleanupCrossSiteIframe
) {
442 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
443 NavigateToURL(shell(), main_url
);
445 // It is safe to obtain the root frame tree node here, as it doesn't change.
446 FrameTreeNode
* root
=
447 static_cast<WebContentsImpl
*>(shell()->web_contents())->
448 GetFrameTree()->root();
450 TestNavigationObserver
observer(shell()->web_contents());
452 // Load a cross-site page into both iframes.
453 GURL foo_url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
454 NavigateFrameToURL(root
->child_at(0), foo_url
);
455 EXPECT_TRUE(observer
.last_navigation_succeeded());
456 EXPECT_EQ(foo_url
, observer
.last_navigation_url());
457 NavigateFrameToURL(root
->child_at(1), foo_url
);
458 EXPECT_TRUE(observer
.last_navigation_succeeded());
459 EXPECT_EQ(foo_url
, observer
.last_navigation_url());
461 // Ensure that we have created a new process for the subframes.
462 ASSERT_EQ(2U, root
->child_count());
463 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
464 root
->child_at(0)->current_frame_host()->GetSiteInstance());
465 EXPECT_EQ(root
->child_at(0)->current_frame_host()->GetSiteInstance(),
466 root
->child_at(1)->current_frame_host()->GetSiteInstance());
468 // Use Javascript in the parent to remove one of the frames and ensure that
469 // the subframe goes away.
470 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
471 "document.body.removeChild("
472 "document.querySelectorAll('iframe')[0])"));
473 ASSERT_EQ(1U, root
->child_count());
475 // Load a new same-site page in the top-level frame and ensure the other
476 // subframe goes away.
477 GURL
new_url(embedded_test_server()->GetURL("/title1.html"));
478 NavigateToURL(shell(), new_url
);
479 ASSERT_EQ(0U, root
->child_count());
482 // Ensure that root frames cannot be detached.
483 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, RestrictFrameDetach
) {
484 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
485 NavigateToURL(shell(), main_url
);
487 // It is safe to obtain the root frame tree node here, as it doesn't change.
488 FrameTreeNode
* root
=
489 static_cast<WebContentsImpl
*>(shell()->web_contents())->
490 GetFrameTree()->root();
492 TestNavigationObserver
observer(shell()->web_contents());
494 // Load cross-site pages into both iframes.
495 GURL foo_url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
496 NavigateFrameToURL(root
->child_at(0), foo_url
);
497 EXPECT_TRUE(observer
.last_navigation_succeeded());
498 EXPECT_EQ(foo_url
, observer
.last_navigation_url());
499 GURL bar_url
= embedded_test_server()->GetURL("bar.com", "/title2.html");
500 NavigateFrameToURL(root
->child_at(1), bar_url
);
501 EXPECT_TRUE(observer
.last_navigation_succeeded());
502 EXPECT_EQ(bar_url
, observer
.last_navigation_url());
504 // Ensure that we have created new processes for the subframes.
505 ASSERT_EQ(2U, root
->child_count());
506 FrameTreeNode
* foo_child
= root
->child_at(0);
507 SiteInstance
* foo_site_instance
=
508 foo_child
->current_frame_host()->GetSiteInstance();
509 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), foo_site_instance
);
510 FrameTreeNode
* bar_child
= root
->child_at(1);
511 SiteInstance
* bar_site_instance
=
512 bar_child
->current_frame_host()->GetSiteInstance();
513 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), bar_site_instance
);
516 " Site A ------------ proxies for B C\n"
517 " |--Site B ------- proxies for A C\n"
518 " +--Site C ------- proxies for A B\n"
519 "Where A = http://127.0.0.1/\n"
520 " B = http://foo.com/\n"
521 " C = http://bar.com/",
522 DepictFrameTree(root
));
524 // Simulate an attempt to detach the root frame from foo_site_instance. This
525 // should kill foo_site_instance's process.
526 RenderFrameProxyHost
* foo_mainframe_rfph
=
527 root
->render_manager()->GetRenderFrameProxyHost(foo_site_instance
);
528 content::RenderProcessHostWatcher
foo_terminated(
529 foo_mainframe_rfph
->GetProcess(),
530 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
531 FrameHostMsg_Detach
evil_msg2(foo_mainframe_rfph
->GetRoutingID());
532 IPC::IpcSecurityTestUtil::PwnMessageReceived(
533 foo_mainframe_rfph
->GetProcess()->GetChannel(), evil_msg2
);
534 foo_terminated
.Wait();
537 " Site A ------------ proxies for B C\n"
538 " |--Site B ------- proxies for A C\n"
539 " +--Site C ------- proxies for A B\n"
540 "Where A = http://127.0.0.1/\n"
541 " B = http://foo.com/ (no process)\n"
542 " C = http://bar.com/",
543 DepictFrameTree(root
));
546 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
547 NavigateRemoteFrame
) {
548 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
549 NavigateToURL(shell(), main_url
);
551 // It is safe to obtain the root frame tree node here, as it doesn't change.
552 FrameTreeNode
* root
=
553 static_cast<WebContentsImpl
*>(shell()->web_contents())->
554 GetFrameTree()->root();
556 TestNavigationObserver
observer(shell()->web_contents());
558 // Load same-site page into iframe.
559 FrameTreeNode
* child
= root
->child_at(0);
560 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
561 NavigateFrameToURL(child
, http_url
);
562 EXPECT_EQ(http_url
, observer
.last_navigation_url());
563 EXPECT_TRUE(observer
.last_navigation_succeeded());
565 // Load cross-site page into iframe.
566 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
567 NavigateFrameToURL(root
->child_at(0), url
);
568 EXPECT_TRUE(observer
.last_navigation_succeeded());
569 EXPECT_EQ(url
, observer
.last_navigation_url());
571 // Ensure that we have created a new process for the subframe.
572 ASSERT_EQ(2U, root
->child_count());
573 SiteInstance
* site_instance
= child
->current_frame_host()->GetSiteInstance();
574 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance
);
576 // Emulate the main frame changing the src of the iframe such that it
577 // navigates cross-site.
578 url
= embedded_test_server()->GetURL("bar.com", "/title3.html");
579 NavigateIframeToURL(shell()->web_contents(), "test", url
);
580 EXPECT_TRUE(observer
.last_navigation_succeeded());
581 EXPECT_EQ(url
, observer
.last_navigation_url());
583 // Check again that a new process is created and is different from the
584 // top level one and the previous one.
585 ASSERT_EQ(2U, root
->child_count());
586 child
= root
->child_at(0);
587 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
588 child
->current_frame_host()->GetSiteInstance());
589 EXPECT_NE(site_instance
,
590 child
->current_frame_host()->GetSiteInstance());
592 // Navigate back to the parent's origin and ensure we return to the
594 NavigateFrameToURL(child
, http_url
);
595 EXPECT_EQ(http_url
, observer
.last_navigation_url());
596 EXPECT_TRUE(observer
.last_navigation_succeeded());
597 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
598 child
->current_frame_host()->GetSiteInstance());
602 // http://crbug.com/465722
603 #define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
604 DISABLED_NavigateRemoteFrameToBlankAndDataURLs
606 #define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
607 NavigateRemoteFrameToBlankAndDataURLs
610 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
611 MAYBE_NavigateRemoteFrameToBlankAndDataURLs
) {
612 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
613 NavigateToURL(shell(), main_url
);
615 // It is safe to obtain the root frame tree node here, as it doesn't change.
616 FrameTreeNode
* root
=
617 static_cast<WebContentsImpl
*>(shell()->web_contents())->
618 GetFrameTree()->root();
620 TestNavigationObserver
observer(shell()->web_contents());
622 // Load same-site page into iframe.
623 FrameTreeNode
* child
= root
->child_at(0);
624 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
625 NavigateFrameToURL(child
, http_url
);
626 EXPECT_EQ(http_url
, observer
.last_navigation_url());
627 EXPECT_TRUE(observer
.last_navigation_succeeded());
629 // Load cross-site page into iframe.
630 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
631 NavigateFrameToURL(root
->child_at(0), url
);
632 EXPECT_TRUE(observer
.last_navigation_succeeded());
633 EXPECT_EQ(url
, observer
.last_navigation_url());
634 ASSERT_EQ(2U, root
->child_count());
635 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
636 root
->child_at(0)->current_frame_host()->GetSiteInstance());
638 // Navigate iframe to a data URL. The navigation happens from a script in the
639 // parent frame, so the data URL should be committed in the same SiteInstance
640 // as the parent frame.
641 GURL
data_url("data:text/html,dataurl");
642 NavigateIframeToURL(shell()->web_contents(), "test", data_url
);
643 EXPECT_TRUE(observer
.last_navigation_succeeded());
644 EXPECT_EQ(data_url
, observer
.last_navigation_url());
646 // Ensure that we have navigated using the top level process.
647 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
648 root
->child_at(0)->current_frame_host()->GetSiteInstance());
650 // Load cross-site page into iframe.
651 url
= embedded_test_server()->GetURL("bar.com", "/title2.html");
652 NavigateFrameToURL(root
->child_at(0), url
);
653 EXPECT_TRUE(observer
.last_navigation_succeeded());
654 EXPECT_EQ(url
, observer
.last_navigation_url());
655 ASSERT_EQ(2U, root
->child_count());
656 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
657 root
->child_at(0)->current_frame_host()->GetSiteInstance());
659 // Navigate iframe to about:blank. The navigation happens from a script in the
660 // parent frame, so it should be committed in the same SiteInstance as the
662 GURL
about_blank_url("about:blank");
663 NavigateIframeToURL(shell()->web_contents(), "test", about_blank_url
);
664 EXPECT_TRUE(observer
.last_navigation_succeeded());
665 EXPECT_EQ(about_blank_url
, observer
.last_navigation_url());
667 // Ensure that we have navigated using the top level process.
668 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
669 root
->child_at(0)->current_frame_host()->GetSiteInstance());
672 // This test checks that killing a renderer process of a remote frame
673 // and then navigating some other frame to the same SiteInstance of the killed
674 // process works properly.
675 // This can be illustrated as follows,
676 // where 1/2/3 are FrameTreeNode-s and A/B are processes and B* is the killed
680 // / \ -> / \ -> Kill B -> / \ -> Navigate 3 to B -> / \ .
683 // Initially, node1.proxy_hosts_ = {B}
684 // After we kill B, we make sure B stays in node1.proxy_hosts_, then we navigate
685 // 3 to B and we expect that to complete normally.
686 // See http://crbug.com/432107.
688 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
689 // site B and stays in not rendered state.
690 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
691 NavigateRemoteFrameToKilledProcess
) {
692 GURL
main_url(embedded_test_server()->GetURL(
693 "/frame_tree/page_with_two_frames.html"));
694 NavigateToURL(shell(), main_url
);
696 // It is safe to obtain the root frame tree node here, as it doesn't change.
697 FrameTreeNode
* root
=
698 static_cast<WebContentsImpl
*>(shell()->web_contents())->
699 GetFrameTree()->root();
701 TestNavigationObserver
observer(shell()->web_contents());
702 ASSERT_EQ(2U, root
->child_count());
704 // Make sure node2 points to the correct cross-site page.
705 GURL site_b_url
= embedded_test_server()->GetURL("bar.com", "/title1.html");
706 FrameTreeNode
* node2
= root
->child_at(0);
707 EXPECT_EQ(site_b_url
, node2
->current_url());
709 // Kill that cross-site renderer.
710 RenderProcessHost
* child_process
=
711 node2
->current_frame_host()->GetProcess();
712 RenderProcessHostWatcher
crash_observer(
713 child_process
, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
714 child_process
->Shutdown(0, false);
715 crash_observer
.Wait();
717 // Now navigate the second iframe (node3) to the same site as the node2.
718 FrameTreeNode
* node3
= root
->child_at(1);
719 NavigateFrameToURL(node3
, site_b_url
);
720 EXPECT_TRUE(observer
.last_navigation_succeeded());
721 EXPECT_EQ(site_b_url
, observer
.last_navigation_url());
724 // This test is similar to
725 // SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess with
726 // addition that node2 also has a cross-origin frame to site C.
730 // 2 3 -> B A -> Kill B -> B* A -> Navigate 3 -> B* B
734 // Initially, node1.proxy_hosts_ = {B, C}
735 // After we kill B, we make sure B stays in node1.proxy_hosts_, but
736 // C gets cleared from node1.proxy_hosts_.
738 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
739 // site B and stays in not rendered state.
740 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
741 NavigateRemoteFrameToKilledProcessWithSubtree
) {
742 GURL
main_url(embedded_test_server()->GetURL(
743 "a.com", "/frame_tree/page_with_two_frames_nested.html"));
744 NavigateToURL(shell(), main_url
);
746 // It is safe to obtain the root frame tree node here, as it doesn't change.
747 FrameTreeNode
* root
=
748 static_cast<WebContentsImpl
*>(shell()->web_contents())->
749 GetFrameTree()->root();
750 TestNavigationObserver
observer(shell()->web_contents());
752 ASSERT_EQ(2U, root
->child_count());
755 embedded_test_server()->GetURL(
756 "bar.com", "/frame_tree/page_with_one_frame.html"));
757 // We can't use a TestNavigationObserver to verify the URL here,
758 // since the frame has children that may have clobbered it in the observer.
759 EXPECT_EQ(site_b_url
, root
->child_at(0)->current_url());
761 // Ensure that a new process is created for node2.
762 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
763 root
->child_at(0)->current_frame_host()->GetSiteInstance());
764 // Ensure that a new process is *not* created for node3.
765 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
766 root
->child_at(1)->current_frame_host()->GetSiteInstance());
768 ASSERT_EQ(1U, root
->child_at(0)->child_count());
770 // Make sure node4 points to the correct cross-site page.
771 FrameTreeNode
* node4
= root
->child_at(0)->child_at(0);
772 GURL
site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
773 EXPECT_EQ(site_c_url
, node4
->current_url());
775 // |site_instance_c| is expected to go away once we kill |child_process_b|
776 // below, so create a local scope so we can extend the lifetime of
777 // |site_instance_c| with a refptr.
779 // Initially each frame has proxies for the other sites.
781 " Site A ------------ proxies for B C\n"
782 " |--Site B ------- proxies for A C\n"
783 " | +--Site C -- proxies for A B\n"
784 " +--Site A ------- proxies for B C\n"
785 "Where A = http://a.com/\n"
786 " B = http://bar.com/\n"
787 " C = http://baz.com/",
788 DepictFrameTree(root
));
790 // Kill the render process for Site B.
791 RenderProcessHost
* child_process_b
=
792 root
->child_at(0)->current_frame_host()->GetProcess();
793 RenderProcessHostWatcher
crash_observer(
794 child_process_b
, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
795 child_process_b
->Shutdown(0, false);
796 crash_observer
.Wait();
798 // The Site C frame (a child of the crashed Site B frame) should go away,
799 // and there should be no remaining proxies for site C anywhere.
801 " Site A ------------ proxies for B\n"
802 " |--Site B ------- proxies for A\n"
803 " +--Site A ------- proxies for B\n"
804 "Where A = http://a.com/\n"
805 " B = http://bar.com/ (no process)",
806 DepictFrameTree(root
));
809 // Now navigate the second iframe (node3) to Site B also.
810 FrameTreeNode
* node3
= root
->child_at(1);
811 GURL url
= embedded_test_server()->GetURL("bar.com", "/title1.html");
812 NavigateFrameToURL(node3
, url
);
813 EXPECT_TRUE(observer
.last_navigation_succeeded());
814 EXPECT_EQ(url
, observer
.last_navigation_url());
817 " Site A ------------ proxies for B\n"
818 " |--Site B ------- proxies for A\n"
819 " +--Site B ------- proxies for A\n"
820 "Where A = http://a.com/\n"
821 " B = http://bar.com/",
822 DepictFrameTree(root
));
825 // Verify that killing a cross-site frame's process B and then navigating a
826 // frame to B correctly recreates all proxies in B.
829 // / | \ / | \ / | \ / | \ .
830 // 2 3 4 -> B A A -> Kill B -> B* A A -> B* B A
832 // After the last step, the test sends a postMessage from node 3 to node 4,
833 // verifying that a proxy for node 4 has been recreated in process B. This
834 // verifies the fix for https://crbug.com/478892.
835 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
836 NavigatingToKilledProcessRestoresAllProxies
) {
837 // Navigate to a page with three frames: one cross-site and two same-site.
838 GURL
main_url(embedded_test_server()->GetURL(
839 "a.com", "/frame_tree/page_with_three_frames.html"));
840 NavigateToURL(shell(), main_url
);
842 // It is safe to obtain the root frame tree node here, as it doesn't change.
843 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
846 TestNavigationObserver
observer(shell()->web_contents());
849 " Site A ------------ proxies for B\n"
850 " |--Site B ------- proxies for A\n"
851 " |--Site A ------- proxies for B\n"
852 " +--Site A ------- proxies for B\n"
853 "Where A = http://a.com/\n"
854 " B = http://b.com/",
855 DepictFrameTree(root
));
857 // Kill the first subframe's b.com renderer.
858 RenderProcessHost
* child_process
=
859 root
->child_at(0)->current_frame_host()->GetProcess();
860 RenderProcessHostWatcher
crash_observer(
861 child_process
, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
862 child_process
->Shutdown(0, false);
863 crash_observer
.Wait();
865 // Navigate the second subframe to b.com to recreate the b.com process.
866 GURL b_url
= embedded_test_server()->GetURL("b.com", "/post_message.html");
867 NavigateFrameToURL(root
->child_at(1), b_url
);
868 // TODO(alexmos): This can be removed once TestFrameNavigationObserver is
869 // fixed to use DidFinishLoad.
871 WaitForRenderFrameReady(root
->child_at(1)->current_frame_host()));
872 EXPECT_TRUE(observer
.last_navigation_succeeded());
873 EXPECT_EQ(b_url
, observer
.last_navigation_url());
874 EXPECT_TRUE(root
->child_at(1)->current_frame_host()->IsRenderFrameLive());
877 " Site A ------------ proxies for B\n"
878 " |--Site B ------- proxies for A\n"
879 " |--Site B ------- proxies for A\n"
880 " +--Site A ------- proxies for B\n"
881 "Where A = http://a.com/\n"
882 " B = http://b.com/",
883 DepictFrameTree(root
));
885 // Check that third subframe's proxy is available in the b.com process by
886 // sending it a postMessage from second subframe, and waiting for a reply.
887 PostMessageAndWaitForReply(root
->child_at(1),
888 "postToSibling('subframe-msg','frame3')",
892 // In A-embed-B-embed-C scenario, verify that killing process B clears proxies
893 // of C from the tree.
897 // 2 3 -> B A -> Kill B -> B* A
901 // node1 is the root.
902 // Initially, both node1.proxy_hosts_ and node3.proxy_hosts_ contain C.
903 // After we kill B, make sure proxies for C are cleared.
904 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
905 KillingRendererClearsDescendantProxies
) {
906 GURL
main_url(embedded_test_server()->GetURL(
907 "a.com", "/frame_tree/page_with_two_frames_nested.html"));
908 NavigateToURL(shell(), main_url
);
910 // It is safe to obtain the root frame tree node here, as it doesn't change.
911 FrameTreeNode
* root
=
912 static_cast<WebContentsImpl
*>(shell()->web_contents())->
913 GetFrameTree()->root();
914 TestNavigationObserver
observer(shell()->web_contents());
916 ASSERT_EQ(2U, root
->child_count());
919 embedded_test_server()->GetURL(
920 "bar.com", "/frame_tree/page_with_one_frame.html"));
921 // We can't use a TestNavigationObserver to verify the URL here,
922 // since the frame has children that may have clobbered it in the observer.
923 EXPECT_EQ(site_b_url
, root
->child_at(0)->current_url());
925 // Ensure that a new process is created for node2.
926 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
927 root
->child_at(0)->current_frame_host()->GetSiteInstance());
928 // Ensure that a new process is *not* created for node3.
929 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
930 root
->child_at(1)->current_frame_host()->GetSiteInstance());
932 ASSERT_EQ(1U, root
->child_at(0)->child_count());
934 // Make sure node4 points to the correct cross-site-page.
935 FrameTreeNode
* node4
= root
->child_at(0)->child_at(0);
936 GURL
site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
937 EXPECT_EQ(site_c_url
, node4
->current_url());
939 // |site_instance_c| is expected to go away once we kill |child_process_b|
940 // below; refcount it to extend the lifetime.
941 scoped_refptr
<SiteInstanceImpl
> site_instance_c
=
942 node4
->current_frame_host()->GetSiteInstance();
944 // Initially proxies for both B and C will be present in the root.
946 " Site A ------------ proxies for B C\n"
947 " |--Site B ------- proxies for A C\n"
948 " | +--Site C -- proxies for A B\n"
949 " +--Site A ------- proxies for B C\n"
950 "Where A = http://a.com/\n"
951 " B = http://bar.com/\n"
952 " C = http://baz.com/",
953 DepictFrameTree(root
));
955 RenderProcessHost
* child_process_b
=
956 root
->child_at(0)->current_frame_host()->GetProcess();
957 RenderProcessHostWatcher
crash_observer(
958 child_process_b
, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
959 child_process_b
->Shutdown(0, false);
960 crash_observer
.Wait();
962 // Make sure proxy C has gone from root.
963 // Make sure proxy C has gone from node3 as well.
964 // Make sure proxy B stays around in root and node3.
966 " Site A ------------ proxies for B\n"
967 " |--Site B ------- proxies for A\n"
968 " +--Site A ------- proxies for B\n"
969 "Where A = http://a.com/\n"
970 " B = http://bar.com/ (no process)",
971 DepictFrameTree(root
));
973 EXPECT_TRUE(site_instance_c
->HasOneRef());
976 // Crash a subframe and ensures its children are cleared from the FrameTree.
977 // See http://crbug.com/338508.
978 // TODO(creis): Disabled for flakiness; see http://crbug.com/405582.
979 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, DISABLED_CrashSubframe
) {
980 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
981 NavigateToURL(shell(), main_url
);
983 StartFrameAtDataURL();
985 // These must stay in scope with replace_host.
986 GURL::Replacements replace_host
;
987 std::string
foo_com("foo.com");
989 // Load cross-site page into iframe.
990 EXPECT_TRUE(NavigateIframeToURL(
991 shell()->web_contents(), "test",
992 embedded_test_server()->GetURL("/cross-site/foo.com/title2.html")));
994 // Check the subframe process.
995 FrameTreeNode
* root
=
996 static_cast<WebContentsImpl
*>(shell()->web_contents())->
997 GetFrameTree()->root();
998 ASSERT_EQ(2U, root
->child_count());
999 FrameTreeNode
* child
= root
->child_at(0);
1000 EXPECT_EQ(main_url
, root
->current_url());
1001 EXPECT_EQ("foo.com", child
->current_url().host());
1002 EXPECT_EQ("/title2.html", child
->current_url().path());
1005 child
->current_frame_host()->render_view_host()->IsRenderViewLive());
1006 EXPECT_TRUE(child
->current_frame_host()->IsRenderFrameLive());
1008 // Crash the subframe process.
1009 RenderProcessHost
* root_process
= root
->current_frame_host()->GetProcess();
1010 RenderProcessHost
* child_process
= child
->current_frame_host()->GetProcess();
1012 RenderProcessHostWatcher
crash_observer(
1014 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1015 child_process
->Shutdown(0, false);
1016 crash_observer
.Wait();
1019 // Ensure that the child frame still exists but has been cleared.
1020 EXPECT_EQ(2U, root
->child_count());
1021 EXPECT_EQ(main_url
, root
->current_url());
1022 EXPECT_EQ(GURL(), child
->current_url());
1025 child
->current_frame_host()->render_view_host()->IsRenderViewLive());
1026 EXPECT_FALSE(child
->current_frame_host()->IsRenderFrameLive());
1027 EXPECT_FALSE(child
->current_frame_host()->render_frame_created_
);
1029 // Now crash the top-level page to clear the child frame.
1031 RenderProcessHostWatcher
crash_observer(
1033 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1034 root_process
->Shutdown(0, false);
1035 crash_observer
.Wait();
1037 EXPECT_EQ(0U, root
->child_count());
1038 EXPECT_EQ(GURL(), root
->current_url());
1041 // When a new subframe is added, related SiteInstances that can reach the
1042 // subframe should create proxies for it (https://crbug.com/423587). This test
1043 // checks that if A embeds B and later adds a new subframe A2, A2 gets a proxy
1045 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, CreateProxiesForNewFrames
) {
1046 GURL
main_url(embedded_test_server()->GetURL(
1047 "b.com", "/frame_tree/page_with_one_frame.html"));
1048 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1050 // It is safe to obtain the root frame tree node here, as it doesn't change.
1051 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1054 ASSERT_EQ(1U, root
->child_count());
1056 // Make sure the frame starts out at the correct cross-site URL.
1057 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
1058 root
->child_at(0)->current_url());
1061 " Site A ------------ proxies for B\n"
1062 " +--Site B ------- proxies for A\n"
1063 "Where A = http://b.com/\n"
1064 " B = http://baz.com/",
1065 DepictFrameTree(root
));
1067 // Add a new child frame to the top-level frame.
1068 RenderFrameHostCreatedObserver
frame_observer(shell()->web_contents(), 1);
1069 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1070 "window.domAutomationController.send("
1071 " addFrame('data:text/html,foo'));"));
1072 frame_observer
.Wait();
1074 // The new frame should have a proxy in Site B, for use by the old frame.
1076 " Site A ------------ proxies for B\n"
1077 " |--Site B ------- proxies for A\n"
1078 " +--Site A ------- proxies for B\n"
1079 "Where A = http://b.com/\n"
1080 " B = http://baz.com/",
1081 DepictFrameTree(root
));
1084 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
1085 // security checks are back in place.
1086 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
1087 // on Android (http://crbug.com/187570).
1088 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
1089 DISABLED_CrossSiteIframeRedirectOnce
) {
1090 ASSERT_TRUE(test_server()->Start());
1091 net::SpawnedTestServer
https_server(
1092 net::SpawnedTestServer::TYPE_HTTPS
,
1093 net::SpawnedTestServer::kLocalhost
,
1094 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1095 ASSERT_TRUE(https_server
.Start());
1097 GURL
main_url(test_server()->GetURL("files/site_per_process_main.html"));
1098 GURL
http_url(test_server()->GetURL("files/title1.html"));
1099 GURL
https_url(https_server
.GetURL("files/title1.html"));
1101 NavigateToURL(shell(), main_url
);
1103 TestNavigationObserver
observer(shell()->web_contents());
1105 // Load cross-site client-redirect page into Iframe.
1106 // Should be blocked.
1107 GURL
client_redirect_https_url(https_server
.GetURL(
1108 "client-redirect?files/title1.html"));
1109 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1110 client_redirect_https_url
));
1111 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
1112 EXPECT_EQ(observer
.last_navigation_url(), client_redirect_https_url
);
1113 EXPECT_FALSE(observer
.last_navigation_succeeded());
1117 // Load cross-site server-redirect page into Iframe,
1118 // which redirects to same-site page.
1119 GURL
server_redirect_http_url(https_server
.GetURL(
1120 "server-redirect?" + http_url
.spec()));
1121 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1122 server_redirect_http_url
));
1123 EXPECT_EQ(observer
.last_navigation_url(), http_url
);
1124 EXPECT_TRUE(observer
.last_navigation_succeeded());
1128 // Load cross-site server-redirect page into Iframe,
1129 // which redirects to cross-site page.
1130 GURL
server_redirect_http_url(https_server
.GetURL(
1131 "server-redirect?files/title1.html"));
1132 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1133 server_redirect_http_url
));
1134 // DidFailProvisionalLoad when navigating to https_url.
1135 EXPECT_EQ(observer
.last_navigation_url(), https_url
);
1136 EXPECT_FALSE(observer
.last_navigation_succeeded());
1140 // Load same-site server-redirect page into Iframe,
1141 // which redirects to cross-site page.
1142 GURL
server_redirect_http_url(test_server()->GetURL(
1143 "server-redirect?" + https_url
.spec()));
1144 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1145 server_redirect_http_url
));
1147 EXPECT_EQ(observer
.last_navigation_url(), https_url
);
1148 EXPECT_FALSE(observer
.last_navigation_succeeded());
1152 // Load same-site client-redirect page into Iframe,
1153 // which redirects to cross-site page.
1154 GURL
client_redirect_http_url(test_server()->GetURL(
1155 "client-redirect?" + https_url
.spec()));
1157 RedirectNotificationObserver
load_observer2(
1158 NOTIFICATION_LOAD_STOP
,
1159 Source
<NavigationController
>(
1160 &shell()->web_contents()->GetController()));
1162 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1163 client_redirect_http_url
));
1165 // Same-site Client-Redirect Page should be loaded successfully.
1166 EXPECT_EQ(observer
.last_navigation_url(), client_redirect_http_url
);
1167 EXPECT_TRUE(observer
.last_navigation_succeeded());
1169 // Redirecting to Cross-site Page should be blocked.
1170 load_observer2
.Wait();
1171 EXPECT_EQ(observer
.last_navigation_url(), https_url
);
1172 EXPECT_FALSE(observer
.last_navigation_succeeded());
1176 // Load same-site server-redirect page into Iframe,
1177 // which redirects to same-site page.
1178 GURL
server_redirect_http_url(test_server()->GetURL(
1179 "server-redirect?files/title1.html"));
1180 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1181 server_redirect_http_url
));
1182 EXPECT_EQ(observer
.last_navigation_url(), http_url
);
1183 EXPECT_TRUE(observer
.last_navigation_succeeded());
1187 // Load same-site client-redirect page into Iframe,
1188 // which redirects to same-site page.
1189 GURL
client_redirect_http_url(test_server()->GetURL(
1190 "client-redirect?" + http_url
.spec()));
1191 RedirectNotificationObserver
load_observer2(
1192 NOTIFICATION_LOAD_STOP
,
1193 Source
<NavigationController
>(
1194 &shell()->web_contents()->GetController()));
1196 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1197 client_redirect_http_url
));
1199 // Same-site Client-Redirect Page should be loaded successfully.
1200 EXPECT_EQ(observer
.last_navigation_url(), client_redirect_http_url
);
1201 EXPECT_TRUE(observer
.last_navigation_succeeded());
1203 // Redirecting to Same-site Page should be loaded successfully.
1204 load_observer2
.Wait();
1205 EXPECT_EQ(observer
.last_navigation_url(), http_url
);
1206 EXPECT_TRUE(observer
.last_navigation_succeeded());
1210 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
1211 // security checks are back in place.
1212 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
1213 // on Android (http://crbug.com/187570).
1214 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
1215 DISABLED_CrossSiteIframeRedirectTwice
) {
1216 ASSERT_TRUE(test_server()->Start());
1217 net::SpawnedTestServer
https_server(
1218 net::SpawnedTestServer::TYPE_HTTPS
,
1219 net::SpawnedTestServer::kLocalhost
,
1220 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1221 ASSERT_TRUE(https_server
.Start());
1223 GURL
main_url(test_server()->GetURL("files/site_per_process_main.html"));
1224 GURL
http_url(test_server()->GetURL("files/title1.html"));
1225 GURL
https_url(https_server
.GetURL("files/title1.html"));
1227 NavigateToURL(shell(), main_url
);
1229 TestNavigationObserver
observer(shell()->web_contents());
1231 // Load client-redirect page pointing to a cross-site client-redirect page,
1232 // which eventually redirects back to same-site page.
1233 GURL
client_redirect_https_url(https_server
.GetURL(
1234 "client-redirect?" + http_url
.spec()));
1235 GURL
client_redirect_http_url(test_server()->GetURL(
1236 "client-redirect?" + client_redirect_https_url
.spec()));
1238 // We should wait until second client redirect get cancelled.
1239 RedirectNotificationObserver
load_observer2(
1240 NOTIFICATION_LOAD_STOP
,
1241 Source
<NavigationController
>(
1242 &shell()->web_contents()->GetController()));
1244 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1245 client_redirect_http_url
));
1247 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
1248 load_observer2
.Wait();
1249 EXPECT_EQ(observer
.last_navigation_url(), client_redirect_https_url
);
1250 EXPECT_FALSE(observer
.last_navigation_succeeded());
1254 // Load server-redirect page pointing to a cross-site server-redirect page,
1255 // which eventually redirect back to same-site page.
1256 GURL
server_redirect_https_url(https_server
.GetURL(
1257 "server-redirect?" + http_url
.spec()));
1258 GURL
server_redirect_http_url(test_server()->GetURL(
1259 "server-redirect?" + server_redirect_https_url
.spec()));
1260 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1261 server_redirect_http_url
));
1262 EXPECT_EQ(observer
.last_navigation_url(), http_url
);
1263 EXPECT_TRUE(observer
.last_navigation_succeeded());
1267 // Load server-redirect page pointing to a cross-site server-redirect page,
1268 // which eventually redirects back to cross-site page.
1269 GURL
server_redirect_https_url(https_server
.GetURL(
1270 "server-redirect?" + https_url
.spec()));
1271 GURL
server_redirect_http_url(test_server()->GetURL(
1272 "server-redirect?" + server_redirect_https_url
.spec()));
1273 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1274 server_redirect_http_url
));
1276 // DidFailProvisionalLoad when navigating to https_url.
1277 EXPECT_EQ(observer
.last_navigation_url(), https_url
);
1278 EXPECT_FALSE(observer
.last_navigation_succeeded());
1282 // Load server-redirect page pointing to a cross-site client-redirect page,
1283 // which eventually redirects back to same-site page.
1284 GURL
client_redirect_http_url(https_server
.GetURL(
1285 "client-redirect?" + http_url
.spec()));
1286 GURL
server_redirect_http_url(test_server()->GetURL(
1287 "server-redirect?" + client_redirect_http_url
.spec()));
1288 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1289 server_redirect_http_url
));
1291 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
1292 EXPECT_EQ(observer
.last_navigation_url(), client_redirect_http_url
);
1293 EXPECT_FALSE(observer
.last_navigation_succeeded());
1297 // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
1298 // created in the FrameTree skipping the subtree of the navigating frame.
1299 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
1300 ProxyCreationSkipsSubtree
) {
1301 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1302 NavigateToURL(shell(), main_url
);
1304 // It is safe to obtain the root frame tree node here, as it doesn't change.
1305 FrameTreeNode
* root
=
1306 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1307 GetFrameTree()->root();
1309 EXPECT_TRUE(root
->child_at(1) != NULL
);
1310 EXPECT_EQ(2U, root
->child_at(1)->child_count());
1313 // Load same-site page into iframe.
1314 TestNavigationObserver
observer(shell()->web_contents());
1315 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
1316 NavigateFrameToURL(root
->child_at(0), http_url
);
1317 EXPECT_EQ(http_url
, observer
.last_navigation_url());
1318 EXPECT_TRUE(observer
.last_navigation_succeeded());
1326 "Where A = http://127.0.0.1/",
1327 DepictFrameTree(root
));
1330 // Create the cross-site URL to navigate to.
1331 GURL cross_site_url
=
1332 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html");
1334 // Load cross-site page into the second iframe without waiting for the
1335 // navigation to complete. Once LoadURLWithParams returns, we would expect
1336 // proxies to have been created in the frame tree, but children of the
1337 // navigating frame to still be present. The reason is that we don't run the
1338 // message loop, so no IPCs that alter the frame tree can be processed.
1339 FrameTreeNode
* child
= root
->child_at(1);
1340 SiteInstance
* site
= NULL
;
1342 TestNavigationObserver
observer(shell()->web_contents());
1343 TestFrameNavigationObserver
navigation_observer(child
);
1344 NavigationController::LoadURLParams
params(cross_site_url
);
1345 params
.transition_type
= PageTransitionFromInt(ui::PAGE_TRANSITION_LINK
);
1346 params
.frame_tree_node_id
= child
->frame_tree_node_id();
1347 child
->navigator()->GetController()->LoadURLWithParams(params
);
1349 site
= child
->render_manager()->pending_frame_host()->GetSiteInstance();
1350 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site
);
1353 " Site A ------------ proxies for B\n"
1354 " |--Site A ------- proxies for B\n"
1355 " +--Site A (B pending)\n"
1359 "Where A = http://127.0.0.1/\n"
1360 " B = http://foo.com/",
1361 DepictFrameTree(root
));
1363 // Now that the verification is done, run the message loop and wait for the
1364 // navigation to complete.
1365 navigation_observer
.Wait();
1366 EXPECT_FALSE(child
->render_manager()->pending_frame_host());
1367 EXPECT_TRUE(observer
.last_navigation_succeeded());
1368 EXPECT_EQ(cross_site_url
, observer
.last_navigation_url());
1371 " Site A ------------ proxies for B\n"
1372 " |--Site A ------- proxies for B\n"
1373 " +--Site B ------- proxies for A\n"
1374 "Where A = http://127.0.0.1/\n"
1375 " B = http://foo.com/",
1376 DepictFrameTree(root
));
1379 // Load another cross-site page into the same iframe.
1380 cross_site_url
= embedded_test_server()->GetURL("bar.com", "/title2.html");
1382 // Perform the same checks as the first cross-site navigation, since
1383 // there have been issues in subsequent cross-site navigations. Also ensure
1384 // that the SiteInstance has properly changed.
1385 // TODO(nasko): Once we have proper cleanup of resources, add code to
1386 // verify that the intermediate SiteInstance/RenderFrameHost have been
1387 // properly cleaned up.
1388 TestNavigationObserver
observer(shell()->web_contents());
1389 TestFrameNavigationObserver
navigation_observer(child
);
1390 NavigationController::LoadURLParams
params(cross_site_url
);
1391 params
.transition_type
= PageTransitionFromInt(ui::PAGE_TRANSITION_LINK
);
1392 params
.frame_tree_node_id
= child
->frame_tree_node_id();
1393 child
->navigator()->GetController()->LoadURLWithParams(params
);
1395 SiteInstance
* site2
=
1396 child
->render_manager()->pending_frame_host()->GetSiteInstance();
1397 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2
);
1398 EXPECT_NE(site
, site2
);
1401 " Site A ------------ proxies for B C\n"
1402 " |--Site A ------- proxies for B C\n"
1403 " +--Site B (C pending) -- proxies for A\n"
1404 "Where A = http://127.0.0.1/\n"
1405 " B = http://foo.com/\n"
1406 " C = http://bar.com/",
1407 DepictFrameTree(root
));
1409 navigation_observer
.Wait();
1410 EXPECT_TRUE(observer
.last_navigation_succeeded());
1411 EXPECT_EQ(cross_site_url
, observer
.last_navigation_url());
1412 EXPECT_EQ(0U, child
->child_count());
1416 // Verify that origin replication works for an A-embed-B-embed-C hierarchy.
1417 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, OriginReplication
) {
1418 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1419 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1421 // It is safe to obtain the root frame tree node here, as it doesn't change.
1422 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1426 TestNavigationObserver
observer(shell()->web_contents());
1428 // Navigate the first subframe to a cross-site page with two subframes.
1429 // NavigateFrameToURL can't be used here because it doesn't guarantee that
1430 // FrameTreeNodes will have been created for child frames when it returns.
1431 RenderFrameHostCreatedObserver
frame_observer(shell()->web_contents(), 4);
1433 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1434 NavigationController::LoadURLParams
params(foo_url
);
1435 params
.transition_type
= ui::PAGE_TRANSITION_LINK
;
1436 params
.frame_tree_node_id
= root
->child_at(0)->frame_tree_node_id();
1437 root
->child_at(0)->navigator()->GetController()->LoadURLWithParams(params
);
1438 frame_observer
.Wait();
1440 // We can't use a TestNavigationObserver to verify the URL here,
1441 // since the frame has children that may have clobbered it in the observer.
1442 EXPECT_EQ(foo_url
, root
->child_at(0)->current_url());
1444 // Ensure that a new process is created for the subframe.
1445 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1446 root
->child_at(0)->current_frame_host()->GetSiteInstance());
1448 // Load cross-site page into subframe's subframe.
1449 ASSERT_EQ(2U, root
->child_at(0)->child_count());
1450 GURL
bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1451 NavigateFrameToURL(root
->child_at(0)->child_at(0), bar_url
);
1452 EXPECT_TRUE(observer
.last_navigation_succeeded());
1453 EXPECT_EQ(bar_url
, observer
.last_navigation_url());
1455 // Check that a new process is created and is different from the top one and
1457 FrameTreeNode
* bottom_child
= root
->child_at(0)->child_at(0);
1458 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1459 bottom_child
->current_frame_host()->GetSiteInstance());
1460 EXPECT_NE(root
->child_at(0)->current_frame_host()->GetSiteInstance(),
1461 bottom_child
->current_frame_host()->GetSiteInstance());
1463 // Check that foo.com frame's location.ancestorOrigins contains the correct
1464 // origin for the parent. The origin should have been replicated as part of
1465 // the ViewMsg_New message that created the parent's RenderFrameProxy in
1466 // foo.com's process.
1467 int ancestor_origins_length
= 0;
1468 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1469 root
->child_at(0)->current_frame_host(),
1470 "window.domAutomationController.send(location.ancestorOrigins.length);",
1471 &ancestor_origins_length
));
1472 EXPECT_EQ(1, ancestor_origins_length
);
1474 EXPECT_TRUE(ExecuteScriptAndExtractString(
1475 root
->child_at(0)->current_frame_host(),
1476 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1478 EXPECT_EQ(result
+ "/", main_url
.GetOrigin().spec());
1480 // Check that bar.com frame's location.ancestorOrigins contains the correct
1481 // origin for its two ancestors. The topmost parent origin should be
1482 // replicated as part of ViewMsg_New, and the middle frame (foo.com's) origin
1483 // should be replicated as part of FrameMsg_NewFrameProxy sent for foo.com's
1484 // frame in bar.com's process.
1485 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1486 bottom_child
->current_frame_host(),
1487 "window.domAutomationController.send(location.ancestorOrigins.length);",
1488 &ancestor_origins_length
));
1489 EXPECT_EQ(2, ancestor_origins_length
);
1490 EXPECT_TRUE(ExecuteScriptAndExtractString(
1491 bottom_child
->current_frame_host(),
1492 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1494 EXPECT_EQ(result
+ "/", foo_url
.GetOrigin().spec());
1495 EXPECT_TRUE(ExecuteScriptAndExtractString(
1496 bottom_child
->current_frame_host(),
1497 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1499 EXPECT_EQ(result
+ "/", main_url
.GetOrigin().spec());
1502 // Check that iframe sandbox flags are replicated correctly.
1503 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, SandboxFlagsReplication
) {
1504 GURL
main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
1505 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1507 // It is safe to obtain the root frame tree node here, as it doesn't change.
1508 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1512 TestNavigationObserver
observer(shell()->web_contents());
1514 // Navigate the second (sandboxed) subframe to a cross-site page with a
1515 // subframe. Use RenderFrameHostCreatedObserver to guarantee that all
1516 // FrameTreeNodes are created for child frames.
1517 RenderFrameHostCreatedObserver
frame_observer(shell()->web_contents(), 4);
1519 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1520 NavigateFrameToURL(root
->child_at(1), foo_url
);
1521 frame_observer
.Wait();
1523 // We can't use a TestNavigationObserver to verify the URL here,
1524 // since the frame has children that may have clobbered it in the observer.
1525 EXPECT_EQ(foo_url
, root
->child_at(1)->current_url());
1527 // Load cross-site page into subframe's subframe.
1528 ASSERT_EQ(2U, root
->child_at(1)->child_count());
1529 GURL
bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1530 NavigateFrameToURL(root
->child_at(1)->child_at(0), bar_url
);
1531 EXPECT_TRUE(observer
.last_navigation_succeeded());
1532 EXPECT_EQ(bar_url
, observer
.last_navigation_url());
1534 // Opening a popup in the sandboxed foo.com iframe should fail.
1535 bool success
= false;
1537 ExecuteScriptAndExtractBool(root
->child_at(1)->current_frame_host(),
1538 "window.domAutomationController.send("
1539 "!window.open('data:text/html,dataurl'));",
1541 EXPECT_TRUE(success
);
1542 EXPECT_EQ(1u, Shell::windows().size());
1544 // Opening a popup in a frame whose parent is sandboxed should also fail.
1545 // Here, bar.com frame's sandboxed parent frame is a remote frame in
1546 // bar.com's process.
1548 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1549 root
->child_at(1)->child_at(0)->current_frame_host(),
1550 "window.domAutomationController.send("
1551 "!window.open('data:text/html,dataurl'));",
1553 EXPECT_TRUE(success
);
1554 EXPECT_EQ(1u, Shell::windows().size());
1556 // Same, but now try the case where bar.com frame's sandboxed parent is a
1557 // local frame in bar.com's process.
1559 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1560 root
->child_at(2)->child_at(0)->current_frame_host(),
1561 "window.domAutomationController.send("
1562 "!window.open('data:text/html,dataurl'));",
1564 EXPECT_TRUE(success
);
1565 EXPECT_EQ(1u, Shell::windows().size());
1567 // Check that foo.com frame's location.ancestorOrigins contains the correct
1568 // origin for the parent, which should be unaffected by sandboxing.
1569 int ancestor_origins_length
= 0;
1570 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1571 root
->child_at(1)->current_frame_host(),
1572 "window.domAutomationController.send(location.ancestorOrigins.length);",
1573 &ancestor_origins_length
));
1574 EXPECT_EQ(1, ancestor_origins_length
);
1576 EXPECT_TRUE(ExecuteScriptAndExtractString(
1577 root
->child_at(1)->current_frame_host(),
1578 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1580 EXPECT_EQ(result
+ "/", main_url
.GetOrigin().spec());
1582 // Now check location.ancestorOrigins for the bar.com frame. The middle frame
1583 // (foo.com's) origin should be unique, since that frame is sandboxed, and
1584 // the top frame should match |main_url|.
1585 FrameTreeNode
* bottom_child
= root
->child_at(1)->child_at(0);
1586 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1587 bottom_child
->current_frame_host(),
1588 "window.domAutomationController.send(location.ancestorOrigins.length);",
1589 &ancestor_origins_length
));
1590 EXPECT_EQ(2, ancestor_origins_length
);
1591 EXPECT_TRUE(ExecuteScriptAndExtractString(
1592 bottom_child
->current_frame_host(),
1593 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1595 EXPECT_EQ("null", result
);
1596 EXPECT_TRUE(ExecuteScriptAndExtractString(
1597 bottom_child
->current_frame_host(),
1598 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1600 EXPECT_EQ(main_url
.GetOrigin().spec(), result
+ "/");
1603 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1604 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, DynamicSandboxFlags
) {
1606 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1607 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1609 // It is safe to obtain the root frame tree node here, as it doesn't change.
1610 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1614 TestNavigationObserver
observer(shell()->web_contents());
1615 ASSERT_EQ(2U, root
->child_count());
1617 // Make sure first frame starts out at the correct cross-site page.
1618 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
1619 root
->child_at(0)->current_url());
1621 // Navigate second frame to another cross-site page.
1622 GURL
baz_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
1623 NavigateFrameToURL(root
->child_at(1), baz_url
);
1624 EXPECT_TRUE(observer
.last_navigation_succeeded());
1625 EXPECT_EQ(baz_url
, observer
.last_navigation_url());
1627 // Both frames should not be sandboxed to start with.
1628 EXPECT_EQ(SandboxFlags::NONE
,
1629 root
->child_at(0)->current_replication_state().sandbox_flags
);
1630 EXPECT_EQ(SandboxFlags::NONE
, root
->child_at(0)->effective_sandbox_flags());
1631 EXPECT_EQ(SandboxFlags::NONE
,
1632 root
->child_at(1)->current_replication_state().sandbox_flags
);
1633 EXPECT_EQ(SandboxFlags::NONE
, root
->child_at(1)->effective_sandbox_flags());
1635 // Dynamically update sandbox flags for the first frame.
1636 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1637 "window.domAutomationController.send("
1638 "document.querySelector('iframe').sandbox="
1639 "'allow-scripts');"));
1641 // Check that updated sandbox flags are propagated to browser process.
1642 // The new flags should be set in current_replication_state(), while
1643 // effective_sandbox_flags() should still reflect the old flags, because
1644 // sandbox flag updates take place only after navigations. "allow-scripts"
1645 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
1646 // per blink::parseSandboxPolicy().
1647 SandboxFlags expected_flags
= SandboxFlags::ALL
& ~SandboxFlags::SCRIPTS
&
1648 ~SandboxFlags::AUTOMATIC_FEATURES
;
1649 EXPECT_EQ(expected_flags
,
1650 root
->child_at(0)->current_replication_state().sandbox_flags
);
1651 EXPECT_EQ(SandboxFlags::NONE
, root
->child_at(0)->effective_sandbox_flags());
1653 // Navigate the first frame to a page on the same site. The new sandbox
1654 // flags should take effect. The new page has a child frame, so use
1655 // TestFrameNavigationObserver to wait for it to be loaded.
1656 TestFrameNavigationObserver
frame_observer(root
->child_at(0), 2);
1658 embedded_test_server()->GetURL("bar.com", "/frame_tree/2-4.html"));
1659 NavigateFrameToURL(root
->child_at(0), bar_url
);
1660 frame_observer
.Wait();
1661 EXPECT_EQ(bar_url
, root
->child_at(0)->current_url());
1662 ASSERT_EQ(1U, root
->child_at(0)->child_count());
1664 // Confirm that the browser process has updated the frame's current sandbox
1666 EXPECT_EQ(expected_flags
,
1667 root
->child_at(0)->current_replication_state().sandbox_flags
);
1668 EXPECT_EQ(expected_flags
, root
->child_at(0)->effective_sandbox_flags());
1670 // Opening a popup in the now-sandboxed frame should fail.
1671 bool success
= false;
1673 ExecuteScriptAndExtractBool(root
->child_at(0)->current_frame_host(),
1674 "window.domAutomationController.send("
1675 "!window.open('data:text/html,dataurl'));",
1677 EXPECT_TRUE(success
);
1678 EXPECT_EQ(1u, Shell::windows().size());
1680 // Navigate the child of the now-sandboxed frame to a page on baz.com. The
1681 // child should inherit the latest sandbox flags from its parent frame, which
1682 // is currently a proxy in baz.com's renderer process. This checks that the
1683 // proxies of |root->child_at(0)| were also updated with the latest sandbox
1685 GURL
baz_child_url(embedded_test_server()->GetURL("baz.com", "/title2.html"));
1686 NavigateFrameToURL(root
->child_at(0)->child_at(0), baz_child_url
);
1687 EXPECT_TRUE(observer
.last_navigation_succeeded());
1688 EXPECT_EQ(baz_child_url
, observer
.last_navigation_url());
1690 // Opening a popup in the child of a sandboxed frame should fail.
1692 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1693 root
->child_at(0)->child_at(0)->current_frame_host(),
1694 "window.domAutomationController.send("
1695 "!window.open('data:text/html,dataurl'));",
1697 EXPECT_TRUE(success
);
1698 EXPECT_EQ(1u, Shell::windows().size());
1701 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1702 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
1703 DynamicSandboxFlagsRemoteToLocal
) {
1705 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1706 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1708 // It is safe to obtain the root frame tree node here, as it doesn't change.
1709 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1713 TestNavigationObserver
observer(shell()->web_contents());
1714 ASSERT_EQ(2U, root
->child_count());
1716 // Make sure the two frames starts out at correct URLs.
1717 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
1718 root
->child_at(0)->current_url());
1719 EXPECT_EQ(embedded_test_server()->GetURL("/title1.html"),
1720 root
->child_at(1)->current_url());
1722 // Update the second frame's sandbox flags.
1723 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1724 "window.domAutomationController.send("
1725 "document.querySelectorAll('iframe')[1].sandbox="
1726 "'allow-scripts');"));
1728 // Check that the current sandbox flags are updated but the effective
1729 // sandbox flags are not.
1730 SandboxFlags expected_flags
= SandboxFlags::ALL
& ~SandboxFlags::SCRIPTS
&
1731 ~SandboxFlags::AUTOMATIC_FEATURES
;
1732 EXPECT_EQ(expected_flags
,
1733 root
->child_at(1)->current_replication_state().sandbox_flags
);
1734 EXPECT_EQ(SandboxFlags::NONE
, root
->child_at(1)->effective_sandbox_flags());
1736 // Navigate the second subframe to a page on bar.com. This will trigger a
1737 // remote-to-local frame swap in bar.com's process. The target page has
1738 // another frame, so use TestFrameNavigationObserver to wait for all frames
1740 TestFrameNavigationObserver
frame_observer(root
->child_at(1), 2);
1741 GURL
bar_url(embedded_test_server()->GetURL(
1742 "bar.com", "/frame_tree/page_with_one_frame.html"));
1743 NavigateFrameToURL(root
->child_at(1), bar_url
);
1744 frame_observer
.Wait();
1745 EXPECT_EQ(bar_url
, root
->child_at(1)->current_url());
1746 ASSERT_EQ(1U, root
->child_at(1)->child_count());
1748 // Confirm that the browser process has updated the current sandbox flags.
1749 EXPECT_EQ(expected_flags
,
1750 root
->child_at(1)->current_replication_state().sandbox_flags
);
1751 EXPECT_EQ(expected_flags
, root
->child_at(1)->effective_sandbox_flags());
1753 // Opening a popup in the sandboxed second frame should fail.
1754 bool success
= false;
1756 ExecuteScriptAndExtractBool(root
->child_at(1)->current_frame_host(),
1757 "window.domAutomationController.send("
1758 "!window.open('data:text/html,dataurl'));",
1760 EXPECT_TRUE(success
);
1761 EXPECT_EQ(1u, Shell::windows().size());
1763 // Make sure that the child frame inherits the sandbox flags of its
1764 // now-sandboxed parent frame.
1766 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1767 root
->child_at(1)->child_at(0)->current_frame_host(),
1768 "window.domAutomationController.send("
1769 "!window.open('data:text/html,dataurl'));",
1771 EXPECT_TRUE(success
);
1772 EXPECT_EQ(1u, Shell::windows().size());
1775 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1776 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
1777 DynamicSandboxFlagsRendererInitiatedNavigation
) {
1779 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
1780 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1782 // It is safe to obtain the root frame tree node here, as it doesn't change.
1783 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1787 TestNavigationObserver
observer(shell()->web_contents());
1788 ASSERT_EQ(1U, root
->child_count());
1790 // Make sure the frame starts out at the correct cross-site page.
1791 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
1792 root
->child_at(0)->current_url());
1794 // The frame should not be sandboxed to start with.
1795 EXPECT_EQ(SandboxFlags::NONE
,
1796 root
->child_at(0)->current_replication_state().sandbox_flags
);
1797 EXPECT_EQ(SandboxFlags::NONE
, root
->child_at(0)->effective_sandbox_flags());
1799 // Dynamically update the frame's sandbox flags.
1800 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1801 "window.domAutomationController.send("
1802 "document.querySelector('iframe').sandbox="
1803 "'allow-scripts');"));
1805 // Check that updated sandbox flags are propagated to browser process.
1806 // The new flags should be set in current_replication_state(), while
1807 // effective_sandbox_flags() should still reflect the old flags, because
1808 // sandbox flag updates take place only after navigations. "allow-scripts"
1809 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
1810 // per blink::parseSandboxPolicy().
1811 SandboxFlags expected_flags
= SandboxFlags::ALL
& ~SandboxFlags::SCRIPTS
&
1812 ~SandboxFlags::AUTOMATIC_FEATURES
;
1813 EXPECT_EQ(expected_flags
,
1814 root
->child_at(0)->current_replication_state().sandbox_flags
);
1815 EXPECT_EQ(SandboxFlags::NONE
, root
->child_at(0)->effective_sandbox_flags());
1817 // Perform a renderer-initiated same-site navigation in the first frame. The
1818 // new sandbox flags should take effect.
1819 TestFrameNavigationObserver
frame_observer(root
->child_at(0));
1820 ASSERT_TRUE(ExecuteScript(root
->child_at(0)->current_frame_host(),
1821 "window.location.href='/title2.html'"));
1822 frame_observer
.Wait();
1823 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title2.html"),
1824 root
->child_at(0)->current_url());
1826 // Confirm that the browser process has updated the frame's current sandbox
1828 EXPECT_EQ(expected_flags
,
1829 root
->child_at(0)->current_replication_state().sandbox_flags
);
1830 EXPECT_EQ(expected_flags
, root
->child_at(0)->effective_sandbox_flags());
1832 // Opening a popup in the now-sandboxed frame should fail.
1833 bool success
= false;
1835 ExecuteScriptAndExtractBool(root
->child_at(0)->current_frame_host(),
1836 "window.domAutomationController.send("
1837 "!window.open('data:text/html,dataurl'));",
1839 EXPECT_TRUE(success
);
1840 EXPECT_EQ(1u, Shell::windows().size());
1843 // Verify that when a new child frame is added, the proxies created for it in
1844 // other SiteInstances have correct sandbox flags and origin.
1852 // The test checks sandbox flags and origin for the proxy added in step 2, by
1853 // checking whether the grandchild frame added in step 3 sees proper sandbox
1854 // flags and origin for its (remote) parent. This wasn't addressed when
1855 // https://crbug.com/423587 was fixed.
1856 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
1857 ProxiesForNewChildFramesHaveCorrectReplicationState
) {
1859 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
1860 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1862 // It is safe to obtain the root frame tree node here, as it doesn't change.
1863 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1866 TestNavigationObserver
observer(shell()->web_contents());
1869 " Site A ------------ proxies for B\n"
1870 " +--Site B ------- proxies for A\n"
1871 "Where A = http://127.0.0.1/\n"
1872 " B = http://baz.com/",
1873 DepictFrameTree(root
));
1875 // In the root frame, add a new sandboxed local frame, which itself has a
1876 // child frame on baz.com. Wait for three RenderFrameHosts to be created:
1877 // the new sandboxed local frame, its child (while it's still local), and a
1878 // pending RFH when starting the cross-site navigation to baz.com.
1879 RenderFrameHostCreatedObserver
frame_observer(shell()->web_contents(), 3);
1881 ExecuteScript(root
->current_frame_host(),
1882 "window.domAutomationController.send("
1883 " addFrame('/frame_tree/page_with_one_frame.html',"
1884 " 'allow-scripts allow-same-origin'))"));
1885 frame_observer
.Wait();
1887 // Wait for the cross-site navigation to baz.com in the grandchild to finish.
1888 FrameTreeNode
* bottom_child
= root
->child_at(1)->child_at(0);
1889 TestFrameNavigationObserver
navigation_observer(bottom_child
);
1890 navigation_observer
.Wait();
1893 " Site A ------------ proxies for B\n"
1894 " |--Site B ------- proxies for A\n"
1895 " +--Site A ------- proxies for B\n"
1896 " +--Site B -- proxies for A\n"
1897 "Where A = http://127.0.0.1/\n"
1898 " B = http://baz.com/",
1899 DepictFrameTree(root
));
1901 // Use location.ancestorOrigins to check that the grandchild on baz.com sees
1902 // correct origin for its parent.
1903 int ancestor_origins_length
= 0;
1904 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1905 bottom_child
->current_frame_host(),
1906 "window.domAutomationController.send(location.ancestorOrigins.length);",
1907 &ancestor_origins_length
));
1908 EXPECT_EQ(2, ancestor_origins_length
);
1909 std::string parent_origin
;
1910 EXPECT_TRUE(ExecuteScriptAndExtractString(
1911 bottom_child
->current_frame_host(),
1912 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1914 EXPECT_EQ(main_url
.GetOrigin().spec(), parent_origin
+ "/");
1916 // Check that the sandbox flags in the browser process are correct.
1917 // "allow-scripts" resets both SandboxFlags::Scripts and
1918 // SandboxFlags::AutomaticFeatures bits per blink::parseSandboxPolicy().
1919 SandboxFlags expected_flags
= SandboxFlags::ALL
& ~SandboxFlags::SCRIPTS
&
1920 ~SandboxFlags::AUTOMATIC_FEATURES
&
1921 ~SandboxFlags::ORIGIN
;
1922 EXPECT_EQ(expected_flags
,
1923 root
->child_at(1)->current_replication_state().sandbox_flags
);
1925 // The child of the sandboxed frame should've inherited sandbox flags, so it
1926 // should not be able to create popups.
1927 bool success
= false;
1929 ExecuteScriptAndExtractBool(bottom_child
->current_frame_host(),
1930 "window.domAutomationController.send("
1931 "!window.open('data:text/html,dataurl'));",
1933 EXPECT_TRUE(success
);
1934 EXPECT_EQ(1u, Shell::windows().size());
1937 // Verify that a child frame can retrieve the name property set by its parent.
1938 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, WindowNameReplication
) {
1939 GURL
main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
1940 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1942 // It is safe to obtain the root frame tree node here, as it doesn't change.
1943 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1947 TestNavigationObserver
observer(shell()->web_contents());
1949 // Load cross-site page into iframe.
1951 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
1952 NavigateFrameToURL(root
->child_at(0), frame_url
);
1953 EXPECT_TRUE(observer
.last_navigation_succeeded());
1954 EXPECT_EQ(frame_url
, observer
.last_navigation_url());
1956 // Ensure that a new process is created for the subframe.
1957 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1958 root
->child_at(0)->current_frame_host()->GetSiteInstance());
1960 // Check that the window.name seen by the frame matches the name attribute
1961 // specified by its parent in the iframe tag.
1963 EXPECT_TRUE(ExecuteScriptAndExtractString(
1964 root
->child_at(0)->current_frame_host(),
1965 "window.domAutomationController.send(window.name);", &result
));
1966 EXPECT_EQ("3-1-name", result
);
1969 // Verify that dynamic updates to a frame's window.name propagate to the
1970 // frame's proxies, so that the latest frame names can be used in navigations.
1971 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, DynamicWindowName
) {
1972 GURL
main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
1973 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1975 // It is safe to obtain the root frame tree node here, as it doesn't change.
1976 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1979 TestNavigationObserver
observer(shell()->web_contents());
1981 // Load cross-site page into iframe.
1983 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
1984 NavigateFrameToURL(root
->child_at(0), frame_url
);
1985 EXPECT_TRUE(observer
.last_navigation_succeeded());
1986 EXPECT_EQ(frame_url
, observer
.last_navigation_url());
1988 // Browser process should know the child frame's original window.name
1989 // specified in the iframe element.
1990 EXPECT_EQ(root
->child_at(0)->frame_name(), "3-1-name");
1992 // Update the child frame's window.name.
1993 EXPECT_TRUE(ExecuteScript(root
->child_at(0)->current_frame_host(),
1994 "window.domAutomationController.send("
1995 "window.name = 'updated-name');"));
1997 // The change should propagate to the browser process.
1998 EXPECT_EQ(root
->child_at(0)->frame_name(), "updated-name");
2000 // The proxy in the parent process should also receive the updated name.
2001 // Check that it can reference the child frame by its new name.
2002 bool success
= false;
2004 ExecuteScriptAndExtractBool(shell()->web_contents(),
2005 "window.domAutomationController.send("
2006 "frames['updated-name'] == frames[0]);",
2008 EXPECT_TRUE(success
);
2010 // Issue a renderer-initiated navigation from the root frame to the child
2011 // frame using the frame's name. Make sure correct frame is navigated.
2013 // TODO(alexmos): When blink::createWindow is refactored to handle
2014 // RemoteFrames, this should also be tested via window.open(url, frame_name)
2015 // and a more complicated frame hierarchy (https://crbug.com/463742)
2016 TestFrameNavigationObserver
frame_observer(root
->child_at(0));
2017 GURL
foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
2018 std::string script
= base::StringPrintf(
2019 "window.domAutomationController.send("
2020 "frames['updated-name'].location.href = '%s');",
2021 foo_url
.spec().c_str());
2022 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script
));
2023 frame_observer
.Wait();
2024 EXPECT_EQ(foo_url
, root
->child_at(0)->current_url());
2027 // Verify that when a frame is navigated to a new origin, the origin update
2028 // propagates to the frame's proxies.
2029 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, OriginUpdatesReachProxies
) {
2031 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2032 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
2034 // It is safe to obtain the root frame tree node here, as it doesn't change.
2035 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2038 TestNavigationObserver
observer(shell()->web_contents());
2041 " Site A ------------ proxies for B\n"
2042 " |--Site B ------- proxies for A\n"
2043 " +--Site A ------- proxies for B\n"
2044 "Where A = http://127.0.0.1/\n"
2045 " B = http://bar.com/",
2046 DepictFrameTree(root
));
2048 // Navigate second subframe to a baz.com. This should send an origin update
2049 // to the frame's proxy in the bar.com (first frame's) process.
2050 GURL frame_url
= embedded_test_server()->GetURL("baz.com", "/title2.html");
2051 NavigateFrameToURL(root
->child_at(1), frame_url
);
2052 EXPECT_TRUE(observer
.last_navigation_succeeded());
2053 EXPECT_EQ(frame_url
, observer
.last_navigation_url());
2055 // The first frame can't directly observe the second frame's origin with
2056 // JavaScript. Instead, try to navigate the second frame from the first
2057 // frame. This should fail with a console error message, which should
2058 // contain the second frame's updated origin (see blink::Frame::canNavigate).
2059 scoped_ptr
<ConsoleObserverDelegate
> console_delegate(
2060 new ConsoleObserverDelegate(
2061 shell()->web_contents(),
2062 "Unsafe JavaScript attempt to initiate navigation*"));
2063 shell()->web_contents()->SetDelegate(console_delegate
.get());
2065 // frames[1] can't be used due to a bug where RemoteFrames are created out of
2066 // order (https://crbug.com/478792). Instead, target second frame by name.
2067 EXPECT_TRUE(ExecuteScript(
2068 root
->child_at(0)->current_frame_host(),
2069 "window.domAutomationController.send("
2070 " parent.frames['frame2'].location.href = 'data:text/html,foo');"));
2071 console_delegate
->Wait();
2073 std::string frame_origin
=
2074 root
->child_at(1)->current_replication_state().origin
.string();
2075 EXPECT_EQ(frame_origin
+ "/", frame_url
.GetOrigin().spec());
2077 MatchPattern(console_delegate
->message(), "*" + frame_origin
+ "*"))
2078 << "Error message does not contain the frame's latest origin ("
2079 << frame_origin
<< ")";
2082 // Ensure that navigating subframes in --site-per-process mode properly fires
2083 // the DidStopLoading event on WebContentsObserver.
2084 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, CrossSiteDidStopLoading
) {
2085 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
2086 NavigateToURL(shell(), main_url
);
2088 // It is safe to obtain the root frame tree node here, as it doesn't change.
2089 FrameTreeNode
* root
=
2090 static_cast<WebContentsImpl
*>(shell()->web_contents())->
2091 GetFrameTree()->root();
2093 TestNavigationObserver
observer(shell()->web_contents());
2095 // Load same-site page into iframe.
2096 FrameTreeNode
* child
= root
->child_at(0);
2097 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
2098 NavigateFrameToURL(child
, http_url
);
2099 EXPECT_EQ(http_url
, observer
.last_navigation_url());
2100 EXPECT_TRUE(observer
.last_navigation_succeeded());
2102 // Load cross-site page into iframe.
2103 TestNavigationObserver
nav_observer(shell()->web_contents(), 1);
2104 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
2105 NavigationController::LoadURLParams
params(url
);
2106 params
.transition_type
= ui::PAGE_TRANSITION_LINK
;
2107 params
.frame_tree_node_id
= child
->frame_tree_node_id();
2108 child
->navigator()->GetController()->LoadURLWithParams(params
);
2109 nav_observer
.Wait();
2111 // Verify that the navigation succeeded and the expected URL was loaded.
2112 EXPECT_TRUE(observer
.last_navigation_succeeded());
2113 EXPECT_EQ(url
, observer
.last_navigation_url());
2116 // Ensure that the renderer does not crash when navigating a frame that has a
2117 // sibling RemoteFrame. See https://crbug.com/426953.
2118 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
2119 NavigateWithSiblingRemoteFrame
) {
2121 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2122 NavigateToURL(shell(), main_url
);
2124 // It is safe to obtain the root frame tree node here, as it doesn't change.
2125 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2128 TestNavigationObserver
observer(shell()->web_contents());
2130 // Make sure the first frame is out of process.
2131 ASSERT_EQ(2U, root
->child_count());
2132 FrameTreeNode
* node2
= root
->child_at(0);
2133 EXPECT_NE(root
->current_frame_host()->GetSiteInstance(),
2134 node2
->current_frame_host()->GetSiteInstance());
2136 // Make sure the second frame is in the parent's process.
2137 FrameTreeNode
* node3
= root
->child_at(1);
2138 EXPECT_EQ(root
->current_frame_host()->GetSiteInstance(),
2139 node3
->current_frame_host()->GetSiteInstance());
2141 // Navigate the second iframe (node3) to a URL in its own process.
2142 GURL title_url
= embedded_test_server()->GetURL("/title2.html");
2143 NavigateFrameToURL(node3
, title_url
);
2144 EXPECT_TRUE(observer
.last_navigation_succeeded());
2145 EXPECT_EQ(title_url
, observer
.last_navigation_url());
2146 EXPECT_EQ(root
->current_frame_host()->GetSiteInstance(),
2147 node3
->current_frame_host()->GetSiteInstance());
2148 EXPECT_TRUE(node3
->current_frame_host()->IsRenderFrameLive());
2151 // Verify that load events for iframe elements work when the child frame is
2152 // out-of-process. In such cases, the load event is forwarded from the child
2153 // frame to the parent frame via the browser process.
2154 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, LoadEventForwarding
) {
2155 // Load a page with a cross-site frame. The parent page has an onload
2156 // handler in the iframe element that appends "LOADED" to the document title.
2159 embedded_test_server()->GetURL("/frame_with_load_event.html"));
2160 base::string16
expected_title(base::UTF8ToUTF16("LOADED"));
2161 TitleWatcher
title_watcher(shell()->web_contents(), expected_title
);
2162 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
2163 EXPECT_EQ(title_watcher
.WaitAndGetTitle(), expected_title
);
2166 // It is safe to obtain the root frame tree node here, as it doesn't change.
2167 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2171 // Load another cross-site page into the iframe and check that the load event
2174 GURL
foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
2175 base::string16
expected_title(base::UTF8ToUTF16("LOADEDLOADED"));
2176 TitleWatcher
title_watcher(shell()->web_contents(), expected_title
);
2177 TestNavigationObserver
observer(shell()->web_contents());
2178 NavigateFrameToURL(root
->child_at(0), foo_url
);
2179 EXPECT_TRUE(observer
.last_navigation_succeeded());
2180 EXPECT_EQ(foo_url
, observer
.last_navigation_url());
2181 EXPECT_EQ(title_watcher
.WaitAndGetTitle(), expected_title
);
2185 // Check that postMessage can be routed between cross-site iframes.
2186 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, SubframePostMessage
) {
2187 GURL
main_url(embedded_test_server()->GetURL(
2188 "/frame_tree/page_with_post_message_frames.html"));
2189 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
2191 // It is safe to obtain the root frame tree node here, as it doesn't change.
2192 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2196 TestNavigationObserver
observer(shell()->web_contents());
2197 ASSERT_EQ(2U, root
->child_count());
2199 // Verify the frames start at correct URLs. First frame should be
2200 // same-site; second frame should be cross-site.
2201 GURL
same_site_url(embedded_test_server()->GetURL("/post_message.html"));
2202 EXPECT_EQ(same_site_url
, root
->child_at(0)->current_url());
2203 GURL
foo_url(embedded_test_server()->GetURL("foo.com",
2204 "/post_message.html"));
2205 EXPECT_EQ(foo_url
, root
->child_at(1)->current_url());
2206 EXPECT_NE(root
->child_at(0)->current_frame_host()->GetSiteInstance(),
2207 root
->child_at(1)->current_frame_host()->GetSiteInstance());
2209 // Send a message from first, same-site frame to second, cross-site frame.
2210 // Expect the second frame to reply back to the first frame.
2211 PostMessageAndWaitForReply(root
->child_at(0),
2212 "postToSibling('subframe-msg','subframe2')",
2213 "\"done-subframe1\"");
2215 // Send a postMessage from second, cross-site frame to its parent. Expect
2216 // parent to send a reply to the frame.
2217 base::string16
expected_title(base::ASCIIToUTF16("subframe-msg"));
2218 TitleWatcher
title_watcher(shell()->web_contents(), expected_title
);
2219 PostMessageAndWaitForReply(root
->child_at(1), "postToParent('subframe-msg')",
2220 "\"done-subframe2\"");
2221 EXPECT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
2223 // Verify the total number of received messages for each subframe. First
2224 // frame should have one message (reply from second frame), and second frame
2225 // should have two messages (message from first frame and reply from parent).
2226 int subframe1_received_messages
= 0;
2227 int subframe2_received_messages
= 0;
2228 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2229 root
->child_at(0)->current_frame_host(),
2230 "window.domAutomationController.send(window.receivedMessages);",
2231 &subframe1_received_messages
));
2232 EXPECT_EQ(1, subframe1_received_messages
);
2233 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2234 root
->child_at(1)->current_frame_host(),
2235 "window.domAutomationController.send(window.receivedMessages);",
2236 &subframe2_received_messages
));
2237 EXPECT_EQ(2, subframe2_received_messages
);
2240 // Check that parent.frames[num] references correct sibling frames when the
2241 // parent is remote. See https://crbug.com/478792.
2242 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, IndexedFrameAccess
) {
2243 // Start on a page with three same-site subframes.
2245 embedded_test_server()->GetURL("a.com", "/frame_tree/top.html"));
2246 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
2248 // It is safe to obtain the root frame tree node here, as it doesn't change.
2249 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2252 ASSERT_EQ(3U, root
->child_count());
2253 FrameTreeNode
* child0
= root
->child_at(0);
2254 FrameTreeNode
* child1
= root
->child_at(1);
2255 FrameTreeNode
* child2
= root
->child_at(2);
2257 // Send each of the frames to a different site. Each new renderer will first
2258 // create proxies for the parent and two sibling subframes and then create
2259 // and insert the new RenderFrame into the frame tree.
2260 GURL
b_url(embedded_test_server()->GetURL("b.com", "/post_message.html"));
2261 GURL
c_url(embedded_test_server()->GetURL("c.com", "/post_message.html"));
2262 GURL
d_url(embedded_test_server()->GetURL("d.com", "/post_message.html"));
2263 NavigateFrameToURL(child0
, b_url
);
2264 // TODO(alexmos): The calls to WaitForRenderFrameReady can be removed once
2265 // TestFrameNavigationObserver is fixed to use DidFinishLoad.
2266 EXPECT_TRUE(WaitForRenderFrameReady(child0
->current_frame_host()));
2267 NavigateFrameToURL(child1
, c_url
);
2268 EXPECT_TRUE(WaitForRenderFrameReady(child1
->current_frame_host()));
2269 NavigateFrameToURL(child2
, d_url
);
2270 EXPECT_TRUE(WaitForRenderFrameReady(child2
->current_frame_host()));
2273 " Site A ------------ proxies for B C D\n"
2274 " |--Site B ------- proxies for A C D\n"
2275 " |--Site C ------- proxies for A B D\n"
2276 " +--Site D ------- proxies for A B C\n"
2277 "Where A = http://a.com/\n"
2278 " B = http://b.com/\n"
2279 " C = http://c.com/\n"
2280 " D = http://d.com/",
2281 DepictFrameTree(root
));
2283 // Check that each subframe sees itself at correct index in parent.frames.
2284 bool success
= false;
2285 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2286 child0
->current_frame_host(),
2287 "window.domAutomationController.send(window === parent.frames[0]);",
2289 EXPECT_TRUE(success
);
2292 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2293 child1
->current_frame_host(),
2294 "window.domAutomationController.send(window === parent.frames[1]);",
2296 EXPECT_TRUE(success
);
2299 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2300 child2
->current_frame_host(),
2301 "window.domAutomationController.send(window === parent.frames[2]);",
2303 EXPECT_TRUE(success
);
2305 // Send a postMessage from B to parent.frames[1], which should go to C, and
2307 PostMessageAndWaitForReply(child0
, "postToSibling('subframe-msg', 1)",
2308 "\"done-1-1-name\"");
2310 // Send a postMessage from C to parent.frames[2], which should go to D, and
2312 PostMessageAndWaitForReply(child1
, "postToSibling('subframe-msg', 2)",
2313 "\"done-1-2-name\"");
2315 // Verify the total number of received messages for each subframe.
2316 int child0_received_messages
= 0;
2317 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2318 child0
->current_frame_host(),
2319 "window.domAutomationController.send(window.receivedMessages);",
2320 &child0_received_messages
));
2321 EXPECT_EQ(1, child0_received_messages
);
2323 int child1_received_messages
= 0;
2324 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2325 child1
->current_frame_host(),
2326 "window.domAutomationController.send(window.receivedMessages);",
2327 &child1_received_messages
));
2328 EXPECT_EQ(2, child1_received_messages
);
2330 int child2_received_messages
= 0;
2331 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2332 child2
->current_frame_host(),
2333 "window.domAutomationController.send(window.receivedMessages);",
2334 &child2_received_messages
));
2335 EXPECT_EQ(1, child2_received_messages
);
2338 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, RFPHDestruction
) {
2339 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
2340 NavigateToURL(shell(), main_url
);
2342 // It is safe to obtain the root frame tree node here, as it doesn't change.
2343 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2347 TestNavigationObserver
observer(shell()->web_contents());
2349 // Load cross-site page into iframe.
2350 FrameTreeNode
* child
= root
->child_at(0);
2351 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
2352 NavigateFrameToURL(root
->child_at(0), url
);
2353 EXPECT_TRUE(observer
.last_navigation_succeeded());
2354 EXPECT_EQ(url
, observer
.last_navigation_url());
2356 " Site A ------------ proxies for B\n"
2357 " |--Site B ------- proxies for A\n"
2358 " +--Site A ------- proxies for B\n"
2359 " |--Site A -- proxies for B\n"
2360 " +--Site A -- proxies for B\n"
2361 " +--Site A -- proxies for B\n"
2362 "Where A = http://127.0.0.1/\n"
2363 " B = http://foo.com/",
2364 DepictFrameTree(root
));
2366 // Load another cross-site page.
2367 url
= embedded_test_server()->GetURL("bar.com", "/title3.html");
2368 NavigateIframeToURL(shell()->web_contents(), "test", url
);
2369 EXPECT_TRUE(observer
.last_navigation_succeeded());
2370 EXPECT_EQ(url
, observer
.last_navigation_url());
2372 " Site A ------------ proxies for C\n"
2373 " |--Site C ------- proxies for A\n"
2374 " +--Site A ------- proxies for C\n"
2375 " |--Site A -- proxies for C\n"
2376 " +--Site A -- proxies for C\n"
2377 " +--Site A -- proxies for C\n"
2378 "Where A = http://127.0.0.1/\n"
2379 " C = http://bar.com/",
2380 DepictFrameTree(root
));
2382 // Navigate back to the parent's origin.
2383 url
= embedded_test_server()->GetURL("/title1.html");
2384 NavigateFrameToURL(child
, url
);
2385 EXPECT_EQ(url
, observer
.last_navigation_url());
2386 EXPECT_TRUE(observer
.last_navigation_succeeded());
2394 "Where A = http://127.0.0.1/",
2395 DepictFrameTree(root
));
2398 } // namespace content