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/location.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/strings/pattern.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "content/browser/frame_host/cross_process_frame_connector.h"
18 #include "content/browser/frame_host/frame_tree.h"
19 #include "content/browser/frame_host/navigator.h"
20 #include "content/browser/frame_host/render_frame_proxy_host.h"
21 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
22 #include "content/browser/renderer_host/render_view_host_impl.h"
23 #include "content/browser/web_contents/web_contents_impl.h"
24 #include "content/common/frame_messages.h"
25 #include "content/public/browser/notification_observer.h"
26 #include "content/public/browser/notification_service.h"
27 #include "content/public/browser/notification_types.h"
28 #include "content/public/common/content_switches.h"
29 #include "content/public/test/browser_test_utils.h"
30 #include "content/public/test/content_browser_test_utils.h"
31 #include "content/public/test/test_navigation_observer.h"
32 #include "content/public/test/test_utils.h"
33 #include "content/shell/browser/shell.h"
34 #include "content/test/content_browser_test_utils_internal.h"
35 #include "content/test/test_frame_navigation_observer.h"
36 #include "ipc/ipc_security_test_util.h"
37 #include "net/dns/mock_host_resolver.h"
38 #include "net/test/embedded_test_server/embedded_test_server.h"
39 #include "third_party/WebKit/public/web/WebSandboxFlags.h"
45 // Helper function to send a postMessage and wait for a reply message. The
46 // |post_message_script| is executed on the |sender_ftn| frame, and the sender
47 // frame is expected to post |reply_status| from the DOMAutomationController
48 // when it receives a reply.
49 void PostMessageAndWaitForReply(FrameTreeNode
* sender_ftn
,
50 const std::string
& post_message_script
,
51 const std::string
& reply_status
) {
52 // Subtle: msg_queue needs to be declared before the ExecuteScript below, or
53 // else it might miss the message of interest. See https://crbug.com/518729.
54 DOMMessageQueue msg_queue
;
57 EXPECT_TRUE(ExecuteScriptAndExtractBool(
58 sender_ftn
->current_frame_host(),
59 "window.domAutomationController.send(" + post_message_script
+ ");",
64 while (msg_queue
.WaitForMessage(&status
)) {
65 if (status
== reply_status
)
70 // Helper function to extract and return "window.receivedMessages" from the
71 // |sender_ftn| frame. This variable is used in post_message.html to count the
72 // number of messages received via postMessage by the current window.
73 int GetReceivedMessages(FrameTreeNode
* ftn
) {
74 int received_messages
= 0;
75 EXPECT_TRUE(ExecuteScriptAndExtractInt(
76 ftn
->current_frame_host(),
77 "window.domAutomationController.send(window.receivedMessages);",
79 return received_messages
;
82 // Helper function to perform a window.open from the |caller_frame| targeting a
83 // frame with the specified name.
84 void NavigateNamedFrame(const ToRenderFrameHost
& caller_frame
,
86 const std::string
& name
) {
88 EXPECT_TRUE(ExecuteScriptAndExtractBool(
90 "window.domAutomationController.send("
91 " !!window.open('" + url
.spec() + "', '" + name
+ "'));",
96 class RedirectNotificationObserver
: public NotificationObserver
{
98 // Register to listen for notifications of the given type from either a
99 // specific source, or from all sources if |source| is
100 // NotificationService::AllSources().
101 RedirectNotificationObserver(int notification_type
,
102 const NotificationSource
& source
);
103 ~RedirectNotificationObserver() override
;
105 // Wait until the specified notification occurs. If the notification was
106 // emitted between the construction of this object and this call then it
107 // returns immediately.
110 // Returns NotificationService::AllSources() if we haven't observed a
112 const NotificationSource
& source() const {
116 const NotificationDetails
& details() const {
120 // NotificationObserver:
121 void Observe(int type
,
122 const NotificationSource
& source
,
123 const NotificationDetails
& details
) override
;
129 NotificationRegistrar registrar_
;
131 NotificationSource source_
;
132 NotificationDetails details_
;
133 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
135 DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver
);
138 RedirectNotificationObserver::RedirectNotificationObserver(
139 int notification_type
,
140 const NotificationSource
& source
)
143 source_(NotificationService::AllSources()) {
144 registrar_
.Add(this, notification_type
, source
);
147 RedirectNotificationObserver::~RedirectNotificationObserver() {}
149 void RedirectNotificationObserver::Wait() {
150 if (seen_
&& seen_twice_
)
154 message_loop_runner_
= new MessageLoopRunner
;
155 message_loop_runner_
->Run();
159 void RedirectNotificationObserver::Observe(
161 const NotificationSource
& source
,
162 const NotificationDetails
& details
) {
170 message_loop_runner_
->Quit();
174 // This observer keeps track of the number of created RenderFrameHosts. Tests
175 // can use this to ensure that a certain number of child frames has been
176 // created after navigating.
177 class RenderFrameHostCreatedObserver
: public WebContentsObserver
{
179 RenderFrameHostCreatedObserver(WebContents
* web_contents
,
180 int expected_frame_count
)
181 : WebContentsObserver(web_contents
),
182 expected_frame_count_(expected_frame_count
),
184 message_loop_runner_(new MessageLoopRunner
) {}
186 ~RenderFrameHostCreatedObserver() override
;
188 // Runs a nested message loop and blocks until the expected number of
189 // RenderFrameHosts is created.
193 // WebContentsObserver
194 void RenderFrameCreated(RenderFrameHost
* render_frame_host
) override
;
196 // The number of RenderFrameHosts to wait for.
197 int expected_frame_count_
;
199 // The number of RenderFrameHosts that have been created.
202 // The MessageLoopRunner used to spin the message loop.
203 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
205 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver
);
208 RenderFrameHostCreatedObserver::~RenderFrameHostCreatedObserver() {
211 void RenderFrameHostCreatedObserver::Wait() {
212 message_loop_runner_
->Run();
215 void RenderFrameHostCreatedObserver::RenderFrameCreated(
216 RenderFrameHost
* render_frame_host
) {
218 if (frames_created_
== expected_frame_count_
) {
219 message_loop_runner_
->Quit();
223 // A WebContentsDelegate that catches messages sent to the console.
224 class ConsoleObserverDelegate
: public WebContentsDelegate
{
226 ConsoleObserverDelegate(WebContents
* web_contents
, const std::string
& filter
)
227 : web_contents_(web_contents
),
230 message_loop_runner_(new MessageLoopRunner
) {}
232 ~ConsoleObserverDelegate() override
{}
234 bool AddMessageToConsole(WebContents
* source
,
236 const base::string16
& message
,
238 const base::string16
& source_id
) override
;
240 std::string
message() { return message_
; }
245 WebContents
* web_contents_
;
247 std::string message_
;
249 // The MessageLoopRunner used to spin the message loop.
250 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
252 DISALLOW_COPY_AND_ASSIGN(ConsoleObserverDelegate
);
255 void ConsoleObserverDelegate::Wait() {
256 message_loop_runner_
->Run();
259 bool ConsoleObserverDelegate::AddMessageToConsole(
262 const base::string16
& message
,
264 const base::string16
& source_id
) {
265 DCHECK(source
== web_contents_
);
267 std::string ascii_message
= base::UTF16ToASCII(message
);
268 if (base::MatchPattern(ascii_message
, filter_
)) {
269 message_
= ascii_message
;
270 message_loop_runner_
->Quit();
278 // SitePerProcessBrowserTest
281 SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
284 std::string
SitePerProcessBrowserTest::DepictFrameTree(FrameTreeNode
* node
) {
285 return visualizer_
.DepictFrameTree(node
);
288 void SitePerProcessBrowserTest::StartFrameAtDataURL() {
289 std::string data_url_script
=
290 "var iframes = document.getElementById('test');iframes.src="
291 "'data:text/html,dataurl';";
292 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script
));
295 void SitePerProcessBrowserTest::SetUpCommandLine(
296 base::CommandLine
* command_line
) {
297 IsolateAllSitesForTesting(command_line
);
300 void SitePerProcessBrowserTest::SetUpOnMainThread() {
301 host_resolver()->AddRule("*", "127.0.0.1");
302 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
303 SetupCrossSiteRedirector(embedded_test_server());
306 // Ensure that navigating subframes in --site-per-process mode works and the
307 // correct documents are committed.
308 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, CrossSiteIframe
) {
309 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
310 NavigateToURL(shell(), main_url
);
312 // It is safe to obtain the root frame tree node here, as it doesn't change.
313 FrameTreeNode
* root
=
314 static_cast<WebContentsImpl
*>(shell()->web_contents())->
315 GetFrameTree()->root();
317 TestNavigationObserver
observer(shell()->web_contents());
319 // Load same-site page into iframe.
320 FrameTreeNode
* child
= root
->child_at(0);
321 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
322 NavigateFrameToURL(child
, http_url
);
323 EXPECT_EQ(http_url
, observer
.last_navigation_url());
324 EXPECT_TRUE(observer
.last_navigation_succeeded());
326 // There should be only one RenderWidgetHost when there are no
327 // cross-process iframes.
328 std::set
<RenderWidgetHostView
*> views_set
=
329 static_cast<WebContentsImpl
*>(shell()->web_contents())
330 ->GetRenderWidgetHostViewsInTree();
331 EXPECT_EQ(1U, views_set
.size());
341 "Where A = http://127.0.0.1/",
342 DepictFrameTree(root
));
344 // Load cross-site page into iframe.
345 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
346 NavigateFrameToURL(root
->child_at(0), url
);
347 // Verify that the navigation succeeded and the expected URL was loaded.
348 EXPECT_TRUE(observer
.last_navigation_succeeded());
349 EXPECT_EQ(url
, observer
.last_navigation_url());
351 // Ensure that we have created a new process for the subframe.
352 ASSERT_EQ(2U, root
->child_count());
353 SiteInstance
* site_instance
= child
->current_frame_host()->GetSiteInstance();
354 RenderViewHost
* rvh
= child
->current_frame_host()->render_view_host();
355 RenderProcessHost
* rph
= child
->current_frame_host()->GetProcess();
356 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh
);
357 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance
);
358 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph
);
360 // There should be now two RenderWidgetHosts, one for each process
361 // rendering a frame.
362 std::set
<RenderWidgetHostView
*> views_set
=
363 static_cast<WebContentsImpl
*>(shell()->web_contents())
364 ->GetRenderWidgetHostViewsInTree();
365 EXPECT_EQ(2U, views_set
.size());
367 RenderFrameProxyHost
* proxy_to_parent
=
368 child
->render_manager()->GetProxyToParent();
369 EXPECT_TRUE(proxy_to_parent
);
370 EXPECT_TRUE(proxy_to_parent
->cross_process_frame_connector());
371 // The out-of-process iframe should have its own RenderWidgetHost,
372 // independent of any RenderViewHost.
375 proxy_to_parent
->cross_process_frame_connector()->get_view_for_testing());
376 EXPECT_TRUE(child
->current_frame_host()->GetRenderWidgetHost());
379 " Site A ------------ proxies for B\n"
380 " |--Site B ------- proxies for A\n"
381 " +--Site A ------- proxies for B\n"
382 " |--Site A -- proxies for B\n"
383 " +--Site A -- proxies for B\n"
384 " +--Site A -- proxies for B\n"
385 "Where A = http://127.0.0.1/\n"
386 " B = http://foo.com/",
387 DepictFrameTree(root
));
389 // Load another cross-site page into the same iframe.
390 url
= embedded_test_server()->GetURL("bar.com", "/title3.html");
391 NavigateFrameToURL(root
->child_at(0), url
);
392 EXPECT_TRUE(observer
.last_navigation_succeeded());
393 EXPECT_EQ(url
, observer
.last_navigation_url());
395 // Check again that a new process is created and is different from the
396 // top level one and the previous one.
397 ASSERT_EQ(2U, root
->child_count());
398 child
= root
->child_at(0);
399 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
400 child
->current_frame_host()->render_view_host());
401 EXPECT_NE(rvh
, child
->current_frame_host()->render_view_host());
402 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
403 child
->current_frame_host()->GetSiteInstance());
404 EXPECT_NE(site_instance
,
405 child
->current_frame_host()->GetSiteInstance());
406 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
407 child
->current_frame_host()->GetProcess());
408 EXPECT_NE(rph
, child
->current_frame_host()->GetProcess());
410 std::set
<RenderWidgetHostView
*> views_set
=
411 static_cast<WebContentsImpl
*>(shell()->web_contents())
412 ->GetRenderWidgetHostViewsInTree();
413 EXPECT_EQ(2U, views_set
.size());
415 EXPECT_EQ(proxy_to_parent
, child
->render_manager()->GetProxyToParent());
416 EXPECT_TRUE(proxy_to_parent
->cross_process_frame_connector());
418 child
->current_frame_host()->render_view_host()->GetView(),
419 proxy_to_parent
->cross_process_frame_connector()->get_view_for_testing());
420 EXPECT_TRUE(child
->current_frame_host()->GetRenderWidgetHost());
423 " Site A ------------ proxies for C\n"
424 " |--Site C ------- proxies for A\n"
425 " +--Site A ------- proxies for C\n"
426 " |--Site A -- proxies for C\n"
427 " +--Site A -- proxies for C\n"
428 " +--Site A -- proxies for C\n"
429 "Where A = http://127.0.0.1/\n"
430 " C = http://bar.com/",
431 DepictFrameTree(root
));
434 // Tests OOPIF rendering by checking that the RWH of the iframe generates
435 // OnSwapCompositorFrame message.
436 #if defined(OS_ANDROID)
437 // http://crbug.com/471850
438 #define MAYBE_CompositorFrameSwapped DISABLED_CompositorFrameSwapped
440 #define MAYBE_CompositorFrameSwapped CompositorFrameSwapped
442 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
443 MAYBE_CompositorFrameSwapped
) {
445 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
446 NavigateToURL(shell(), main_url
);
448 // It is safe to obtain the root frame tree node here, as it doesn't change.
449 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
452 ASSERT_EQ(1U, root
->child_count());
454 FrameTreeNode
* child_node
= root
->child_at(0);
455 GURL
site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
456 EXPECT_EQ(site_url
, child_node
->current_url());
457 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
458 child_node
->current_frame_host()->GetSiteInstance());
459 RenderWidgetHostViewBase
* rwhv_base
= static_cast<RenderWidgetHostViewBase
*>(
460 child_node
->current_frame_host()->GetRenderWidgetHost()->GetView());
462 // Wait for OnSwapCompositorFrame message.
463 while (rwhv_base
->RendererFrameNumber() <= 0) {
464 // TODO(lazyboy): Find a better way to avoid sleeping like this. See
465 // http://crbug.com/405282 for details.
466 base::RunLoop run_loop
;
467 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
468 FROM_HERE
, run_loop
.QuitClosure(),
469 base::TimeDelta::FromMilliseconds(10));
474 // Ensure that OOPIFs are deleted after navigating to a new main frame.
475 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, CleanupCrossSiteIframe
) {
476 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
477 NavigateToURL(shell(), main_url
);
479 // It is safe to obtain the root frame tree node here, as it doesn't change.
480 FrameTreeNode
* root
=
481 static_cast<WebContentsImpl
*>(shell()->web_contents())->
482 GetFrameTree()->root();
484 TestNavigationObserver
observer(shell()->web_contents());
486 // Load a cross-site page into both iframes.
487 GURL foo_url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
488 NavigateFrameToURL(root
->child_at(0), foo_url
);
489 EXPECT_TRUE(observer
.last_navigation_succeeded());
490 EXPECT_EQ(foo_url
, observer
.last_navigation_url());
491 NavigateFrameToURL(root
->child_at(1), foo_url
);
492 EXPECT_TRUE(observer
.last_navigation_succeeded());
493 EXPECT_EQ(foo_url
, observer
.last_navigation_url());
495 // Ensure that we have created a new process for the subframes.
497 " Site A ------------ proxies for B\n"
498 " |--Site B ------- proxies for A\n"
499 " +--Site B ------- proxies for A\n"
500 "Where A = http://127.0.0.1/\n"
501 " B = http://foo.com/",
502 DepictFrameTree(root
));
504 int subframe_process_id
= root
->child_at(0)
505 ->current_frame_host()
509 int subframe_rvh_id
= root
->child_at(0)
510 ->current_frame_host()
513 EXPECT_TRUE(RenderViewHost::FromID(subframe_process_id
, subframe_rvh_id
));
515 // Use Javascript in the parent to remove one of the frames and ensure that
516 // the subframe goes away.
517 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
518 "document.body.removeChild("
519 "document.querySelectorAll('iframe')[0])"));
520 ASSERT_EQ(1U, root
->child_count());
522 // Load a new same-site page in the top-level frame and ensure the other
523 // subframe goes away.
524 GURL
new_url(embedded_test_server()->GetURL("/title1.html"));
525 NavigateToURL(shell(), new_url
);
526 ASSERT_EQ(0U, root
->child_count());
528 // Ensure the RVH for the subframe gets cleaned up when the frame goes away.
529 EXPECT_FALSE(RenderViewHost::FromID(subframe_process_id
, subframe_rvh_id
));
532 // Ensure that root frames cannot be detached.
533 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, RestrictFrameDetach
) {
534 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
535 NavigateToURL(shell(), main_url
);
537 // It is safe to obtain the root frame tree node here, as it doesn't change.
538 FrameTreeNode
* root
=
539 static_cast<WebContentsImpl
*>(shell()->web_contents())->
540 GetFrameTree()->root();
542 TestNavigationObserver
observer(shell()->web_contents());
544 // Load cross-site pages into both iframes.
545 GURL foo_url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
546 NavigateFrameToURL(root
->child_at(0), foo_url
);
547 EXPECT_TRUE(observer
.last_navigation_succeeded());
548 EXPECT_EQ(foo_url
, observer
.last_navigation_url());
549 GURL bar_url
= embedded_test_server()->GetURL("bar.com", "/title2.html");
550 NavigateFrameToURL(root
->child_at(1), bar_url
);
551 EXPECT_TRUE(observer
.last_navigation_succeeded());
552 EXPECT_EQ(bar_url
, observer
.last_navigation_url());
554 // Ensure that we have created new processes for the subframes.
555 ASSERT_EQ(2U, root
->child_count());
556 FrameTreeNode
* foo_child
= root
->child_at(0);
557 SiteInstance
* foo_site_instance
=
558 foo_child
->current_frame_host()->GetSiteInstance();
559 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), foo_site_instance
);
560 FrameTreeNode
* bar_child
= root
->child_at(1);
561 SiteInstance
* bar_site_instance
=
562 bar_child
->current_frame_host()->GetSiteInstance();
563 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), bar_site_instance
);
566 " Site A ------------ proxies for B C\n"
567 " |--Site B ------- proxies for A C\n"
568 " +--Site C ------- proxies for A B\n"
569 "Where A = http://127.0.0.1/\n"
570 " B = http://foo.com/\n"
571 " C = http://bar.com/",
572 DepictFrameTree(root
));
574 // Simulate an attempt to detach the root frame from foo_site_instance. This
575 // should kill foo_site_instance's process.
576 RenderFrameProxyHost
* foo_mainframe_rfph
=
577 root
->render_manager()->GetRenderFrameProxyHost(foo_site_instance
);
578 content::RenderProcessHostWatcher
foo_terminated(
579 foo_mainframe_rfph
->GetProcess(),
580 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
581 FrameHostMsg_Detach
evil_msg2(foo_mainframe_rfph
->GetRoutingID());
582 IPC::IpcSecurityTestUtil::PwnMessageReceived(
583 foo_mainframe_rfph
->GetProcess()->GetChannel(), evil_msg2
);
584 foo_terminated
.Wait();
587 " Site A ------------ proxies for B C\n"
588 " |--Site B ------- proxies for A C\n"
589 " +--Site C ------- proxies for A B\n"
590 "Where A = http://127.0.0.1/\n"
591 " B = http://foo.com/ (no process)\n"
592 " C = http://bar.com/",
593 DepictFrameTree(root
));
596 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
597 NavigateRemoteFrame
) {
598 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
599 NavigateToURL(shell(), main_url
);
601 // It is safe to obtain the root frame tree node here, as it doesn't change.
602 FrameTreeNode
* root
=
603 static_cast<WebContentsImpl
*>(shell()->web_contents())->
604 GetFrameTree()->root();
606 TestNavigationObserver
observer(shell()->web_contents());
608 // Load same-site page into iframe.
609 FrameTreeNode
* child
= root
->child_at(0);
610 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
611 NavigateFrameToURL(child
, http_url
);
612 EXPECT_EQ(http_url
, observer
.last_navigation_url());
613 EXPECT_TRUE(observer
.last_navigation_succeeded());
615 // Load cross-site page into iframe.
616 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
617 NavigateFrameToURL(root
->child_at(0), url
);
618 EXPECT_TRUE(observer
.last_navigation_succeeded());
619 EXPECT_EQ(url
, observer
.last_navigation_url());
621 // Ensure that we have created a new process for the subframe.
622 ASSERT_EQ(2U, root
->child_count());
623 SiteInstance
* site_instance
= child
->current_frame_host()->GetSiteInstance();
624 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance
);
626 // Emulate the main frame changing the src of the iframe such that it
627 // navigates cross-site.
628 url
= embedded_test_server()->GetURL("bar.com", "/title3.html");
629 NavigateIframeToURL(shell()->web_contents(), "test", url
);
630 EXPECT_TRUE(observer
.last_navigation_succeeded());
631 EXPECT_EQ(url
, observer
.last_navigation_url());
633 // Check again that a new process is created and is different from the
634 // top level one and the previous one.
635 ASSERT_EQ(2U, root
->child_count());
636 child
= root
->child_at(0);
637 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
638 child
->current_frame_host()->GetSiteInstance());
639 EXPECT_NE(site_instance
,
640 child
->current_frame_host()->GetSiteInstance());
642 // Navigate back to the parent's origin and ensure we return to the
644 NavigateFrameToURL(child
, http_url
);
645 EXPECT_EQ(http_url
, observer
.last_navigation_url());
646 EXPECT_TRUE(observer
.last_navigation_succeeded());
647 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
648 child
->current_frame_host()->GetSiteInstance());
652 // http://crbug.com/465722
653 #define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
654 DISABLED_NavigateRemoteFrameToBlankAndDataURLs
656 #define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
657 NavigateRemoteFrameToBlankAndDataURLs
660 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
661 MAYBE_NavigateRemoteFrameToBlankAndDataURLs
) {
662 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
663 NavigateToURL(shell(), main_url
);
665 // It is safe to obtain the root frame tree node here, as it doesn't change.
666 FrameTreeNode
* root
=
667 static_cast<WebContentsImpl
*>(shell()->web_contents())->
668 GetFrameTree()->root();
670 TestNavigationObserver
observer(shell()->web_contents());
672 // Load same-site page into iframe.
673 FrameTreeNode
* child
= root
->child_at(0);
674 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
675 NavigateFrameToURL(child
, http_url
);
676 EXPECT_EQ(http_url
, observer
.last_navigation_url());
677 EXPECT_TRUE(observer
.last_navigation_succeeded());
679 // Load cross-site page into iframe.
680 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
681 NavigateFrameToURL(root
->child_at(0), url
);
682 EXPECT_TRUE(observer
.last_navigation_succeeded());
683 EXPECT_EQ(url
, observer
.last_navigation_url());
684 ASSERT_EQ(2U, root
->child_count());
685 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
686 root
->child_at(0)->current_frame_host()->GetSiteInstance());
688 // Navigate iframe to a data URL. The navigation happens from a script in the
689 // parent frame, so the data URL should be committed in the same SiteInstance
690 // as the parent frame.
691 GURL
data_url("data:text/html,dataurl");
692 NavigateIframeToURL(shell()->web_contents(), "test", data_url
);
693 EXPECT_TRUE(observer
.last_navigation_succeeded());
694 EXPECT_EQ(data_url
, observer
.last_navigation_url());
696 // Ensure that we have navigated using the top level process.
697 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
698 root
->child_at(0)->current_frame_host()->GetSiteInstance());
700 // Load cross-site page into iframe.
701 url
= embedded_test_server()->GetURL("bar.com", "/title2.html");
702 NavigateFrameToURL(root
->child_at(0), url
);
703 EXPECT_TRUE(observer
.last_navigation_succeeded());
704 EXPECT_EQ(url
, observer
.last_navigation_url());
705 ASSERT_EQ(2U, root
->child_count());
706 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
707 root
->child_at(0)->current_frame_host()->GetSiteInstance());
709 // Navigate iframe to about:blank. The navigation happens from a script in the
710 // parent frame, so it should be committed in the same SiteInstance as the
712 GURL
about_blank_url("about:blank");
713 NavigateIframeToURL(shell()->web_contents(), "test", about_blank_url
);
714 EXPECT_TRUE(observer
.last_navigation_succeeded());
715 EXPECT_EQ(about_blank_url
, observer
.last_navigation_url());
717 // Ensure that we have navigated using the top level process.
718 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
719 root
->child_at(0)->current_frame_host()->GetSiteInstance());
722 // This test checks that killing a renderer process of a remote frame
723 // and then navigating some other frame to the same SiteInstance of the killed
724 // process works properly.
725 // This can be illustrated as follows,
726 // where 1/2/3 are FrameTreeNode-s and A/B are processes and B* is the killed
730 // / \ -> / \ -> Kill B -> / \ -> Navigate 3 to B -> / \ .
733 // Initially, node1.proxy_hosts_ = {B}
734 // After we kill B, we make sure B stays in node1.proxy_hosts_, then we navigate
735 // 3 to B and we expect that to complete normally.
736 // See http://crbug.com/432107.
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 NavigateRemoteFrameToKilledProcess
) {
742 GURL
main_url(embedded_test_server()->GetURL(
743 "/frame_tree/page_with_two_frames.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();
751 TestNavigationObserver
observer(shell()->web_contents());
752 ASSERT_EQ(2U, root
->child_count());
754 // Make sure node2 points to the correct cross-site page.
755 GURL site_b_url
= embedded_test_server()->GetURL("bar.com", "/title1.html");
756 FrameTreeNode
* node2
= root
->child_at(0);
757 EXPECT_EQ(site_b_url
, node2
->current_url());
759 // Kill that cross-site renderer.
760 RenderProcessHost
* child_process
=
761 node2
->current_frame_host()->GetProcess();
762 RenderProcessHostWatcher
crash_observer(
763 child_process
, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
764 child_process
->Shutdown(0, false);
765 crash_observer
.Wait();
767 // Now navigate the second iframe (node3) to the same site as the node2.
768 FrameTreeNode
* node3
= root
->child_at(1);
769 NavigateFrameToURL(node3
, site_b_url
);
770 EXPECT_TRUE(observer
.last_navigation_succeeded());
771 EXPECT_EQ(site_b_url
, observer
.last_navigation_url());
774 // This test is similar to
775 // SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess with
776 // addition that node2 also has a cross-origin frame to site C.
780 // 2 3 -> B A -> Kill B -> B* A -> Navigate 3 -> B* B
784 // Initially, node1.proxy_hosts_ = {B, C}
785 // After we kill B, we make sure B stays in node1.proxy_hosts_, but
786 // C gets cleared from node1.proxy_hosts_.
788 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
789 // site B and stays in not rendered state.
790 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
791 NavigateRemoteFrameToKilledProcessWithSubtree
) {
792 GURL
main_url(embedded_test_server()->GetURL(
793 "a.com", "/frame_tree/page_with_two_frames_nested.html"));
794 NavigateToURL(shell(), main_url
);
796 // It is safe to obtain the root frame tree node here, as it doesn't change.
797 FrameTreeNode
* root
=
798 static_cast<WebContentsImpl
*>(shell()->web_contents())->
799 GetFrameTree()->root();
800 TestNavigationObserver
observer(shell()->web_contents());
802 ASSERT_EQ(2U, root
->child_count());
805 embedded_test_server()->GetURL(
806 "bar.com", "/frame_tree/page_with_one_frame.html"));
807 // We can't use a TestNavigationObserver to verify the URL here,
808 // since the frame has children that may have clobbered it in the observer.
809 EXPECT_EQ(site_b_url
, root
->child_at(0)->current_url());
811 // Ensure that a new process is created for node2.
812 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
813 root
->child_at(0)->current_frame_host()->GetSiteInstance());
814 // Ensure that a new process is *not* created for node3.
815 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
816 root
->child_at(1)->current_frame_host()->GetSiteInstance());
818 ASSERT_EQ(1U, root
->child_at(0)->child_count());
820 // Make sure node4 points to the correct cross-site page.
821 FrameTreeNode
* node4
= root
->child_at(0)->child_at(0);
822 GURL
site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
823 EXPECT_EQ(site_c_url
, node4
->current_url());
825 // |site_instance_c| is expected to go away once we kill |child_process_b|
826 // below, so create a local scope so we can extend the lifetime of
827 // |site_instance_c| with a refptr.
829 // Initially each frame has proxies for the other sites.
831 " Site A ------------ proxies for B C\n"
832 " |--Site B ------- proxies for A C\n"
833 " | +--Site C -- proxies for A B\n"
834 " +--Site A ------- proxies for B C\n"
835 "Where A = http://a.com/\n"
836 " B = http://bar.com/\n"
837 " C = http://baz.com/",
838 DepictFrameTree(root
));
840 // Kill the render process for Site B.
841 RenderProcessHost
* child_process_b
=
842 root
->child_at(0)->current_frame_host()->GetProcess();
843 RenderProcessHostWatcher
crash_observer(
844 child_process_b
, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
845 child_process_b
->Shutdown(0, false);
846 crash_observer
.Wait();
848 // The Site C frame (a child of the crashed Site B frame) should go away,
849 // and there should be no remaining proxies for site C anywhere.
851 " Site A ------------ proxies for B\n"
852 " |--Site B ------- proxies for A\n"
853 " +--Site A ------- proxies for B\n"
854 "Where A = http://a.com/\n"
855 " B = http://bar.com/ (no process)",
856 DepictFrameTree(root
));
859 // Now navigate the second iframe (node3) to Site B also.
860 FrameTreeNode
* node3
= root
->child_at(1);
861 GURL url
= embedded_test_server()->GetURL("bar.com", "/title1.html");
862 NavigateFrameToURL(node3
, url
);
863 EXPECT_TRUE(observer
.last_navigation_succeeded());
864 EXPECT_EQ(url
, observer
.last_navigation_url());
867 " Site A ------------ proxies for B\n"
868 " |--Site B ------- proxies for A\n"
869 " +--Site B ------- proxies for A\n"
870 "Where A = http://a.com/\n"
871 " B = http://bar.com/",
872 DepictFrameTree(root
));
875 // Verify that killing a cross-site frame's process B and then navigating a
876 // frame to B correctly recreates all proxies in B.
879 // / | \ / | \ / | \ / | \ .
880 // 2 3 4 -> B A A -> Kill B -> B* A A -> B* B A
882 // After the last step, the test sends a postMessage from node 3 to node 4,
883 // verifying that a proxy for node 4 has been recreated in process B. This
884 // verifies the fix for https://crbug.com/478892.
885 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
886 NavigatingToKilledProcessRestoresAllProxies
) {
887 // Navigate to a page with three frames: one cross-site and two same-site.
888 GURL
main_url(embedded_test_server()->GetURL(
889 "a.com", "/frame_tree/page_with_three_frames.html"));
890 NavigateToURL(shell(), main_url
);
892 // It is safe to obtain the root frame tree node here, as it doesn't change.
893 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
896 TestNavigationObserver
observer(shell()->web_contents());
899 " Site A ------------ proxies for B\n"
900 " |--Site B ------- proxies for A\n"
901 " |--Site A ------- proxies for B\n"
902 " +--Site A ------- proxies for B\n"
903 "Where A = http://a.com/\n"
904 " B = http://b.com/",
905 DepictFrameTree(root
));
907 // Kill the first subframe's b.com renderer.
908 RenderProcessHost
* child_process
=
909 root
->child_at(0)->current_frame_host()->GetProcess();
910 RenderProcessHostWatcher
crash_observer(
911 child_process
, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
912 child_process
->Shutdown(0, false);
913 crash_observer
.Wait();
915 // Navigate the second subframe to b.com to recreate the b.com process.
916 GURL b_url
= embedded_test_server()->GetURL("b.com", "/post_message.html");
917 NavigateFrameToURL(root
->child_at(1), b_url
);
918 // TODO(alexmos): This can be removed once TestFrameNavigationObserver is
919 // fixed to use DidFinishLoad.
921 WaitForRenderFrameReady(root
->child_at(1)->current_frame_host()));
922 EXPECT_TRUE(observer
.last_navigation_succeeded());
923 EXPECT_EQ(b_url
, observer
.last_navigation_url());
924 EXPECT_TRUE(root
->child_at(1)->current_frame_host()->IsRenderFrameLive());
927 " Site A ------------ proxies for B\n"
928 " |--Site B ------- proxies for A\n"
929 " |--Site B ------- proxies for A\n"
930 " +--Site A ------- proxies for B\n"
931 "Where A = http://a.com/\n"
932 " B = http://b.com/",
933 DepictFrameTree(root
));
935 // Check that third subframe's proxy is available in the b.com process by
936 // sending it a postMessage from second subframe, and waiting for a reply.
937 PostMessageAndWaitForReply(root
->child_at(1),
938 "postToSibling('subframe-msg','frame3')",
942 // Verify that proxy creation doesn't recreate a crashed process if no frame
943 // will be created in it.
946 // / | \ / | \ / | \ / | \ .
947 // 2 3 4 -> B A A -> Kill B -> B* A A -> B* A A
951 // The test kills process B (node 2), creates a child frame of node 4 in
952 // process A, and then checks that process B isn't resurrected to create a
953 // proxy for the new child frame. See https://crbug.com/476846.
954 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
955 CreateChildFrameAfterKillingProcess
) {
956 // Navigate to a page with three frames: one cross-site and two same-site.
957 GURL
main_url(embedded_test_server()->GetURL(
958 "a.com", "/frame_tree/page_with_three_frames.html"));
959 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
961 // It is safe to obtain the root frame tree node here, as it doesn't change.
962 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
967 " Site A ------------ proxies for B\n"
968 " |--Site B ------- proxies for A\n"
969 " |--Site A ------- proxies for B\n"
970 " +--Site A ------- proxies for B\n"
971 "Where A = http://a.com/\n"
972 " B = http://b.com/",
973 DepictFrameTree(root
));
974 SiteInstance
* b_site_instance
=
975 root
->child_at(0)->current_frame_host()->GetSiteInstance();
977 // Kill the first subframe's renderer (B).
978 RenderProcessHost
* child_process
=
979 root
->child_at(0)->current_frame_host()->GetProcess();
980 RenderProcessHostWatcher
crash_observer(
981 child_process
, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
982 child_process
->Shutdown(0, false);
983 crash_observer
.Wait();
985 // Add a new child frame to the third subframe.
986 RenderFrameHostCreatedObserver
frame_observer(shell()->web_contents(), 1);
987 EXPECT_TRUE(ExecuteScript(
988 root
->child_at(2)->current_frame_host(),
989 "document.body.appendChild(document.createElement('iframe'));"));
990 frame_observer
.Wait();
992 // The new frame should have a RenderFrameProxyHost for B, but it should not
993 // be alive, and B should still not have a process (verified by last line of
994 // expected DepictFrameTree output).
996 " Site A ------------ proxies for B\n"
997 " |--Site B ------- proxies for A\n"
998 " |--Site A ------- proxies for B\n"
999 " +--Site A ------- proxies for B\n"
1000 " +--Site A -- proxies for B\n"
1001 "Where A = http://a.com/\n"
1002 " B = http://b.com/ (no process)",
1003 DepictFrameTree(root
));
1004 FrameTreeNode
* grandchild
= root
->child_at(2)->child_at(0);
1005 RenderFrameProxyHost
* grandchild_rfph
=
1006 grandchild
->render_manager()->GetRenderFrameProxyHost(b_site_instance
);
1007 EXPECT_FALSE(grandchild_rfph
->is_render_frame_proxy_live());
1009 // Navigate the second subframe to b.com to recreate process B.
1010 TestNavigationObserver
observer(shell()->web_contents());
1011 GURL b_url
= embedded_test_server()->GetURL("b.com", "/title1.html");
1012 NavigateFrameToURL(root
->child_at(1), b_url
);
1013 EXPECT_TRUE(observer
.last_navigation_succeeded());
1014 EXPECT_EQ(b_url
, observer
.last_navigation_url());
1016 // Ensure that the grandchild RenderFrameProxy in B was created when process
1018 EXPECT_TRUE(grandchild_rfph
->is_render_frame_proxy_live());
1021 // Verify that creating a child frame after killing and reloading an opener
1022 // process doesn't crash. See https://crbug.com/501152.
1023 // 1. Navigate to site A.
1024 // 2. Open a popup with window.open and navigate it cross-process to site B.
1025 // 3. Kill process A for the original tab.
1026 // 4. Reload the original tab to resurrect process A.
1027 // 5. Add a child frame to the top-level frame in the popup tab B.
1028 // In step 5, we try to create proxies for the child frame in all SiteInstances
1029 // for which its parent has proxies. This includes A. However, even though
1030 // process A is live (step 4), the parent proxy in A is not live (which was
1031 // incorrectly assumed previously). This is because step 4 does not resurrect
1032 // proxies for popups opened before the crash.
1033 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
1034 CreateChildFrameAfterKillingOpener
) {
1035 GURL
main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
1036 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1038 // It is safe to obtain the root frame tree node here, as it doesn't change.
1039 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1042 SiteInstance
* site_instance_a
= root
->current_frame_host()->GetSiteInstance();
1044 // Open a popup and navigate it cross-process to b.com.
1045 ShellAddedObserver new_shell_observer
;
1046 EXPECT_TRUE(ExecuteScript(root
->current_frame_host(),
1047 "popup = window.open('about:blank');"));
1048 Shell
* popup
= new_shell_observer
.GetShell();
1049 GURL
popup_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
1050 EXPECT_TRUE(NavigateToURL(popup
, popup_url
));
1052 // Verify that each top-level frame has proxies in the other's SiteInstance.
1053 FrameTreeNode
* popup_root
=
1054 static_cast<WebContentsImpl
*>(popup
->web_contents())
1058 " Site A ------------ proxies for B\n"
1059 "Where A = http://a.com/\n"
1060 " B = http://b.com/",
1061 DepictFrameTree(root
));
1063 " Site B ------------ proxies for A\n"
1064 "Where A = http://a.com/\n"
1065 " B = http://b.com/",
1066 DepictFrameTree(popup_root
));
1068 // Kill the first window's renderer (a.com).
1069 RenderProcessHost
* child_process
= root
->current_frame_host()->GetProcess();
1070 RenderProcessHostWatcher
crash_observer(
1071 child_process
, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1072 child_process
->Shutdown(0, false);
1073 crash_observer
.Wait();
1074 EXPECT_FALSE(root
->current_frame_host()->IsRenderFrameLive());
1076 // The proxy for the popup in a.com should've died.
1077 RenderFrameProxyHost
* rfph
=
1078 popup_root
->render_manager()->GetRenderFrameProxyHost(site_instance_a
);
1079 EXPECT_FALSE(rfph
->is_render_frame_proxy_live());
1081 // Recreate the a.com renderer.
1082 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1083 EXPECT_TRUE(root
->current_frame_host()->IsRenderFrameLive());
1085 // The popup's proxy in a.com should still not be live. Re-navigating the
1086 // main window to a.com doesn't reinitialize a.com proxies for popups
1087 // previously opened from the main window.
1088 EXPECT_FALSE(rfph
->is_render_frame_proxy_live());
1090 // Add a new child frame on the popup.
1091 RenderFrameHostCreatedObserver
frame_observer(popup
->web_contents(), 1);
1092 EXPECT_TRUE(ExecuteScript(
1093 popup
->web_contents(),
1094 "document.body.appendChild(document.createElement('iframe'));"));
1095 frame_observer
.Wait();
1097 // Both the child frame's and its parent's proxies should still not be live.
1098 // The main page can't reach them since it lost reference to the popup after
1099 // it crashed, so there is no need to create them.
1100 EXPECT_FALSE(rfph
->is_render_frame_proxy_live());
1101 RenderFrameProxyHost
* child_rfph
=
1102 popup_root
->child_at(0)->render_manager()->GetRenderFrameProxyHost(
1104 EXPECT_TRUE(child_rfph
);
1105 EXPECT_FALSE(child_rfph
->is_render_frame_proxy_live());
1108 // In A-embed-B-embed-C scenario, verify that killing process B clears proxies
1109 // of C from the tree.
1113 // 2 3 -> B A -> Kill B -> B* A
1117 // node1 is the root.
1118 // Initially, both node1.proxy_hosts_ and node3.proxy_hosts_ contain C.
1119 // After we kill B, make sure proxies for C are cleared.
1120 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
1121 KillingRendererClearsDescendantProxies
) {
1122 GURL
main_url(embedded_test_server()->GetURL(
1123 "a.com", "/frame_tree/page_with_two_frames_nested.html"));
1124 NavigateToURL(shell(), main_url
);
1126 // It is safe to obtain the root frame tree node here, as it doesn't change.
1127 FrameTreeNode
* root
=
1128 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1129 GetFrameTree()->root();
1130 ASSERT_EQ(2U, root
->child_count());
1133 embedded_test_server()->GetURL(
1134 "bar.com", "/frame_tree/page_with_one_frame.html"));
1135 // We can't use a TestNavigationObserver to verify the URL here,
1136 // since the frame has children that may have clobbered it in the observer.
1137 EXPECT_EQ(site_b_url
, root
->child_at(0)->current_url());
1139 // Ensure that a new process is created for node2.
1140 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1141 root
->child_at(0)->current_frame_host()->GetSiteInstance());
1142 // Ensure that a new process is *not* created for node3.
1143 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
1144 root
->child_at(1)->current_frame_host()->GetSiteInstance());
1146 ASSERT_EQ(1U, root
->child_at(0)->child_count());
1148 // Make sure node4 points to the correct cross-site-page.
1149 FrameTreeNode
* node4
= root
->child_at(0)->child_at(0);
1150 GURL
site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
1151 EXPECT_EQ(site_c_url
, node4
->current_url());
1153 // |site_instance_c|'s frames and proxies are expected to go away once we kill
1154 // |child_process_b| below.
1155 scoped_refptr
<SiteInstanceImpl
> site_instance_c
=
1156 node4
->current_frame_host()->GetSiteInstance();
1158 // Initially proxies for both B and C will be present in the root.
1160 " Site A ------------ proxies for B C\n"
1161 " |--Site B ------- proxies for A C\n"
1162 " | +--Site C -- proxies for A B\n"
1163 " +--Site A ------- proxies for B C\n"
1164 "Where A = http://a.com/\n"
1165 " B = http://bar.com/\n"
1166 " C = http://baz.com/",
1167 DepictFrameTree(root
));
1169 EXPECT_GT(site_instance_c
->active_frame_count(), 0U);
1172 RenderProcessHost
* child_process_b
=
1173 root
->child_at(0)->current_frame_host()->GetProcess();
1174 RenderProcessHostWatcher
crash_observer(
1175 child_process_b
, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1176 child_process_b
->Shutdown(0, false);
1177 crash_observer
.Wait();
1179 // Make sure proxy C has gone from root.
1180 // Make sure proxy C has gone from node3 as well.
1181 // Make sure proxy B stays around in root and node3.
1183 " Site A ------------ proxies for B\n"
1184 " |--Site B ------- proxies for A\n"
1185 " +--Site A ------- proxies for B\n"
1186 "Where A = http://a.com/\n"
1187 " B = http://bar.com/ (no process)",
1188 DepictFrameTree(root
));
1190 EXPECT_EQ(0U, site_instance_c
->active_frame_count());
1193 // Crash a subframe and ensures its children are cleared from the FrameTree.
1194 // See http://crbug.com/338508.
1195 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, CrashSubframe
) {
1196 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1197 NavigateToURL(shell(), main_url
);
1199 StartFrameAtDataURL();
1201 // Load cross-site page into iframe.
1202 EXPECT_TRUE(NavigateIframeToURL(
1203 shell()->web_contents(), "test",
1204 embedded_test_server()->GetURL("/cross-site/foo.com/title2.html")));
1206 // Check the subframe process.
1207 FrameTreeNode
* root
=
1208 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1209 GetFrameTree()->root();
1210 ASSERT_EQ(2U, root
->child_count());
1211 FrameTreeNode
* child
= root
->child_at(0);
1212 EXPECT_EQ(main_url
, root
->current_url());
1213 EXPECT_EQ("foo.com", child
->current_url().host());
1214 EXPECT_EQ("/title2.html", child
->current_url().path());
1217 child
->current_frame_host()->render_view_host()->IsRenderViewLive());
1218 EXPECT_TRUE(child
->current_frame_host()->IsRenderFrameLive());
1220 // Crash the subframe process.
1221 RenderProcessHost
* root_process
= root
->current_frame_host()->GetProcess();
1222 RenderProcessHost
* child_process
= child
->current_frame_host()->GetProcess();
1224 RenderProcessHostWatcher
crash_observer(
1226 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1227 child_process
->Shutdown(0, false);
1228 crash_observer
.Wait();
1231 // Ensure that the child frame still exists but has been cleared.
1232 EXPECT_EQ(2U, root
->child_count());
1233 EXPECT_EQ(main_url
, root
->current_url());
1234 EXPECT_EQ(GURL(), child
->current_url());
1237 child
->current_frame_host()->render_view_host()->IsRenderViewLive());
1238 EXPECT_FALSE(child
->current_frame_host()->IsRenderFrameLive());
1239 EXPECT_FALSE(child
->current_frame_host()->render_frame_created_
);
1241 // Now crash the top-level page to clear the child frame.
1243 RenderProcessHostWatcher
crash_observer(
1245 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
1246 root_process
->Shutdown(0, false);
1247 crash_observer
.Wait();
1249 EXPECT_EQ(0U, root
->child_count());
1250 EXPECT_EQ(GURL(), root
->current_url());
1253 // When a new subframe is added, related SiteInstances that can reach the
1254 // subframe should create proxies for it (https://crbug.com/423587). This test
1255 // checks that if A embeds B and later adds a new subframe A2, A2 gets a proxy
1257 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, CreateProxiesForNewFrames
) {
1258 GURL
main_url(embedded_test_server()->GetURL(
1259 "b.com", "/frame_tree/page_with_one_frame.html"));
1260 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1262 // It is safe to obtain the root frame tree node here, as it doesn't change.
1263 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1266 ASSERT_EQ(1U, root
->child_count());
1268 // Make sure the frame starts out at the correct cross-site URL.
1269 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
1270 root
->child_at(0)->current_url());
1273 " Site A ------------ proxies for B\n"
1274 " +--Site B ------- proxies for A\n"
1275 "Where A = http://b.com/\n"
1276 " B = http://baz.com/",
1277 DepictFrameTree(root
));
1279 // Add a new child frame to the top-level frame.
1280 RenderFrameHostCreatedObserver
frame_observer(shell()->web_contents(), 1);
1281 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1282 "window.domAutomationController.send("
1283 " addFrame('data:text/html,foo'));"));
1284 frame_observer
.Wait();
1286 // The new frame should have a proxy in Site B, for use by the old frame.
1288 " Site A ------------ proxies for B\n"
1289 " |--Site B ------- proxies for A\n"
1290 " +--Site A ------- proxies for B\n"
1291 "Where A = http://b.com/\n"
1292 " B = http://baz.com/",
1293 DepictFrameTree(root
));
1296 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
1297 // security checks are back in place.
1298 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
1299 // on Android (http://crbug.com/187570).
1300 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
1301 DISABLED_CrossSiteIframeRedirectOnce
) {
1302 ASSERT_TRUE(test_server()->Start());
1303 net::SpawnedTestServer
https_server(
1304 net::SpawnedTestServer::TYPE_HTTPS
,
1305 net::SpawnedTestServer::kLocalhost
,
1306 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1307 ASSERT_TRUE(https_server
.Start());
1309 GURL
main_url(test_server()->GetURL("files/site_per_process_main.html"));
1310 GURL
http_url(test_server()->GetURL("files/title1.html"));
1311 GURL
https_url(https_server
.GetURL("files/title1.html"));
1313 NavigateToURL(shell(), main_url
);
1315 TestNavigationObserver
observer(shell()->web_contents());
1317 // Load cross-site client-redirect page into Iframe.
1318 // Should be blocked.
1319 GURL
client_redirect_https_url(https_server
.GetURL(
1320 "client-redirect?files/title1.html"));
1321 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1322 client_redirect_https_url
));
1323 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
1324 EXPECT_EQ(observer
.last_navigation_url(), client_redirect_https_url
);
1325 EXPECT_FALSE(observer
.last_navigation_succeeded());
1329 // Load cross-site server-redirect page into Iframe,
1330 // which redirects to same-site page.
1331 GURL
server_redirect_http_url(https_server
.GetURL(
1332 "server-redirect?" + http_url
.spec()));
1333 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1334 server_redirect_http_url
));
1335 EXPECT_EQ(observer
.last_navigation_url(), http_url
);
1336 EXPECT_TRUE(observer
.last_navigation_succeeded());
1340 // Load cross-site server-redirect page into Iframe,
1341 // which redirects to cross-site page.
1342 GURL
server_redirect_http_url(https_server
.GetURL(
1343 "server-redirect?files/title1.html"));
1344 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1345 server_redirect_http_url
));
1346 // DidFailProvisionalLoad when navigating to https_url.
1347 EXPECT_EQ(observer
.last_navigation_url(), https_url
);
1348 EXPECT_FALSE(observer
.last_navigation_succeeded());
1352 // Load same-site server-redirect page into Iframe,
1353 // which redirects to cross-site page.
1354 GURL
server_redirect_http_url(test_server()->GetURL(
1355 "server-redirect?" + https_url
.spec()));
1356 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1357 server_redirect_http_url
));
1359 EXPECT_EQ(observer
.last_navigation_url(), https_url
);
1360 EXPECT_FALSE(observer
.last_navigation_succeeded());
1364 // Load same-site client-redirect page into Iframe,
1365 // which redirects to cross-site page.
1366 GURL
client_redirect_http_url(test_server()->GetURL(
1367 "client-redirect?" + https_url
.spec()));
1369 RedirectNotificationObserver
load_observer2(
1370 NOTIFICATION_LOAD_STOP
,
1371 Source
<NavigationController
>(
1372 &shell()->web_contents()->GetController()));
1374 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1375 client_redirect_http_url
));
1377 // Same-site Client-Redirect Page should be loaded successfully.
1378 EXPECT_EQ(observer
.last_navigation_url(), client_redirect_http_url
);
1379 EXPECT_TRUE(observer
.last_navigation_succeeded());
1381 // Redirecting to Cross-site Page should be blocked.
1382 load_observer2
.Wait();
1383 EXPECT_EQ(observer
.last_navigation_url(), https_url
);
1384 EXPECT_FALSE(observer
.last_navigation_succeeded());
1388 // Load same-site server-redirect page into Iframe,
1389 // which redirects to same-site page.
1390 GURL
server_redirect_http_url(test_server()->GetURL(
1391 "server-redirect?files/title1.html"));
1392 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1393 server_redirect_http_url
));
1394 EXPECT_EQ(observer
.last_navigation_url(), http_url
);
1395 EXPECT_TRUE(observer
.last_navigation_succeeded());
1399 // Load same-site client-redirect page into Iframe,
1400 // which redirects to same-site page.
1401 GURL
client_redirect_http_url(test_server()->GetURL(
1402 "client-redirect?" + http_url
.spec()));
1403 RedirectNotificationObserver
load_observer2(
1404 NOTIFICATION_LOAD_STOP
,
1405 Source
<NavigationController
>(
1406 &shell()->web_contents()->GetController()));
1408 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1409 client_redirect_http_url
));
1411 // Same-site Client-Redirect Page should be loaded successfully.
1412 EXPECT_EQ(observer
.last_navigation_url(), client_redirect_http_url
);
1413 EXPECT_TRUE(observer
.last_navigation_succeeded());
1415 // Redirecting to Same-site Page should be loaded successfully.
1416 load_observer2
.Wait();
1417 EXPECT_EQ(observer
.last_navigation_url(), http_url
);
1418 EXPECT_TRUE(observer
.last_navigation_succeeded());
1422 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
1423 // security checks are back in place.
1424 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
1425 // on Android (http://crbug.com/187570).
1426 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
1427 DISABLED_CrossSiteIframeRedirectTwice
) {
1428 ASSERT_TRUE(test_server()->Start());
1429 net::SpawnedTestServer
https_server(
1430 net::SpawnedTestServer::TYPE_HTTPS
,
1431 net::SpawnedTestServer::kLocalhost
,
1432 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1433 ASSERT_TRUE(https_server
.Start());
1435 GURL
main_url(test_server()->GetURL("files/site_per_process_main.html"));
1436 GURL
http_url(test_server()->GetURL("files/title1.html"));
1437 GURL
https_url(https_server
.GetURL("files/title1.html"));
1439 NavigateToURL(shell(), main_url
);
1441 TestNavigationObserver
observer(shell()->web_contents());
1443 // Load client-redirect page pointing to a cross-site client-redirect page,
1444 // which eventually redirects back to same-site page.
1445 GURL
client_redirect_https_url(https_server
.GetURL(
1446 "client-redirect?" + http_url
.spec()));
1447 GURL
client_redirect_http_url(test_server()->GetURL(
1448 "client-redirect?" + client_redirect_https_url
.spec()));
1450 // We should wait until second client redirect get cancelled.
1451 RedirectNotificationObserver
load_observer2(
1452 NOTIFICATION_LOAD_STOP
,
1453 Source
<NavigationController
>(
1454 &shell()->web_contents()->GetController()));
1456 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1457 client_redirect_http_url
));
1459 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
1460 load_observer2
.Wait();
1461 EXPECT_EQ(observer
.last_navigation_url(), client_redirect_https_url
);
1462 EXPECT_FALSE(observer
.last_navigation_succeeded());
1466 // Load server-redirect page pointing to a cross-site server-redirect page,
1467 // which eventually redirect back to same-site page.
1468 GURL
server_redirect_https_url(https_server
.GetURL(
1469 "server-redirect?" + http_url
.spec()));
1470 GURL
server_redirect_http_url(test_server()->GetURL(
1471 "server-redirect?" + server_redirect_https_url
.spec()));
1472 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1473 server_redirect_http_url
));
1474 EXPECT_EQ(observer
.last_navigation_url(), http_url
);
1475 EXPECT_TRUE(observer
.last_navigation_succeeded());
1479 // Load server-redirect page pointing to a cross-site server-redirect page,
1480 // which eventually redirects back to cross-site page.
1481 GURL
server_redirect_https_url(https_server
.GetURL(
1482 "server-redirect?" + https_url
.spec()));
1483 GURL
server_redirect_http_url(test_server()->GetURL(
1484 "server-redirect?" + server_redirect_https_url
.spec()));
1485 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1486 server_redirect_http_url
));
1488 // DidFailProvisionalLoad when navigating to https_url.
1489 EXPECT_EQ(observer
.last_navigation_url(), https_url
);
1490 EXPECT_FALSE(observer
.last_navigation_succeeded());
1494 // Load server-redirect page pointing to a cross-site client-redirect page,
1495 // which eventually redirects back to same-site page.
1496 GURL
client_redirect_http_url(https_server
.GetURL(
1497 "client-redirect?" + http_url
.spec()));
1498 GURL
server_redirect_http_url(test_server()->GetURL(
1499 "server-redirect?" + client_redirect_http_url
.spec()));
1500 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1501 server_redirect_http_url
));
1503 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
1504 EXPECT_EQ(observer
.last_navigation_url(), client_redirect_http_url
);
1505 EXPECT_FALSE(observer
.last_navigation_succeeded());
1509 // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
1510 // created in the FrameTree skipping the subtree of the navigating frame.
1511 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
1512 ProxyCreationSkipsSubtree
) {
1513 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1514 NavigateToURL(shell(), main_url
);
1516 // It is safe to obtain the root frame tree node here, as it doesn't change.
1517 FrameTreeNode
* root
=
1518 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1519 GetFrameTree()->root();
1521 EXPECT_TRUE(root
->child_at(1) != NULL
);
1522 EXPECT_EQ(2U, root
->child_at(1)->child_count());
1525 // Load same-site page into iframe.
1526 TestNavigationObserver
observer(shell()->web_contents());
1527 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
1528 NavigateFrameToURL(root
->child_at(0), http_url
);
1529 EXPECT_EQ(http_url
, observer
.last_navigation_url());
1530 EXPECT_TRUE(observer
.last_navigation_succeeded());
1538 "Where A = http://127.0.0.1/",
1539 DepictFrameTree(root
));
1542 // Create the cross-site URL to navigate to.
1543 GURL cross_site_url
=
1544 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html");
1546 // Load cross-site page into the second iframe without waiting for the
1547 // navigation to complete. Once LoadURLWithParams returns, we would expect
1548 // proxies to have been created in the frame tree, but children of the
1549 // navigating frame to still be present. The reason is that we don't run the
1550 // message loop, so no IPCs that alter the frame tree can be processed.
1551 FrameTreeNode
* child
= root
->child_at(1);
1552 SiteInstance
* site
= NULL
;
1553 bool browser_side_navigation
=
1554 base::CommandLine::ForCurrentProcess()->HasSwitch(
1555 switches::kEnableBrowserSideNavigation
);
1556 std::string cross_site_rfh_type
=
1557 browser_side_navigation
? "speculative" : "pending";
1559 TestNavigationObserver
observer(shell()->web_contents());
1560 TestFrameNavigationObserver
navigation_observer(child
);
1561 NavigationController::LoadURLParams
params(cross_site_url
);
1562 params
.transition_type
= PageTransitionFromInt(ui::PAGE_TRANSITION_LINK
);
1563 params
.frame_tree_node_id
= child
->frame_tree_node_id();
1564 child
->navigator()->GetController()->LoadURLWithParams(params
);
1566 if (browser_side_navigation
) {
1567 site
= child
->render_manager()
1568 ->speculative_frame_host()
1569 ->GetSiteInstance();
1571 site
= child
->render_manager()->pending_frame_host()->GetSiteInstance();
1573 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site
);
1575 std::string tree
= base::StringPrintf(
1576 " Site A ------------ proxies for B\n"
1577 " |--Site A ------- proxies for B\n"
1578 " +--Site A (B %s)\n"
1582 "Where A = http://127.0.0.1/\n"
1583 " B = http://foo.com/",
1584 cross_site_rfh_type
.c_str());
1585 EXPECT_EQ(tree
, DepictFrameTree(root
));
1587 // Now that the verification is done, run the message loop and wait for the
1588 // navigation to complete.
1589 navigation_observer
.Wait();
1590 EXPECT_FALSE(child
->render_manager()->pending_frame_host());
1591 EXPECT_TRUE(observer
.last_navigation_succeeded());
1592 EXPECT_EQ(cross_site_url
, observer
.last_navigation_url());
1595 " Site A ------------ proxies for B\n"
1596 " |--Site A ------- proxies for B\n"
1597 " +--Site B ------- proxies for A\n"
1598 "Where A = http://127.0.0.1/\n"
1599 " B = http://foo.com/",
1600 DepictFrameTree(root
));
1603 // Load another cross-site page into the same iframe.
1604 cross_site_url
= embedded_test_server()->GetURL("bar.com", "/title2.html");
1606 // Perform the same checks as the first cross-site navigation, since
1607 // there have been issues in subsequent cross-site navigations. Also ensure
1608 // that the SiteInstance has properly changed.
1609 // TODO(nasko): Once we have proper cleanup of resources, add code to
1610 // verify that the intermediate SiteInstance/RenderFrameHost have been
1611 // properly cleaned up.
1612 TestNavigationObserver
observer(shell()->web_contents());
1613 TestFrameNavigationObserver
navigation_observer(child
);
1614 NavigationController::LoadURLParams
params(cross_site_url
);
1615 params
.transition_type
= PageTransitionFromInt(ui::PAGE_TRANSITION_LINK
);
1616 params
.frame_tree_node_id
= child
->frame_tree_node_id();
1617 child
->navigator()->GetController()->LoadURLWithParams(params
);
1619 SiteInstance
* site2
;
1620 if (browser_side_navigation
) {
1621 site2
= child
->render_manager()
1622 ->speculative_frame_host()
1623 ->GetSiteInstance();
1625 site2
= child
->render_manager()->pending_frame_host()->GetSiteInstance();
1627 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2
);
1628 EXPECT_NE(site
, site2
);
1630 std::string tree
= base::StringPrintf(
1631 " Site A ------------ proxies for B C\n"
1632 " |--Site A ------- proxies for B C\n"
1633 " +--Site B (C %s) -- proxies for A\n"
1634 "Where A = http://127.0.0.1/\n"
1635 " B = http://foo.com/\n"
1636 " C = http://bar.com/",
1637 cross_site_rfh_type
.c_str());
1638 EXPECT_EQ(tree
, DepictFrameTree(root
));
1640 navigation_observer
.Wait();
1641 EXPECT_TRUE(observer
.last_navigation_succeeded());
1642 EXPECT_EQ(cross_site_url
, observer
.last_navigation_url());
1643 EXPECT_EQ(0U, child
->child_count());
1647 // Verify that origin replication works for an A-embed-B-embed-C hierarchy.
1648 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, OriginReplication
) {
1649 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1650 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1652 // It is safe to obtain the root frame tree node here, as it doesn't change.
1653 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1657 TestNavigationObserver
observer(shell()->web_contents());
1659 // Navigate the first subframe to a cross-site page with two subframes.
1661 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1662 NavigateFrameToURL(root
->child_at(0), foo_url
);
1663 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1665 // We can't use a TestNavigationObserver to verify the URL here,
1666 // since the frame has children that may have clobbered it in the observer.
1667 EXPECT_EQ(foo_url
, root
->child_at(0)->current_url());
1669 // Ensure that a new process is created for the subframe.
1670 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1671 root
->child_at(0)->current_frame_host()->GetSiteInstance());
1673 // Load cross-site page into subframe's subframe.
1674 ASSERT_EQ(2U, root
->child_at(0)->child_count());
1675 GURL
bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1676 NavigateFrameToURL(root
->child_at(0)->child_at(0), bar_url
);
1677 EXPECT_TRUE(observer
.last_navigation_succeeded());
1678 EXPECT_EQ(bar_url
, observer
.last_navigation_url());
1680 // Check that a new process is created and is different from the top one and
1682 FrameTreeNode
* bottom_child
= root
->child_at(0)->child_at(0);
1683 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1684 bottom_child
->current_frame_host()->GetSiteInstance());
1685 EXPECT_NE(root
->child_at(0)->current_frame_host()->GetSiteInstance(),
1686 bottom_child
->current_frame_host()->GetSiteInstance());
1688 // Check that foo.com frame's location.ancestorOrigins contains the correct
1689 // origin for the parent. The origin should have been replicated as part of
1690 // the ViewMsg_New message that created the parent's RenderFrameProxy in
1691 // foo.com's process.
1692 int ancestor_origins_length
= 0;
1693 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1694 root
->child_at(0)->current_frame_host(),
1695 "window.domAutomationController.send(location.ancestorOrigins.length);",
1696 &ancestor_origins_length
));
1697 EXPECT_EQ(1, ancestor_origins_length
);
1699 EXPECT_TRUE(ExecuteScriptAndExtractString(
1700 root
->child_at(0)->current_frame_host(),
1701 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1703 EXPECT_EQ(result
+ "/", main_url
.GetOrigin().spec());
1705 // Check that bar.com frame's location.ancestorOrigins contains the correct
1706 // origin for its two ancestors. The topmost parent origin should be
1707 // replicated as part of ViewMsg_New, and the middle frame (foo.com's) origin
1708 // should be replicated as part of FrameMsg_NewFrameProxy sent for foo.com's
1709 // frame in bar.com's process.
1710 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1711 bottom_child
->current_frame_host(),
1712 "window.domAutomationController.send(location.ancestorOrigins.length);",
1713 &ancestor_origins_length
));
1714 EXPECT_EQ(2, ancestor_origins_length
);
1715 EXPECT_TRUE(ExecuteScriptAndExtractString(
1716 bottom_child
->current_frame_host(),
1717 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1719 EXPECT_EQ(result
+ "/", foo_url
.GetOrigin().spec());
1720 EXPECT_TRUE(ExecuteScriptAndExtractString(
1721 bottom_child
->current_frame_host(),
1722 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1724 EXPECT_EQ(result
+ "/", main_url
.GetOrigin().spec());
1727 // Check that iframe sandbox flags are replicated correctly.
1728 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, SandboxFlagsReplication
) {
1729 GURL
main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
1730 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1732 // It is safe to obtain the root frame tree node here, as it doesn't change.
1733 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1737 TestNavigationObserver
observer(shell()->web_contents());
1739 // Navigate the second (sandboxed) subframe to a cross-site page with a
1742 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1743 NavigateFrameToURL(root
->child_at(1), foo_url
);
1744 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1746 // We can't use a TestNavigationObserver to verify the URL here,
1747 // since the frame has children that may have clobbered it in the observer.
1748 EXPECT_EQ(foo_url
, root
->child_at(1)->current_url());
1750 // Load cross-site page into subframe's subframe.
1751 ASSERT_EQ(2U, root
->child_at(1)->child_count());
1752 GURL
bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1753 NavigateFrameToURL(root
->child_at(1)->child_at(0), bar_url
);
1754 EXPECT_TRUE(observer
.last_navigation_succeeded());
1755 EXPECT_EQ(bar_url
, observer
.last_navigation_url());
1757 // Opening a popup in the sandboxed foo.com iframe should fail.
1758 bool success
= false;
1760 ExecuteScriptAndExtractBool(root
->child_at(1)->current_frame_host(),
1761 "window.domAutomationController.send("
1762 "!window.open('data:text/html,dataurl'));",
1764 EXPECT_TRUE(success
);
1765 EXPECT_EQ(1u, Shell::windows().size());
1767 // Opening a popup in a frame whose parent is sandboxed should also fail.
1768 // Here, bar.com frame's sandboxed parent frame is a remote frame in
1769 // bar.com's process.
1771 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1772 root
->child_at(1)->child_at(0)->current_frame_host(),
1773 "window.domAutomationController.send("
1774 "!window.open('data:text/html,dataurl'));",
1776 EXPECT_TRUE(success
);
1777 EXPECT_EQ(1u, Shell::windows().size());
1779 // Same, but now try the case where bar.com frame's sandboxed parent is a
1780 // local frame in bar.com's process.
1782 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1783 root
->child_at(2)->child_at(0)->current_frame_host(),
1784 "window.domAutomationController.send("
1785 "!window.open('data:text/html,dataurl'));",
1787 EXPECT_TRUE(success
);
1788 EXPECT_EQ(1u, Shell::windows().size());
1790 // Check that foo.com frame's location.ancestorOrigins contains the correct
1791 // origin for the parent, which should be unaffected by sandboxing.
1792 int ancestor_origins_length
= 0;
1793 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1794 root
->child_at(1)->current_frame_host(),
1795 "window.domAutomationController.send(location.ancestorOrigins.length);",
1796 &ancestor_origins_length
));
1797 EXPECT_EQ(1, ancestor_origins_length
);
1799 EXPECT_TRUE(ExecuteScriptAndExtractString(
1800 root
->child_at(1)->current_frame_host(),
1801 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1803 EXPECT_EQ(result
+ "/", main_url
.GetOrigin().spec());
1805 // Now check location.ancestorOrigins for the bar.com frame. The middle frame
1806 // (foo.com's) origin should be unique, since that frame is sandboxed, and
1807 // the top frame should match |main_url|.
1808 FrameTreeNode
* bottom_child
= root
->child_at(1)->child_at(0);
1809 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1810 bottom_child
->current_frame_host(),
1811 "window.domAutomationController.send(location.ancestorOrigins.length);",
1812 &ancestor_origins_length
));
1813 EXPECT_EQ(2, ancestor_origins_length
);
1814 EXPECT_TRUE(ExecuteScriptAndExtractString(
1815 bottom_child
->current_frame_host(),
1816 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1818 EXPECT_EQ("null", result
);
1819 EXPECT_TRUE(ExecuteScriptAndExtractString(
1820 bottom_child
->current_frame_host(),
1821 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1823 EXPECT_EQ(main_url
.GetOrigin().spec(), result
+ "/");
1826 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1827 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, DynamicSandboxFlags
) {
1829 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1830 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1832 // It is safe to obtain the root frame tree node here, as it doesn't change.
1833 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1837 TestNavigationObserver
observer(shell()->web_contents());
1838 ASSERT_EQ(2U, root
->child_count());
1840 // Make sure first frame starts out at the correct cross-site page.
1841 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
1842 root
->child_at(0)->current_url());
1844 // Navigate second frame to another cross-site page.
1845 GURL
baz_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
1846 NavigateFrameToURL(root
->child_at(1), baz_url
);
1847 EXPECT_TRUE(observer
.last_navigation_succeeded());
1848 EXPECT_EQ(baz_url
, observer
.last_navigation_url());
1850 // Both frames should not be sandboxed to start with.
1851 EXPECT_EQ(blink::WebSandboxFlags::None
,
1852 root
->child_at(0)->current_replication_state().sandbox_flags
);
1853 EXPECT_EQ(blink::WebSandboxFlags::None
,
1854 root
->child_at(0)->effective_sandbox_flags());
1855 EXPECT_EQ(blink::WebSandboxFlags::None
,
1856 root
->child_at(1)->current_replication_state().sandbox_flags
);
1857 EXPECT_EQ(blink::WebSandboxFlags::None
,
1858 root
->child_at(1)->effective_sandbox_flags());
1860 // Dynamically update sandbox flags for the first frame.
1861 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1862 "window.domAutomationController.send("
1863 "document.querySelector('iframe').sandbox="
1864 "'allow-scripts');"));
1866 // Check that updated sandbox flags are propagated to browser process.
1867 // The new flags should be set in current_replication_state(), while
1868 // effective_sandbox_flags() should still reflect the old flags, because
1869 // sandbox flag updates take place only after navigations. "allow-scripts"
1870 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
1871 // per blink::parseSandboxPolicy().
1872 blink::WebSandboxFlags expected_flags
=
1873 blink::WebSandboxFlags::All
& ~blink::WebSandboxFlags::Scripts
&
1874 ~blink::WebSandboxFlags::AutomaticFeatures
;
1875 EXPECT_EQ(expected_flags
,
1876 root
->child_at(0)->current_replication_state().sandbox_flags
);
1877 EXPECT_EQ(blink::WebSandboxFlags::None
,
1878 root
->child_at(0)->effective_sandbox_flags());
1880 // Navigate the first frame to a page on the same site. The new sandbox
1881 // flags should take effect.
1883 embedded_test_server()->GetURL("bar.com", "/frame_tree/2-4.html"));
1884 NavigateFrameToURL(root
->child_at(0), bar_url
);
1885 // (The new page has a subframe; wait for it to load as well.)
1886 ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
1887 EXPECT_EQ(bar_url
, root
->child_at(0)->current_url());
1888 ASSERT_EQ(1U, root
->child_at(0)->child_count());
1891 " Site A ------------ proxies for B C\n"
1892 " |--Site B ------- proxies for A C\n"
1893 " | +--Site B -- proxies for A C\n"
1894 " +--Site C ------- proxies for A B\n"
1895 "Where A = http://127.0.0.1/\n"
1896 " B = http://bar.com/\n"
1897 " C = http://baz.com/",
1898 DepictFrameTree(root
));
1900 // Confirm that the browser process has updated the frame's current sandbox
1902 EXPECT_EQ(expected_flags
,
1903 root
->child_at(0)->current_replication_state().sandbox_flags
);
1904 EXPECT_EQ(expected_flags
, root
->child_at(0)->effective_sandbox_flags());
1906 // Opening a popup in the now-sandboxed frame should fail.
1907 bool success
= false;
1909 ExecuteScriptAndExtractBool(root
->child_at(0)->current_frame_host(),
1910 "window.domAutomationController.send("
1911 "!window.open('data:text/html,dataurl'));",
1913 EXPECT_TRUE(success
);
1914 EXPECT_EQ(1u, Shell::windows().size());
1916 // Navigate the child of the now-sandboxed frame to a page on baz.com. The
1917 // child should inherit the latest sandbox flags from its parent frame, which
1918 // is currently a proxy in baz.com's renderer process. This checks that the
1919 // proxies of |root->child_at(0)| were also updated with the latest sandbox
1921 GURL
baz_child_url(embedded_test_server()->GetURL("baz.com", "/title2.html"));
1922 NavigateFrameToURL(root
->child_at(0)->child_at(0), baz_child_url
);
1923 EXPECT_TRUE(observer
.last_navigation_succeeded());
1924 EXPECT_EQ(baz_child_url
, observer
.last_navigation_url());
1927 " Site A ------------ proxies for B C\n"
1928 " |--Site B ------- proxies for A C\n"
1929 " | +--Site C -- proxies for A B\n"
1930 " +--Site C ------- proxies for A B\n"
1931 "Where A = http://127.0.0.1/\n"
1932 " B = http://bar.com/\n"
1933 " C = http://baz.com/",
1934 DepictFrameTree(root
));
1936 // Opening a popup in the child of a sandboxed frame should fail.
1938 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1939 root
->child_at(0)->child_at(0)->current_frame_host(),
1940 "window.domAutomationController.send("
1941 "!window.open('data:text/html,dataurl'));",
1943 EXPECT_TRUE(success
);
1944 EXPECT_EQ(1u, Shell::windows().size());
1947 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1948 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
1949 DynamicSandboxFlagsRemoteToLocal
) {
1951 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1952 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
1954 // It is safe to obtain the root frame tree node here, as it doesn't change.
1955 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1959 TestNavigationObserver
observer(shell()->web_contents());
1960 ASSERT_EQ(2U, root
->child_count());
1962 // Make sure the two frames starts out at correct URLs.
1963 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
1964 root
->child_at(0)->current_url());
1965 EXPECT_EQ(embedded_test_server()->GetURL("/title1.html"),
1966 root
->child_at(1)->current_url());
1968 // Update the second frame's sandbox flags.
1969 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1970 "window.domAutomationController.send("
1971 "document.querySelectorAll('iframe')[1].sandbox="
1972 "'allow-scripts');"));
1974 // Check that the current sandbox flags are updated but the effective
1975 // sandbox flags are not.
1976 blink::WebSandboxFlags expected_flags
=
1977 blink::WebSandboxFlags::All
& ~blink::WebSandboxFlags::Scripts
&
1978 ~blink::WebSandboxFlags::AutomaticFeatures
;
1979 EXPECT_EQ(expected_flags
,
1980 root
->child_at(1)->current_replication_state().sandbox_flags
);
1981 EXPECT_EQ(blink::WebSandboxFlags::None
,
1982 root
->child_at(1)->effective_sandbox_flags());
1984 // Navigate the second subframe to a page on bar.com. This will trigger a
1985 // remote-to-local frame swap in bar.com's process. The target page has
1986 // another frame, so use TestFrameNavigationObserver to wait for all frames
1988 TestFrameNavigationObserver
frame_observer(root
->child_at(1), 2);
1989 GURL
bar_url(embedded_test_server()->GetURL(
1990 "bar.com", "/frame_tree/page_with_one_frame.html"));
1991 NavigateFrameToURL(root
->child_at(1), bar_url
);
1992 frame_observer
.Wait();
1993 EXPECT_EQ(bar_url
, root
->child_at(1)->current_url());
1994 ASSERT_EQ(1U, root
->child_at(1)->child_count());
1996 // Confirm that the browser process has updated the current sandbox flags.
1997 EXPECT_EQ(expected_flags
,
1998 root
->child_at(1)->current_replication_state().sandbox_flags
);
1999 EXPECT_EQ(expected_flags
, root
->child_at(1)->effective_sandbox_flags());
2001 // Opening a popup in the sandboxed second frame should fail.
2002 bool success
= false;
2004 ExecuteScriptAndExtractBool(root
->child_at(1)->current_frame_host(),
2005 "window.domAutomationController.send("
2006 "!window.open('data:text/html,dataurl'));",
2008 EXPECT_TRUE(success
);
2009 EXPECT_EQ(1u, Shell::windows().size());
2011 // Make sure that the child frame inherits the sandbox flags of its
2012 // now-sandboxed parent frame.
2014 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2015 root
->child_at(1)->child_at(0)->current_frame_host(),
2016 "window.domAutomationController.send("
2017 "!window.open('data:text/html,dataurl'));",
2019 EXPECT_TRUE(success
);
2020 EXPECT_EQ(1u, Shell::windows().size());
2023 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
2024 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
2025 DynamicSandboxFlagsRendererInitiatedNavigation
) {
2027 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
2028 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
2030 // It is safe to obtain the root frame tree node here, as it doesn't change.
2031 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2035 TestNavigationObserver
observer(shell()->web_contents());
2036 ASSERT_EQ(1U, root
->child_count());
2038 // Make sure the frame starts out at the correct cross-site page.
2039 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
2040 root
->child_at(0)->current_url());
2042 // The frame should not be sandboxed to start with.
2043 EXPECT_EQ(blink::WebSandboxFlags::None
,
2044 root
->child_at(0)->current_replication_state().sandbox_flags
);
2045 EXPECT_EQ(blink::WebSandboxFlags::None
,
2046 root
->child_at(0)->effective_sandbox_flags());
2048 // Dynamically update the frame's sandbox flags.
2049 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
2050 "window.domAutomationController.send("
2051 "document.querySelector('iframe').sandbox="
2052 "'allow-scripts');"));
2054 // Check that updated sandbox flags are propagated to browser process.
2055 // The new flags should be set in current_replication_state(), while
2056 // effective_sandbox_flags() should still reflect the old flags, because
2057 // sandbox flag updates take place only after navigations. "allow-scripts"
2058 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
2059 // per blink::parseSandboxPolicy().
2060 blink::WebSandboxFlags expected_flags
=
2061 blink::WebSandboxFlags::All
& ~blink::WebSandboxFlags::Scripts
&
2062 ~blink::WebSandboxFlags::AutomaticFeatures
;
2063 EXPECT_EQ(expected_flags
,
2064 root
->child_at(0)->current_replication_state().sandbox_flags
);
2065 EXPECT_EQ(blink::WebSandboxFlags::None
,
2066 root
->child_at(0)->effective_sandbox_flags());
2068 // Perform a renderer-initiated same-site navigation in the first frame. The
2069 // new sandbox flags should take effect.
2070 TestFrameNavigationObserver
frame_observer(root
->child_at(0));
2071 ASSERT_TRUE(ExecuteScript(root
->child_at(0)->current_frame_host(),
2072 "window.location.href='/title2.html'"));
2073 frame_observer
.Wait();
2074 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title2.html"),
2075 root
->child_at(0)->current_url());
2077 // Confirm that the browser process has updated the frame's current sandbox
2079 EXPECT_EQ(expected_flags
,
2080 root
->child_at(0)->current_replication_state().sandbox_flags
);
2081 EXPECT_EQ(expected_flags
, root
->child_at(0)->effective_sandbox_flags());
2083 // Opening a popup in the now-sandboxed frame should fail.
2084 bool success
= false;
2086 ExecuteScriptAndExtractBool(root
->child_at(0)->current_frame_host(),
2087 "window.domAutomationController.send("
2088 "!window.open('data:text/html,dataurl'));",
2090 EXPECT_TRUE(success
);
2091 EXPECT_EQ(1u, Shell::windows().size());
2094 // Verify that when a new child frame is added, the proxies created for it in
2095 // other SiteInstances have correct sandbox flags and origin.
2103 // The test checks sandbox flags and origin for the proxy added in step 2, by
2104 // checking whether the grandchild frame added in step 3 sees proper sandbox
2105 // flags and origin for its (remote) parent. This wasn't addressed when
2106 // https://crbug.com/423587 was fixed.
2107 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
2108 ProxiesForNewChildFramesHaveCorrectReplicationState
) {
2110 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
2111 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
2113 // It is safe to obtain the root frame tree node here, as it doesn't change.
2114 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2117 TestNavigationObserver
observer(shell()->web_contents());
2120 " Site A ------------ proxies for B\n"
2121 " +--Site B ------- proxies for A\n"
2122 "Where A = http://127.0.0.1/\n"
2123 " B = http://baz.com/",
2124 DepictFrameTree(root
));
2126 // In the root frame, add a new sandboxed local frame, which itself has a
2127 // child frame on baz.com. Wait for three RenderFrameHosts to be created:
2128 // the new sandboxed local frame, its child (while it's still local), and a
2129 // pending RFH when starting the cross-site navigation to baz.com.
2130 RenderFrameHostCreatedObserver
frame_observer(shell()->web_contents(), 3);
2132 ExecuteScript(root
->current_frame_host(),
2133 "window.domAutomationController.send("
2134 " addFrame('/frame_tree/page_with_one_frame.html',"
2135 " 'allow-scripts allow-same-origin'))"));
2136 frame_observer
.Wait();
2138 // Wait for the cross-site navigation to baz.com in the grandchild to finish.
2139 FrameTreeNode
* bottom_child
= root
->child_at(1)->child_at(0);
2140 TestFrameNavigationObserver
navigation_observer(bottom_child
);
2141 navigation_observer
.Wait();
2144 " Site A ------------ proxies for B\n"
2145 " |--Site B ------- proxies for A\n"
2146 " +--Site A ------- proxies for B\n"
2147 " +--Site B -- proxies for A\n"
2148 "Where A = http://127.0.0.1/\n"
2149 " B = http://baz.com/",
2150 DepictFrameTree(root
));
2152 // Use location.ancestorOrigins to check that the grandchild on baz.com sees
2153 // correct origin for its parent.
2154 int ancestor_origins_length
= 0;
2155 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2156 bottom_child
->current_frame_host(),
2157 "window.domAutomationController.send(location.ancestorOrigins.length);",
2158 &ancestor_origins_length
));
2159 EXPECT_EQ(2, ancestor_origins_length
);
2160 std::string parent_origin
;
2161 EXPECT_TRUE(ExecuteScriptAndExtractString(
2162 bottom_child
->current_frame_host(),
2163 "window.domAutomationController.send(location.ancestorOrigins[0]);",
2165 EXPECT_EQ(main_url
.GetOrigin().spec(), parent_origin
+ "/");
2167 // Check that the sandbox flags in the browser process are correct.
2168 // "allow-scripts" resets both WebSandboxFlags::Scripts and
2169 // WebSandboxFlags::AutomaticFeatures bits per blink::parseSandboxPolicy().
2170 blink::WebSandboxFlags expected_flags
=
2171 blink::WebSandboxFlags::All
& ~blink::WebSandboxFlags::Scripts
&
2172 ~blink::WebSandboxFlags::AutomaticFeatures
&
2173 ~blink::WebSandboxFlags::Origin
;
2174 EXPECT_EQ(expected_flags
,
2175 root
->child_at(1)->current_replication_state().sandbox_flags
);
2177 // The child of the sandboxed frame should've inherited sandbox flags, so it
2178 // should not be able to create popups.
2179 bool success
= false;
2181 ExecuteScriptAndExtractBool(bottom_child
->current_frame_host(),
2182 "window.domAutomationController.send("
2183 "!window.open('data:text/html,dataurl'));",
2185 EXPECT_TRUE(success
);
2186 EXPECT_EQ(1u, Shell::windows().size());
2189 // Verify that a child frame can retrieve the name property set by its parent.
2190 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, WindowNameReplication
) {
2191 GURL
main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
2192 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
2194 // It is safe to obtain the root frame tree node here, as it doesn't change.
2195 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2199 TestNavigationObserver
observer(shell()->web_contents());
2201 // Load cross-site page into iframe.
2203 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
2204 NavigateFrameToURL(root
->child_at(0), frame_url
);
2205 EXPECT_TRUE(observer
.last_navigation_succeeded());
2206 EXPECT_EQ(frame_url
, observer
.last_navigation_url());
2208 // Ensure that a new process is created for the subframe.
2209 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
2210 root
->child_at(0)->current_frame_host()->GetSiteInstance());
2212 // Check that the window.name seen by the frame matches the name attribute
2213 // specified by its parent in the iframe tag.
2215 EXPECT_TRUE(ExecuteScriptAndExtractString(
2216 root
->child_at(0)->current_frame_host(),
2217 "window.domAutomationController.send(window.name);", &result
));
2218 EXPECT_EQ("3-1-name", result
);
2221 // Verify that dynamic updates to a frame's window.name propagate to the
2222 // frame's proxies, so that the latest frame names can be used in navigations.
2223 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, DynamicWindowName
) {
2224 GURL
main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
2225 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
2227 // It is safe to obtain the root frame tree node here, as it doesn't change.
2228 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2231 TestNavigationObserver
observer(shell()->web_contents());
2233 // Load cross-site page into iframe.
2235 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
2236 NavigateFrameToURL(root
->child_at(0), frame_url
);
2237 EXPECT_TRUE(observer
.last_navigation_succeeded());
2238 EXPECT_EQ(frame_url
, observer
.last_navigation_url());
2240 // Browser process should know the child frame's original window.name
2241 // specified in the iframe element.
2242 EXPECT_EQ(root
->child_at(0)->frame_name(), "3-1-name");
2244 // Update the child frame's window.name.
2245 EXPECT_TRUE(ExecuteScript(root
->child_at(0)->current_frame_host(),
2246 "window.domAutomationController.send("
2247 "window.name = 'updated-name');"));
2249 // The change should propagate to the browser process.
2250 EXPECT_EQ(root
->child_at(0)->frame_name(), "updated-name");
2252 // The proxy in the parent process should also receive the updated name.
2253 // Check that it can reference the child frame by its new name.
2254 bool success
= false;
2256 ExecuteScriptAndExtractBool(shell()->web_contents(),
2257 "window.domAutomationController.send("
2258 "frames['updated-name'] == frames[0]);",
2260 EXPECT_TRUE(success
);
2262 // Issue a renderer-initiated navigation from the root frame to the child
2263 // frame using the frame's name. Make sure correct frame is navigated.
2265 // TODO(alexmos): When blink::createWindow is refactored to handle
2266 // RemoteFrames, this should also be tested via window.open(url, frame_name)
2267 // and a more complicated frame hierarchy (https://crbug.com/463742)
2268 TestFrameNavigationObserver
frame_observer(root
->child_at(0));
2269 GURL
foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
2270 std::string script
= base::StringPrintf(
2271 "window.domAutomationController.send("
2272 "frames['updated-name'].location.href = '%s');",
2273 foo_url
.spec().c_str());
2274 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script
));
2275 frame_observer
.Wait();
2276 EXPECT_EQ(foo_url
, root
->child_at(0)->current_url());
2279 // Verify that when a frame is navigated to a new origin, the origin update
2280 // propagates to the frame's proxies.
2281 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, OriginUpdatesReachProxies
) {
2283 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2284 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
2286 // It is safe to obtain the root frame tree node here, as it doesn't change.
2287 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2290 TestNavigationObserver
observer(shell()->web_contents());
2293 " Site A ------------ proxies for B\n"
2294 " |--Site B ------- proxies for A\n"
2295 " +--Site A ------- proxies for B\n"
2296 "Where A = http://127.0.0.1/\n"
2297 " B = http://bar.com/",
2298 DepictFrameTree(root
));
2300 // Navigate second subframe to a baz.com. This should send an origin update
2301 // to the frame's proxy in the bar.com (first frame's) process.
2302 GURL frame_url
= embedded_test_server()->GetURL("baz.com", "/title2.html");
2303 NavigateFrameToURL(root
->child_at(1), frame_url
);
2304 EXPECT_TRUE(observer
.last_navigation_succeeded());
2305 EXPECT_EQ(frame_url
, observer
.last_navigation_url());
2307 // The first frame can't directly observe the second frame's origin with
2308 // JavaScript. Instead, try to navigate the second frame from the first
2309 // frame. This should fail with a console error message, which should
2310 // contain the second frame's updated origin (see blink::Frame::canNavigate).
2311 scoped_ptr
<ConsoleObserverDelegate
> console_delegate(
2312 new ConsoleObserverDelegate(
2313 shell()->web_contents(),
2314 "Unsafe JavaScript attempt to initiate navigation*"));
2315 shell()->web_contents()->SetDelegate(console_delegate
.get());
2317 // frames[1] can't be used due to a bug where RemoteFrames are created out of
2318 // order (https://crbug.com/478792). Instead, target second frame by name.
2319 EXPECT_TRUE(ExecuteScript(
2320 root
->child_at(0)->current_frame_host(),
2321 "window.domAutomationController.send("
2322 " parent.frames['frame2'].location.href = 'data:text/html,foo');"));
2323 console_delegate
->Wait();
2325 std::string frame_origin
=
2326 root
->child_at(1)->current_replication_state().origin
.Serialize();
2327 EXPECT_EQ(frame_origin
+ "/", frame_url
.GetOrigin().spec());
2329 base::MatchPattern(console_delegate
->message(), "*" + frame_origin
+ "*"))
2330 << "Error message does not contain the frame's latest origin ("
2331 << frame_origin
<< ")";
2334 // Ensure that navigating subframes in --site-per-process mode properly fires
2335 // the DidStopLoading event on WebContentsObserver.
2336 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, CrossSiteDidStopLoading
) {
2337 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
2338 NavigateToURL(shell(), main_url
);
2340 // It is safe to obtain the root frame tree node here, as it doesn't change.
2341 FrameTreeNode
* root
=
2342 static_cast<WebContentsImpl
*>(shell()->web_contents())->
2343 GetFrameTree()->root();
2345 TestNavigationObserver
observer(shell()->web_contents());
2347 // Load same-site page into iframe.
2348 FrameTreeNode
* child
= root
->child_at(0);
2349 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
2350 NavigateFrameToURL(child
, http_url
);
2351 EXPECT_EQ(http_url
, observer
.last_navigation_url());
2352 EXPECT_TRUE(observer
.last_navigation_succeeded());
2354 // Load cross-site page into iframe.
2355 TestNavigationObserver
nav_observer(shell()->web_contents(), 1);
2356 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
2357 NavigationController::LoadURLParams
params(url
);
2358 params
.transition_type
= ui::PAGE_TRANSITION_LINK
;
2359 params
.frame_tree_node_id
= child
->frame_tree_node_id();
2360 child
->navigator()->GetController()->LoadURLWithParams(params
);
2361 nav_observer
.Wait();
2363 // Verify that the navigation succeeded and the expected URL was loaded.
2364 EXPECT_TRUE(observer
.last_navigation_succeeded());
2365 EXPECT_EQ(url
, observer
.last_navigation_url());
2368 // Ensure that the renderer does not crash when navigating a frame that has a
2369 // sibling RemoteFrame. See https://crbug.com/426953.
2370 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
2371 NavigateWithSiblingRemoteFrame
) {
2373 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2374 NavigateToURL(shell(), main_url
);
2376 // It is safe to obtain the root frame tree node here, as it doesn't change.
2377 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2380 TestNavigationObserver
observer(shell()->web_contents());
2382 // Make sure the first frame is out of process.
2383 ASSERT_EQ(2U, root
->child_count());
2384 FrameTreeNode
* node2
= root
->child_at(0);
2385 EXPECT_NE(root
->current_frame_host()->GetSiteInstance(),
2386 node2
->current_frame_host()->GetSiteInstance());
2388 // Make sure the second frame is in the parent's process.
2389 FrameTreeNode
* node3
= root
->child_at(1);
2390 EXPECT_EQ(root
->current_frame_host()->GetSiteInstance(),
2391 node3
->current_frame_host()->GetSiteInstance());
2393 // Navigate the second iframe (node3) to a URL in its own process.
2394 GURL title_url
= embedded_test_server()->GetURL("/title2.html");
2395 NavigateFrameToURL(node3
, title_url
);
2396 EXPECT_TRUE(observer
.last_navigation_succeeded());
2397 EXPECT_EQ(title_url
, observer
.last_navigation_url());
2398 EXPECT_EQ(root
->current_frame_host()->GetSiteInstance(),
2399 node3
->current_frame_host()->GetSiteInstance());
2400 EXPECT_TRUE(node3
->current_frame_host()->IsRenderFrameLive());
2403 // Verify that load events for iframe elements work when the child frame is
2404 // out-of-process. In such cases, the load event is forwarded from the child
2405 // frame to the parent frame via the browser process.
2406 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, LoadEventForwarding
) {
2407 // Load a page with a cross-site frame. The parent page has an onload
2408 // handler in the iframe element that appends "LOADED" to the document title.
2411 embedded_test_server()->GetURL("/frame_with_load_event.html"));
2412 base::string16
expected_title(base::UTF8ToUTF16("LOADED"));
2413 TitleWatcher
title_watcher(shell()->web_contents(), expected_title
);
2414 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
2415 EXPECT_EQ(title_watcher
.WaitAndGetTitle(), expected_title
);
2418 // It is safe to obtain the root frame tree node here, as it doesn't change.
2419 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2423 // Load another cross-site page into the iframe and check that the load event
2426 GURL
foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
2427 base::string16
expected_title(base::UTF8ToUTF16("LOADEDLOADED"));
2428 TitleWatcher
title_watcher(shell()->web_contents(), expected_title
);
2429 TestNavigationObserver
observer(shell()->web_contents());
2430 NavigateFrameToURL(root
->child_at(0), foo_url
);
2431 EXPECT_TRUE(observer
.last_navigation_succeeded());
2432 EXPECT_EQ(foo_url
, observer
.last_navigation_url());
2433 EXPECT_EQ(title_watcher
.WaitAndGetTitle(), expected_title
);
2437 // Check that postMessage can be routed between cross-site iframes.
2438 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, SubframePostMessage
) {
2439 GURL
main_url(embedded_test_server()->GetURL(
2440 "/frame_tree/page_with_post_message_frames.html"));
2441 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
2443 // It is safe to obtain the root frame tree node here, as it doesn't change.
2444 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2448 ASSERT_EQ(2U, root
->child_count());
2450 // Verify the frames start at correct URLs. First frame should be
2451 // same-site; second frame should be cross-site.
2452 GURL
same_site_url(embedded_test_server()->GetURL("/post_message.html"));
2453 EXPECT_EQ(same_site_url
, root
->child_at(0)->current_url());
2454 GURL
foo_url(embedded_test_server()->GetURL("foo.com",
2455 "/post_message.html"));
2456 EXPECT_EQ(foo_url
, root
->child_at(1)->current_url());
2457 EXPECT_NE(root
->child_at(0)->current_frame_host()->GetSiteInstance(),
2458 root
->child_at(1)->current_frame_host()->GetSiteInstance());
2460 // Send a message from first, same-site frame to second, cross-site frame.
2461 // Expect the second frame to reply back to the first frame.
2462 PostMessageAndWaitForReply(root
->child_at(0),
2463 "postToSibling('subframe-msg','subframe2')",
2464 "\"done-subframe1\"");
2466 // Send a postMessage from second, cross-site frame to its parent. Expect
2467 // parent to send a reply to the frame.
2468 base::string16
expected_title(base::ASCIIToUTF16("subframe-msg"));
2469 TitleWatcher
title_watcher(shell()->web_contents(), expected_title
);
2470 PostMessageAndWaitForReply(root
->child_at(1), "postToParent('subframe-msg')",
2471 "\"done-subframe2\"");
2472 EXPECT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
2474 // Verify the total number of received messages for each subframe. First
2475 // frame should have one message (reply from second frame). Second frame
2476 // should have two messages (message from first frame and reply from parent).
2477 // Parent should have one message (from second frame).
2478 EXPECT_EQ(1, GetReceivedMessages(root
->child_at(0)));
2479 EXPECT_EQ(2, GetReceivedMessages(root
->child_at(1)));
2480 EXPECT_EQ(1, GetReceivedMessages(root
));
2483 // Check that postMessage can be sent from a subframe on a cross-process opener
2484 // tab, and that its event.source points to a valid proxy.
2485 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
2486 PostMessageWithSubframeOnOpenerChain
) {
2487 GURL
main_url(embedded_test_server()->GetURL(
2488 "a.com", "/frame_tree/page_with_post_message_frames.html"));
2489 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
2491 // It is safe to obtain the root frame tree node here, as it doesn't change.
2492 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2496 ASSERT_EQ(2U, root
->child_count());
2498 // Verify the initial state of the world. First frame should be same-site;
2499 // second frame should be cross-site.
2501 " Site A ------------ proxies for B\n"
2502 " |--Site A ------- proxies for B\n"
2503 " +--Site B ------- proxies for A\n"
2504 "Where A = http://a.com/\n"
2505 " B = http://foo.com/",
2506 DepictFrameTree(root
));
2508 // Open a popup from the first subframe (so that popup's window.opener points
2509 // to the subframe) and navigate it to bar.com.
2510 ShellAddedObserver new_shell_observer
;
2511 EXPECT_TRUE(ExecuteScript(root
->child_at(0)->current_frame_host(),
2512 "openPopup('about:blank');"));
2513 Shell
* popup
= new_shell_observer
.GetShell();
2515 embedded_test_server()->GetURL("bar.com", "/post_message.html"));
2516 EXPECT_TRUE(NavigateToURL(popup
, popup_url
));
2518 // From the popup, open another popup for baz.com. This will be used to
2519 // check that the whole opener chain is processed when creating proxies and
2520 // not just an immediate opener.
2521 ShellAddedObserver new_shell_observer2
;
2523 ExecuteScript(popup
->web_contents(), "openPopup('about:blank');"));
2524 Shell
* popup2
= new_shell_observer2
.GetShell();
2526 embedded_test_server()->GetURL("baz.com", "/post_message.html"));
2527 EXPECT_TRUE(NavigateToURL(popup2
, popup2_url
));
2529 // Ensure that we've created proxies for SiteInstances of both popups (C, D)
2530 // in the main window's frame tree.
2532 " Site A ------------ proxies for B C D\n"
2533 " |--Site A ------- proxies for B C D\n"
2534 " +--Site B ------- proxies for A C D\n"
2535 "Where A = http://a.com/\n"
2536 " B = http://foo.com/\n"
2537 " C = http://bar.com/\n"
2538 " D = http://baz.com/",
2539 DepictFrameTree(root
));
2541 // Check the first popup's frame tree as well. Note that it doesn't have a
2542 // proxy for foo.com, since foo.com can't reach the popup. It does have a
2543 // proxy for its opener a.com (which can reach it via the window.open
2544 // reference) and second popup (which can reach it via window.opener).
2545 FrameTreeNode
* popup_root
=
2546 static_cast<WebContentsImpl
*>(popup
->web_contents())
2550 " Site C ------------ proxies for A D\n"
2551 "Where A = http://a.com/\n"
2552 " C = http://bar.com/\n"
2553 " D = http://baz.com/",
2554 DepictFrameTree(popup_root
));
2556 // Send a message from first subframe on main page to the first popup and
2557 // wait for a reply back. The reply verifies that the proxy for the opener
2558 // tab's subframe is targeted properly.
2559 PostMessageAndWaitForReply(root
->child_at(0), "postToPopup('subframe-msg')",
2560 "\"done-subframe1\"");
2562 // Send a postMessage from the popup to window.opener and ensure that it
2563 // reaches subframe1. This verifies that the subframe opener information
2564 // propagated to the popup's RenderFrame. Wait for subframe1 to send a reply
2565 // message to the popup.
2566 EXPECT_TRUE(ExecuteScript(popup
->web_contents(), "window.name = 'popup';"));
2567 PostMessageAndWaitForReply(popup_root
, "postToOpener('subframe-msg', '*')",
2570 // Second a postMessage from popup2 to window.opener.opener, which should
2571 // resolve to subframe1. This tests opener chains of length greater than 1.
2572 // As before, subframe1 will send a reply to popup2.
2573 FrameTreeNode
* popup2_root
=
2574 static_cast<WebContentsImpl
*>(popup2
->web_contents())
2577 EXPECT_TRUE(ExecuteScript(popup2
->web_contents(), "window.name = 'popup2';"));
2578 PostMessageAndWaitForReply(popup2_root
,
2579 "postToOpenerOfOpener('subframe-msg', '*')",
2582 // Verify the total number of received messages for each subframe:
2583 // - 3 for first subframe (two from first popup, one from second popup)
2584 // - 2 for popup (both from first subframe)
2585 // - 1 for popup2 (reply from first subframe)
2586 // - 0 for other frames
2587 EXPECT_EQ(0, GetReceivedMessages(root
));
2588 EXPECT_EQ(3, GetReceivedMessages(root
->child_at(0)));
2589 EXPECT_EQ(0, GetReceivedMessages(root
->child_at(1)));
2590 EXPECT_EQ(2, GetReceivedMessages(popup_root
));
2591 EXPECT_EQ(1, GetReceivedMessages(popup2_root
));
2594 // Check that parent.frames[num] references correct sibling frames when the
2595 // parent is remote. See https://crbug.com/478792.
2596 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, IndexedFrameAccess
) {
2597 // Start on a page with three same-site subframes.
2599 embedded_test_server()->GetURL("a.com", "/frame_tree/top.html"));
2600 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
2602 // It is safe to obtain the root frame tree node here, as it doesn't change.
2603 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2606 ASSERT_EQ(3U, root
->child_count());
2607 FrameTreeNode
* child0
= root
->child_at(0);
2608 FrameTreeNode
* child1
= root
->child_at(1);
2609 FrameTreeNode
* child2
= root
->child_at(2);
2611 // Send each of the frames to a different site. Each new renderer will first
2612 // create proxies for the parent and two sibling subframes and then create
2613 // and insert the new RenderFrame into the frame tree.
2614 GURL
b_url(embedded_test_server()->GetURL("b.com", "/post_message.html"));
2615 GURL
c_url(embedded_test_server()->GetURL("c.com", "/post_message.html"));
2616 GURL
d_url(embedded_test_server()->GetURL("d.com", "/post_message.html"));
2617 NavigateFrameToURL(child0
, b_url
);
2618 // TODO(alexmos): The calls to WaitForRenderFrameReady can be removed once
2619 // TestFrameNavigationObserver is fixed to use DidFinishLoad.
2620 EXPECT_TRUE(WaitForRenderFrameReady(child0
->current_frame_host()));
2621 NavigateFrameToURL(child1
, c_url
);
2622 EXPECT_TRUE(WaitForRenderFrameReady(child1
->current_frame_host()));
2623 NavigateFrameToURL(child2
, d_url
);
2624 EXPECT_TRUE(WaitForRenderFrameReady(child2
->current_frame_host()));
2627 " Site A ------------ proxies for B C D\n"
2628 " |--Site B ------- proxies for A C D\n"
2629 " |--Site C ------- proxies for A B D\n"
2630 " +--Site D ------- proxies for A B C\n"
2631 "Where A = http://a.com/\n"
2632 " B = http://b.com/\n"
2633 " C = http://c.com/\n"
2634 " D = http://d.com/",
2635 DepictFrameTree(root
));
2637 // Check that each subframe sees itself at correct index in parent.frames.
2638 bool success
= false;
2639 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2640 child0
->current_frame_host(),
2641 "window.domAutomationController.send(window === parent.frames[0]);",
2643 EXPECT_TRUE(success
);
2646 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2647 child1
->current_frame_host(),
2648 "window.domAutomationController.send(window === parent.frames[1]);",
2650 EXPECT_TRUE(success
);
2653 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2654 child2
->current_frame_host(),
2655 "window.domAutomationController.send(window === parent.frames[2]);",
2657 EXPECT_TRUE(success
);
2659 // Send a postMessage from B to parent.frames[1], which should go to C, and
2661 PostMessageAndWaitForReply(child0
, "postToSibling('subframe-msg', 1)",
2662 "\"done-1-1-name\"");
2664 // Send a postMessage from C to parent.frames[2], which should go to D, and
2666 PostMessageAndWaitForReply(child1
, "postToSibling('subframe-msg', 2)",
2667 "\"done-1-2-name\"");
2669 // Verify the total number of received messages for each subframe.
2670 EXPECT_EQ(1, GetReceivedMessages(child0
));
2671 EXPECT_EQ(2, GetReceivedMessages(child1
));
2672 EXPECT_EQ(1, GetReceivedMessages(child2
));
2675 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, RFPHDestruction
) {
2676 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
2677 NavigateToURL(shell(), main_url
);
2679 // It is safe to obtain the root frame tree node here, as it doesn't change.
2680 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2684 TestNavigationObserver
observer(shell()->web_contents());
2686 // Load cross-site page into iframe.
2687 FrameTreeNode
* child
= root
->child_at(0);
2688 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
2689 NavigateFrameToURL(root
->child_at(0), url
);
2690 EXPECT_TRUE(observer
.last_navigation_succeeded());
2691 EXPECT_EQ(url
, observer
.last_navigation_url());
2693 " Site A ------------ proxies for B\n"
2694 " |--Site B ------- proxies for A\n"
2695 " +--Site A ------- proxies for B\n"
2696 " |--Site A -- proxies for B\n"
2697 " +--Site A -- proxies for B\n"
2698 " +--Site A -- proxies for B\n"
2699 "Where A = http://127.0.0.1/\n"
2700 " B = http://foo.com/",
2701 DepictFrameTree(root
));
2703 // Load another cross-site page.
2704 url
= embedded_test_server()->GetURL("bar.com", "/title3.html");
2705 NavigateIframeToURL(shell()->web_contents(), "test", url
);
2706 EXPECT_TRUE(observer
.last_navigation_succeeded());
2707 EXPECT_EQ(url
, observer
.last_navigation_url());
2709 " Site A ------------ proxies for C\n"
2710 " |--Site C ------- proxies for A\n"
2711 " +--Site A ------- proxies for C\n"
2712 " |--Site A -- proxies for C\n"
2713 " +--Site A -- proxies for C\n"
2714 " +--Site A -- proxies for C\n"
2715 "Where A = http://127.0.0.1/\n"
2716 " C = http://bar.com/",
2717 DepictFrameTree(root
));
2719 // Navigate back to the parent's origin.
2720 url
= embedded_test_server()->GetURL("/title1.html");
2721 NavigateFrameToURL(child
, url
);
2722 EXPECT_EQ(url
, observer
.last_navigation_url());
2723 EXPECT_TRUE(observer
.last_navigation_succeeded());
2731 "Where A = http://127.0.0.1/",
2732 DepictFrameTree(root
));
2735 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, OpenPopupWithRemoteParent
) {
2737 embedded_test_server()->GetURL("a.com", "/site_per_process_main.html"));
2738 NavigateToURL(shell(), main_url
);
2740 // It is safe to obtain the root frame tree node here, as it doesn't change.
2741 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2745 // Navigate first child cross-site.
2746 GURL
frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
2747 NavigateFrameToURL(root
->child_at(0), frame_url
);
2749 // Open a popup from the first child.
2750 Shell
* new_shell
= OpenPopup(root
->child_at(0)->current_frame_host(),
2751 GURL(url::kAboutBlankURL
), "");
2752 EXPECT_TRUE(new_shell
);
2754 // Check that the popup's opener is correct on both the browser and renderer
2756 FrameTreeNode
* popup_root
=
2757 static_cast<WebContentsImpl
*>(new_shell
->web_contents())
2760 EXPECT_EQ(root
->child_at(0), popup_root
->opener());
2762 std::string opener_url
;
2763 EXPECT_TRUE(ExecuteScriptAndExtractString(
2764 popup_root
->current_frame_host(),
2765 "window.domAutomationController.send(window.opener.location.href);",
2767 EXPECT_EQ(frame_url
.spec(), opener_url
);
2769 // Now try the same with a cross-site popup and make sure it ends up in a new
2770 // process and with a correct opener.
2771 GURL
popup_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
2772 Shell
* cross_site_popup
=
2773 OpenPopup(root
->child_at(0)->current_frame_host(), popup_url
, "");
2774 EXPECT_TRUE(cross_site_popup
);
2776 FrameTreeNode
* cross_site_popup_root
=
2777 static_cast<WebContentsImpl
*>(cross_site_popup
->web_contents())
2780 EXPECT_EQ(cross_site_popup_root
->current_url(), popup_url
);
2782 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
2783 cross_site_popup
->web_contents()->GetSiteInstance());
2784 EXPECT_NE(root
->child_at(0)->current_frame_host()->GetSiteInstance(),
2785 cross_site_popup
->web_contents()->GetSiteInstance());
2787 EXPECT_EQ(root
->child_at(0), cross_site_popup_root
->opener());
2789 // Ensure the popup's window.opener points to the right subframe. Note that
2790 // we can't check the opener's location as above since it's cross-origin.
2791 bool success
= false;
2792 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2793 cross_site_popup_root
->current_frame_host(),
2794 "window.domAutomationController.send("
2795 " window.opener === window.opener.top.frames[0]);",
2797 EXPECT_TRUE(success
);
2800 // Verify that named frames are discoverable from their opener's ancestors.
2801 // See https://crbug.com/511474.
2802 // Disable this flaky test on the official cros-trunk for now.
2803 // See crbug.com/515302.
2804 #if defined(OFFICIAL_BUILD)
2805 #define MAYBE_DiscoverNamedFrameFromAncestorOfOpener \
2806 DISABLED_DiscoverNamedFrameFromAncestorOfOpener
2808 #define MAYBE_DiscoverNamedFrameFromAncestorOfOpener \
2809 DiscoverNamedFrameFromAncestorOfOpener
2810 #endif // defined(OFFICIAL_BUILD)
2811 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
2812 MAYBE_DiscoverNamedFrameFromAncestorOfOpener
) {
2814 embedded_test_server()->GetURL("a.com", "/site_per_process_main.html"));
2815 NavigateToURL(shell(), main_url
);
2817 // It is safe to obtain the root frame tree node here, as it doesn't change.
2818 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2822 // Navigate first child cross-site.
2823 GURL
frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
2824 NavigateFrameToURL(root
->child_at(0), frame_url
);
2826 // Open a popup named "foo" from the first child.
2827 Shell
* foo_shell
= OpenPopup(root
->child_at(0)->current_frame_host(),
2828 GURL(url::kAboutBlankURL
), "foo");
2829 EXPECT_TRUE(foo_shell
);
2831 // Check that a proxy was created for the "foo" popup in a.com.
2832 FrameTreeNode
* foo_root
=
2833 static_cast<WebContentsImpl
*>(foo_shell
->web_contents())
2836 SiteInstance
* site_instance_a
= root
->current_frame_host()->GetSiteInstance();
2837 RenderFrameProxyHost
* popup_rfph_for_a
=
2838 foo_root
->render_manager()->GetRenderFrameProxyHost(site_instance_a
);
2839 EXPECT_TRUE(popup_rfph_for_a
);
2841 // Verify that the main frame can find the "foo" popup by name. If
2842 // window.open targets the correct frame, the "foo" popup's current URL
2843 // should be updated to |named_frame_url|.
2844 GURL
named_frame_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
2845 NavigateNamedFrame(shell()->web_contents(), named_frame_url
, "foo");
2846 EXPECT_TRUE(WaitForLoadStop(foo_shell
->web_contents()));
2847 EXPECT_EQ(named_frame_url
, foo_root
->current_url());
2849 // Navigate the popup cross-site and ensure it's still reachable via
2850 // window.open from the main frame.
2851 GURL
d_url(embedded_test_server()->GetURL("d.com", "/title3.html"));
2852 NavigateToURL(foo_shell
, d_url
);
2853 EXPECT_EQ(d_url
, foo_root
->current_url());
2854 NavigateNamedFrame(shell()->web_contents(), named_frame_url
, "foo");
2855 EXPECT_TRUE(WaitForLoadStop(foo_shell
->web_contents()));
2856 EXPECT_EQ(named_frame_url
, foo_root
->current_url());
2859 // Similar to DiscoverNamedFrameFromAncestorOfOpener, but check that if a
2860 // window is created without a name and acquires window.name later, it will
2861 // still be discoverable from its opener's ancestors. Also, instead of using
2862 // an opener's ancestor, this test uses a popup with same origin as that
2863 // ancestor. See https://crbug.com/511474.
2864 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
2865 DiscoverFrameAfterSettingWindowName
) {
2867 embedded_test_server()->GetURL("a.com", "/site_per_process_main.html"));
2868 NavigateToURL(shell(), main_url
);
2870 // It is safe to obtain the root frame tree node here, as it doesn't change.
2871 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2875 // Open a same-site popup from the main frame.
2876 GURL
a_com_url(embedded_test_server()->GetURL("a.com", "/title3.html"));
2877 Shell
* a_com_shell
=
2878 OpenPopup(root
->child_at(0)->current_frame_host(), a_com_url
, "");
2879 EXPECT_TRUE(a_com_shell
);
2881 // Navigate first child on main frame cross-site.
2882 GURL
frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
2883 NavigateFrameToURL(root
->child_at(0), frame_url
);
2885 // Open an unnamed popup from the first child frame.
2886 Shell
* foo_shell
= OpenPopup(root
->child_at(0)->current_frame_host(),
2887 GURL(url::kAboutBlankURL
), "");
2888 EXPECT_TRUE(foo_shell
);
2890 // There should be no proxy created for the "foo" popup in a.com, since
2891 // there's no way for the two a.com frames to access it yet.
2892 FrameTreeNode
* foo_root
=
2893 static_cast<WebContentsImpl
*>(foo_shell
->web_contents())
2896 SiteInstance
* site_instance_a
= root
->current_frame_host()->GetSiteInstance();
2898 foo_root
->render_manager()->GetRenderFrameProxyHost(site_instance_a
));
2900 // Set window.name in the popup's frame.
2901 EXPECT_TRUE(ExecuteScript(foo_shell
->web_contents(), "window.name = 'foo'"));
2903 // A proxy for the popup should now exist in a.com.
2905 foo_root
->render_manager()->GetRenderFrameProxyHost(site_instance_a
));
2907 // Verify that the a.com popup can now find the "foo" popup by name.
2908 GURL
named_frame_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
2909 NavigateNamedFrame(a_com_shell
->web_contents(), named_frame_url
, "foo");
2910 EXPECT_TRUE(WaitForLoadStop(foo_shell
->web_contents()));
2911 EXPECT_EQ(named_frame_url
, foo_root
->current_url());
2914 } // namespace content