Move browser-to-renderer opener plumbing to frame routing IDs.
[chromium-blink-merge.git] / content / browser / site_per_process_browsertest.cc
blobc5514f65877f626e21c0a2542325bd26ee9a9310
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/site_per_process_browsertest.h"
7 #include <algorithm>
8 #include <vector>
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"
41 namespace content {
43 namespace {
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 bool success = false;
53 EXPECT_TRUE(ExecuteScriptAndExtractBool(
54 sender_ftn->current_frame_host(),
55 "window.domAutomationController.send(" + post_message_script + ");",
56 &success));
57 EXPECT_TRUE(success);
59 content::DOMMessageQueue msg_queue;
60 std::string status;
61 while (msg_queue.WaitForMessage(&status)) {
62 if (status == reply_status)
63 break;
67 // Helper function to extract and return "window.receivedMessages" from the
68 // |sender_ftn| frame. This variable is used in post_message.html to count the
69 // number of messages received via postMessage by the current window.
70 int GetReceivedMessages(FrameTreeNode* ftn) {
71 int received_messages = 0;
72 EXPECT_TRUE(ExecuteScriptAndExtractInt(
73 ftn->current_frame_host(),
74 "window.domAutomationController.send(window.receivedMessages);",
75 &received_messages));
76 return received_messages;
79 class RedirectNotificationObserver : public NotificationObserver {
80 public:
81 // Register to listen for notifications of the given type from either a
82 // specific source, or from all sources if |source| is
83 // NotificationService::AllSources().
84 RedirectNotificationObserver(int notification_type,
85 const NotificationSource& source);
86 ~RedirectNotificationObserver() override;
88 // Wait until the specified notification occurs. If the notification was
89 // emitted between the construction of this object and this call then it
90 // returns immediately.
91 void Wait();
93 // Returns NotificationService::AllSources() if we haven't observed a
94 // notification yet.
95 const NotificationSource& source() const {
96 return source_;
99 const NotificationDetails& details() const {
100 return details_;
103 // NotificationObserver:
104 void Observe(int type,
105 const NotificationSource& source,
106 const NotificationDetails& details) override;
108 private:
109 bool seen_;
110 bool seen_twice_;
111 bool running_;
112 NotificationRegistrar registrar_;
114 NotificationSource source_;
115 NotificationDetails details_;
116 scoped_refptr<MessageLoopRunner> message_loop_runner_;
118 DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver);
121 RedirectNotificationObserver::RedirectNotificationObserver(
122 int notification_type,
123 const NotificationSource& source)
124 : seen_(false),
125 running_(false),
126 source_(NotificationService::AllSources()) {
127 registrar_.Add(this, notification_type, source);
130 RedirectNotificationObserver::~RedirectNotificationObserver() {}
132 void RedirectNotificationObserver::Wait() {
133 if (seen_ && seen_twice_)
134 return;
136 running_ = true;
137 message_loop_runner_ = new MessageLoopRunner;
138 message_loop_runner_->Run();
139 EXPECT_TRUE(seen_);
142 void RedirectNotificationObserver::Observe(
143 int type,
144 const NotificationSource& source,
145 const NotificationDetails& details) {
146 source_ = source;
147 details_ = details;
148 seen_twice_ = seen_;
149 seen_ = true;
150 if (!running_)
151 return;
153 message_loop_runner_->Quit();
154 running_ = false;
157 // This observer keeps track of the number of created RenderFrameHosts. Tests
158 // can use this to ensure that a certain number of child frames has been
159 // created after navigating.
160 class RenderFrameHostCreatedObserver : public WebContentsObserver {
161 public:
162 RenderFrameHostCreatedObserver(WebContents* web_contents,
163 int expected_frame_count)
164 : WebContentsObserver(web_contents),
165 expected_frame_count_(expected_frame_count),
166 frames_created_(0),
167 message_loop_runner_(new MessageLoopRunner) {}
169 ~RenderFrameHostCreatedObserver() override;
171 // Runs a nested message loop and blocks until the expected number of
172 // RenderFrameHosts is created.
173 void Wait();
175 private:
176 // WebContentsObserver
177 void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
179 // The number of RenderFrameHosts to wait for.
180 int expected_frame_count_;
182 // The number of RenderFrameHosts that have been created.
183 int frames_created_;
185 // The MessageLoopRunner used to spin the message loop.
186 scoped_refptr<MessageLoopRunner> message_loop_runner_;
188 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver);
191 RenderFrameHostCreatedObserver::~RenderFrameHostCreatedObserver() {
194 void RenderFrameHostCreatedObserver::Wait() {
195 message_loop_runner_->Run();
198 void RenderFrameHostCreatedObserver::RenderFrameCreated(
199 RenderFrameHost* render_frame_host) {
200 frames_created_++;
201 if (frames_created_ == expected_frame_count_) {
202 message_loop_runner_->Quit();
206 // A WebContentsDelegate that catches messages sent to the console.
207 class ConsoleObserverDelegate : public WebContentsDelegate {
208 public:
209 ConsoleObserverDelegate(WebContents* web_contents, const std::string& filter)
210 : web_contents_(web_contents),
211 filter_(filter),
212 message_(""),
213 message_loop_runner_(new MessageLoopRunner) {}
215 ~ConsoleObserverDelegate() override {}
217 bool AddMessageToConsole(WebContents* source,
218 int32 level,
219 const base::string16& message,
220 int32 line_no,
221 const base::string16& source_id) override;
223 std::string message() { return message_; }
225 void Wait();
227 private:
228 WebContents* web_contents_;
229 std::string filter_;
230 std::string message_;
232 // The MessageLoopRunner used to spin the message loop.
233 scoped_refptr<MessageLoopRunner> message_loop_runner_;
235 DISALLOW_COPY_AND_ASSIGN(ConsoleObserverDelegate);
238 void ConsoleObserverDelegate::Wait() {
239 message_loop_runner_->Run();
242 bool ConsoleObserverDelegate::AddMessageToConsole(
243 WebContents* source,
244 int32 level,
245 const base::string16& message,
246 int32 line_no,
247 const base::string16& source_id) {
248 DCHECK(source == web_contents_);
250 std::string ascii_message = base::UTF16ToASCII(message);
251 if (base::MatchPattern(ascii_message, filter_)) {
252 message_ = ascii_message;
253 message_loop_runner_->Quit();
255 return false;
258 } // namespace
261 // SitePerProcessBrowserTest
264 SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
267 std::string SitePerProcessBrowserTest::DepictFrameTree(FrameTreeNode* node) {
268 return visualizer_.DepictFrameTree(node);
271 void SitePerProcessBrowserTest::StartFrameAtDataURL() {
272 std::string data_url_script =
273 "var iframes = document.getElementById('test');iframes.src="
274 "'data:text/html,dataurl';";
275 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script));
278 void SitePerProcessBrowserTest::SetUpCommandLine(
279 base::CommandLine* command_line) {
280 command_line->AppendSwitch(switches::kSitePerProcess);
283 void SitePerProcessBrowserTest::SetUpOnMainThread() {
284 host_resolver()->AddRule("*", "127.0.0.1");
285 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
286 SetupCrossSiteRedirector(embedded_test_server());
289 // Ensure that navigating subframes in --site-per-process mode works and the
290 // correct documents are committed.
291 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
292 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
293 NavigateToURL(shell(), main_url);
295 // It is safe to obtain the root frame tree node here, as it doesn't change.
296 FrameTreeNode* root =
297 static_cast<WebContentsImpl*>(shell()->web_contents())->
298 GetFrameTree()->root();
300 TestNavigationObserver observer(shell()->web_contents());
302 // Load same-site page into iframe.
303 FrameTreeNode* child = root->child_at(0);
304 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
305 NavigateFrameToURL(child, http_url);
306 EXPECT_EQ(http_url, observer.last_navigation_url());
307 EXPECT_TRUE(observer.last_navigation_succeeded());
309 // There should be only one RenderWidgetHost when there are no
310 // cross-process iframes.
311 std::set<RenderWidgetHostView*> views_set =
312 static_cast<WebContentsImpl*>(shell()->web_contents())
313 ->GetRenderWidgetHostViewsInTree();
314 EXPECT_EQ(1U, views_set.size());
317 EXPECT_EQ(
318 " Site A\n"
319 " |--Site A\n"
320 " +--Site A\n"
321 " |--Site A\n"
322 " +--Site A\n"
323 " +--Site A\n"
324 "Where A = http://127.0.0.1/",
325 DepictFrameTree(root));
327 // Load cross-site page into iframe.
328 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
329 NavigateFrameToURL(root->child_at(0), url);
330 // Verify that the navigation succeeded and the expected URL was loaded.
331 EXPECT_TRUE(observer.last_navigation_succeeded());
332 EXPECT_EQ(url, observer.last_navigation_url());
334 // Ensure that we have created a new process for the subframe.
335 ASSERT_EQ(2U, root->child_count());
336 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
337 RenderViewHost* rvh = child->current_frame_host()->render_view_host();
338 RenderProcessHost* rph = child->current_frame_host()->GetProcess();
339 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
340 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
341 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph);
343 // There should be now two RenderWidgetHosts, one for each process
344 // rendering a frame.
345 std::set<RenderWidgetHostView*> views_set =
346 static_cast<WebContentsImpl*>(shell()->web_contents())
347 ->GetRenderWidgetHostViewsInTree();
348 EXPECT_EQ(2U, views_set.size());
350 RenderFrameProxyHost* proxy_to_parent =
351 child->render_manager()->GetProxyToParent();
352 EXPECT_TRUE(proxy_to_parent);
353 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
354 // The out-of-process iframe should have its own RenderWidgetHost,
355 // independent of any RenderViewHost.
356 EXPECT_NE(
357 rvh->GetView(),
358 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
359 EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
361 EXPECT_EQ(
362 " Site A ------------ proxies for B\n"
363 " |--Site B ------- proxies for A\n"
364 " +--Site A ------- proxies for B\n"
365 " |--Site A -- proxies for B\n"
366 " +--Site A -- proxies for B\n"
367 " +--Site A -- proxies for B\n"
368 "Where A = http://127.0.0.1/\n"
369 " B = http://foo.com/",
370 DepictFrameTree(root));
372 // Load another cross-site page into the same iframe.
373 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
374 NavigateFrameToURL(root->child_at(0), url);
375 EXPECT_TRUE(observer.last_navigation_succeeded());
376 EXPECT_EQ(url, observer.last_navigation_url());
378 // Check again that a new process is created and is different from the
379 // top level one and the previous one.
380 ASSERT_EQ(2U, root->child_count());
381 child = root->child_at(0);
382 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
383 child->current_frame_host()->render_view_host());
384 EXPECT_NE(rvh, child->current_frame_host()->render_view_host());
385 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
386 child->current_frame_host()->GetSiteInstance());
387 EXPECT_NE(site_instance,
388 child->current_frame_host()->GetSiteInstance());
389 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
390 child->current_frame_host()->GetProcess());
391 EXPECT_NE(rph, child->current_frame_host()->GetProcess());
393 std::set<RenderWidgetHostView*> views_set =
394 static_cast<WebContentsImpl*>(shell()->web_contents())
395 ->GetRenderWidgetHostViewsInTree();
396 EXPECT_EQ(2U, views_set.size());
398 EXPECT_EQ(proxy_to_parent, child->render_manager()->GetProxyToParent());
399 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
400 EXPECT_NE(
401 child->current_frame_host()->render_view_host()->GetView(),
402 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
403 EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
405 EXPECT_EQ(
406 " Site A ------------ proxies for C\n"
407 " |--Site C ------- proxies for A\n"
408 " +--Site A ------- proxies for C\n"
409 " |--Site A -- proxies for C\n"
410 " +--Site A -- proxies for C\n"
411 " +--Site A -- proxies for C\n"
412 "Where A = http://127.0.0.1/\n"
413 " C = http://bar.com/",
414 DepictFrameTree(root));
417 // Tests OOPIF rendering by checking that the RWH of the iframe generates
418 // OnSwapCompositorFrame message.
419 #if defined(OS_ANDROID)
420 // http://crbug.com/471850
421 #define MAYBE_CompositorFrameSwapped DISABLED_CompositorFrameSwapped
422 #else
423 #define MAYBE_CompositorFrameSwapped CompositorFrameSwapped
424 #endif
425 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
426 MAYBE_CompositorFrameSwapped) {
427 GURL main_url(
428 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
429 NavigateToURL(shell(), main_url);
431 // It is safe to obtain the root frame tree node here, as it doesn't change.
432 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
433 ->GetFrameTree()
434 ->root();
435 ASSERT_EQ(1U, root->child_count());
437 FrameTreeNode* child_node = root->child_at(0);
438 GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
439 EXPECT_EQ(site_url, child_node->current_url());
440 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
441 child_node->current_frame_host()->GetSiteInstance());
442 RenderWidgetHostViewBase* rwhv_base = static_cast<RenderWidgetHostViewBase*>(
443 child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
445 // Wait for OnSwapCompositorFrame message.
446 while (rwhv_base->RendererFrameNumber() <= 0) {
447 // TODO(lazyboy): Find a better way to avoid sleeping like this. See
448 // http://crbug.com/405282 for details.
449 base::RunLoop run_loop;
450 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
451 FROM_HERE, run_loop.QuitClosure(),
452 base::TimeDelta::FromMilliseconds(10));
453 run_loop.Run();
457 // Ensure that OOPIFs are deleted after navigating to a new main frame.
458 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CleanupCrossSiteIframe) {
459 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
460 NavigateToURL(shell(), main_url);
462 // It is safe to obtain the root frame tree node here, as it doesn't change.
463 FrameTreeNode* root =
464 static_cast<WebContentsImpl*>(shell()->web_contents())->
465 GetFrameTree()->root();
467 TestNavigationObserver observer(shell()->web_contents());
469 // Load a cross-site page into both iframes.
470 GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html");
471 NavigateFrameToURL(root->child_at(0), foo_url);
472 EXPECT_TRUE(observer.last_navigation_succeeded());
473 EXPECT_EQ(foo_url, observer.last_navigation_url());
474 NavigateFrameToURL(root->child_at(1), foo_url);
475 EXPECT_TRUE(observer.last_navigation_succeeded());
476 EXPECT_EQ(foo_url, observer.last_navigation_url());
478 // Ensure that we have created a new process for the subframes.
479 EXPECT_EQ(
480 " Site A ------------ proxies for B\n"
481 " |--Site B ------- proxies for A\n"
482 " +--Site B ------- proxies for A\n"
483 "Where A = http://127.0.0.1/\n"
484 " B = http://foo.com/",
485 DepictFrameTree(root));
487 int subframe_process_id = root->child_at(0)
488 ->current_frame_host()
489 ->GetSiteInstance()
490 ->GetProcess()
491 ->GetID();
492 int subframe_rvh_id = root->child_at(0)
493 ->current_frame_host()
494 ->render_view_host()
495 ->GetRoutingID();
496 EXPECT_TRUE(RenderViewHost::FromID(subframe_process_id, subframe_rvh_id));
498 // Use Javascript in the parent to remove one of the frames and ensure that
499 // the subframe goes away.
500 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
501 "document.body.removeChild("
502 "document.querySelectorAll('iframe')[0])"));
503 ASSERT_EQ(1U, root->child_count());
505 // Load a new same-site page in the top-level frame and ensure the other
506 // subframe goes away.
507 GURL new_url(embedded_test_server()->GetURL("/title1.html"));
508 NavigateToURL(shell(), new_url);
509 ASSERT_EQ(0U, root->child_count());
511 // Ensure the RVH for the subframe gets cleaned up when the frame goes away.
512 EXPECT_FALSE(RenderViewHost::FromID(subframe_process_id, subframe_rvh_id));
515 // Ensure that root frames cannot be detached.
516 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RestrictFrameDetach) {
517 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
518 NavigateToURL(shell(), main_url);
520 // It is safe to obtain the root frame tree node here, as it doesn't change.
521 FrameTreeNode* root =
522 static_cast<WebContentsImpl*>(shell()->web_contents())->
523 GetFrameTree()->root();
525 TestNavigationObserver observer(shell()->web_contents());
527 // Load cross-site pages into both iframes.
528 GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html");
529 NavigateFrameToURL(root->child_at(0), foo_url);
530 EXPECT_TRUE(observer.last_navigation_succeeded());
531 EXPECT_EQ(foo_url, observer.last_navigation_url());
532 GURL bar_url = embedded_test_server()->GetURL("bar.com", "/title2.html");
533 NavigateFrameToURL(root->child_at(1), bar_url);
534 EXPECT_TRUE(observer.last_navigation_succeeded());
535 EXPECT_EQ(bar_url, observer.last_navigation_url());
537 // Ensure that we have created new processes for the subframes.
538 ASSERT_EQ(2U, root->child_count());
539 FrameTreeNode* foo_child = root->child_at(0);
540 SiteInstance* foo_site_instance =
541 foo_child->current_frame_host()->GetSiteInstance();
542 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), foo_site_instance);
543 FrameTreeNode* bar_child = root->child_at(1);
544 SiteInstance* bar_site_instance =
545 bar_child->current_frame_host()->GetSiteInstance();
546 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), bar_site_instance);
548 EXPECT_EQ(
549 " Site A ------------ proxies for B C\n"
550 " |--Site B ------- proxies for A C\n"
551 " +--Site C ------- proxies for A B\n"
552 "Where A = http://127.0.0.1/\n"
553 " B = http://foo.com/\n"
554 " C = http://bar.com/",
555 DepictFrameTree(root));
557 // Simulate an attempt to detach the root frame from foo_site_instance. This
558 // should kill foo_site_instance's process.
559 RenderFrameProxyHost* foo_mainframe_rfph =
560 root->render_manager()->GetRenderFrameProxyHost(foo_site_instance);
561 content::RenderProcessHostWatcher foo_terminated(
562 foo_mainframe_rfph->GetProcess(),
563 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
564 FrameHostMsg_Detach evil_msg2(foo_mainframe_rfph->GetRoutingID());
565 IPC::IpcSecurityTestUtil::PwnMessageReceived(
566 foo_mainframe_rfph->GetProcess()->GetChannel(), evil_msg2);
567 foo_terminated.Wait();
569 EXPECT_EQ(
570 " Site A ------------ proxies for B C\n"
571 " |--Site B ------- proxies for A C\n"
572 " +--Site C ------- proxies for A B\n"
573 "Where A = http://127.0.0.1/\n"
574 " B = http://foo.com/ (no process)\n"
575 " C = http://bar.com/",
576 DepictFrameTree(root));
579 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
580 NavigateRemoteFrame) {
581 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
582 NavigateToURL(shell(), main_url);
584 // It is safe to obtain the root frame tree node here, as it doesn't change.
585 FrameTreeNode* root =
586 static_cast<WebContentsImpl*>(shell()->web_contents())->
587 GetFrameTree()->root();
589 TestNavigationObserver observer(shell()->web_contents());
591 // Load same-site page into iframe.
592 FrameTreeNode* child = root->child_at(0);
593 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
594 NavigateFrameToURL(child, http_url);
595 EXPECT_EQ(http_url, observer.last_navigation_url());
596 EXPECT_TRUE(observer.last_navigation_succeeded());
598 // Load cross-site page into iframe.
599 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
600 NavigateFrameToURL(root->child_at(0), url);
601 EXPECT_TRUE(observer.last_navigation_succeeded());
602 EXPECT_EQ(url, observer.last_navigation_url());
604 // Ensure that we have created a new process for the subframe.
605 ASSERT_EQ(2U, root->child_count());
606 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
607 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
609 // Emulate the main frame changing the src of the iframe such that it
610 // navigates cross-site.
611 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
612 NavigateIframeToURL(shell()->web_contents(), "test", url);
613 EXPECT_TRUE(observer.last_navigation_succeeded());
614 EXPECT_EQ(url, observer.last_navigation_url());
616 // Check again that a new process is created and is different from the
617 // top level one and the previous one.
618 ASSERT_EQ(2U, root->child_count());
619 child = root->child_at(0);
620 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
621 child->current_frame_host()->GetSiteInstance());
622 EXPECT_NE(site_instance,
623 child->current_frame_host()->GetSiteInstance());
625 // Navigate back to the parent's origin and ensure we return to the
626 // parent's process.
627 NavigateFrameToURL(child, http_url);
628 EXPECT_EQ(http_url, observer.last_navigation_url());
629 EXPECT_TRUE(observer.last_navigation_succeeded());
630 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
631 child->current_frame_host()->GetSiteInstance());
634 #if defined(OS_WIN)
635 // http://crbug.com/465722
636 #define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
637 DISABLED_NavigateRemoteFrameToBlankAndDataURLs
638 #else
639 #define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
640 NavigateRemoteFrameToBlankAndDataURLs
641 #endif
643 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
644 MAYBE_NavigateRemoteFrameToBlankAndDataURLs) {
645 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
646 NavigateToURL(shell(), main_url);
648 // It is safe to obtain the root frame tree node here, as it doesn't change.
649 FrameTreeNode* root =
650 static_cast<WebContentsImpl*>(shell()->web_contents())->
651 GetFrameTree()->root();
653 TestNavigationObserver observer(shell()->web_contents());
655 // Load same-site page into iframe.
656 FrameTreeNode* child = root->child_at(0);
657 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
658 NavigateFrameToURL(child, http_url);
659 EXPECT_EQ(http_url, observer.last_navigation_url());
660 EXPECT_TRUE(observer.last_navigation_succeeded());
662 // Load cross-site page into iframe.
663 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
664 NavigateFrameToURL(root->child_at(0), url);
665 EXPECT_TRUE(observer.last_navigation_succeeded());
666 EXPECT_EQ(url, observer.last_navigation_url());
667 ASSERT_EQ(2U, root->child_count());
668 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
669 root->child_at(0)->current_frame_host()->GetSiteInstance());
671 // Navigate iframe to a data URL. The navigation happens from a script in the
672 // parent frame, so the data URL should be committed in the same SiteInstance
673 // as the parent frame.
674 GURL data_url("data:text/html,dataurl");
675 NavigateIframeToURL(shell()->web_contents(), "test", data_url);
676 EXPECT_TRUE(observer.last_navigation_succeeded());
677 EXPECT_EQ(data_url, observer.last_navigation_url());
679 // Ensure that we have navigated using the top level process.
680 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
681 root->child_at(0)->current_frame_host()->GetSiteInstance());
683 // Load cross-site page into iframe.
684 url = embedded_test_server()->GetURL("bar.com", "/title2.html");
685 NavigateFrameToURL(root->child_at(0), url);
686 EXPECT_TRUE(observer.last_navigation_succeeded());
687 EXPECT_EQ(url, observer.last_navigation_url());
688 ASSERT_EQ(2U, root->child_count());
689 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
690 root->child_at(0)->current_frame_host()->GetSiteInstance());
692 // Navigate iframe to about:blank. The navigation happens from a script in the
693 // parent frame, so it should be committed in the same SiteInstance as the
694 // parent frame.
695 GURL about_blank_url("about:blank");
696 NavigateIframeToURL(shell()->web_contents(), "test", about_blank_url);
697 EXPECT_TRUE(observer.last_navigation_succeeded());
698 EXPECT_EQ(about_blank_url, observer.last_navigation_url());
700 // Ensure that we have navigated using the top level process.
701 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
702 root->child_at(0)->current_frame_host()->GetSiteInstance());
705 // This test checks that killing a renderer process of a remote frame
706 // and then navigating some other frame to the same SiteInstance of the killed
707 // process works properly.
708 // This can be illustrated as follows,
709 // where 1/2/3 are FrameTreeNode-s and A/B are processes and B* is the killed
710 // B process:
712 // 1 A A A
713 // / \ -> / \ -> Kill B -> / \ -> Navigate 3 to B -> / \ .
714 // 2 3 B A B* A B* B
716 // Initially, node1.proxy_hosts_ = {B}
717 // After we kill B, we make sure B stays in node1.proxy_hosts_, then we navigate
718 // 3 to B and we expect that to complete normally.
719 // See http://crbug.com/432107.
721 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
722 // site B and stays in not rendered state.
723 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
724 NavigateRemoteFrameToKilledProcess) {
725 GURL main_url(embedded_test_server()->GetURL(
726 "/frame_tree/page_with_two_frames.html"));
727 NavigateToURL(shell(), main_url);
729 // It is safe to obtain the root frame tree node here, as it doesn't change.
730 FrameTreeNode* root =
731 static_cast<WebContentsImpl*>(shell()->web_contents())->
732 GetFrameTree()->root();
734 TestNavigationObserver observer(shell()->web_contents());
735 ASSERT_EQ(2U, root->child_count());
737 // Make sure node2 points to the correct cross-site page.
738 GURL site_b_url = embedded_test_server()->GetURL("bar.com", "/title1.html");
739 FrameTreeNode* node2 = root->child_at(0);
740 EXPECT_EQ(site_b_url, node2->current_url());
742 // Kill that cross-site renderer.
743 RenderProcessHost* child_process =
744 node2->current_frame_host()->GetProcess();
745 RenderProcessHostWatcher crash_observer(
746 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
747 child_process->Shutdown(0, false);
748 crash_observer.Wait();
750 // Now navigate the second iframe (node3) to the same site as the node2.
751 FrameTreeNode* node3 = root->child_at(1);
752 NavigateFrameToURL(node3, site_b_url);
753 EXPECT_TRUE(observer.last_navigation_succeeded());
754 EXPECT_EQ(site_b_url, observer.last_navigation_url());
757 // This test is similar to
758 // SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess with
759 // addition that node2 also has a cross-origin frame to site C.
761 // 1 A A A
762 // / \ / \ / \ / \ .
763 // 2 3 -> B A -> Kill B -> B* A -> Navigate 3 -> B* B
764 // / /
765 // 4 C
767 // Initially, node1.proxy_hosts_ = {B, C}
768 // After we kill B, we make sure B stays in node1.proxy_hosts_, but
769 // C gets cleared from node1.proxy_hosts_.
771 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
772 // site B and stays in not rendered state.
773 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
774 NavigateRemoteFrameToKilledProcessWithSubtree) {
775 GURL main_url(embedded_test_server()->GetURL(
776 "a.com", "/frame_tree/page_with_two_frames_nested.html"));
777 NavigateToURL(shell(), main_url);
779 // It is safe to obtain the root frame tree node here, as it doesn't change.
780 FrameTreeNode* root =
781 static_cast<WebContentsImpl*>(shell()->web_contents())->
782 GetFrameTree()->root();
783 TestNavigationObserver observer(shell()->web_contents());
785 ASSERT_EQ(2U, root->child_count());
787 GURL site_b_url(
788 embedded_test_server()->GetURL(
789 "bar.com", "/frame_tree/page_with_one_frame.html"));
790 // We can't use a TestNavigationObserver to verify the URL here,
791 // since the frame has children that may have clobbered it in the observer.
792 EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
794 // Ensure that a new process is created for node2.
795 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
796 root->child_at(0)->current_frame_host()->GetSiteInstance());
797 // Ensure that a new process is *not* created for node3.
798 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
799 root->child_at(1)->current_frame_host()->GetSiteInstance());
801 ASSERT_EQ(1U, root->child_at(0)->child_count());
803 // Make sure node4 points to the correct cross-site page.
804 FrameTreeNode* node4 = root->child_at(0)->child_at(0);
805 GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
806 EXPECT_EQ(site_c_url, node4->current_url());
808 // |site_instance_c| is expected to go away once we kill |child_process_b|
809 // below, so create a local scope so we can extend the lifetime of
810 // |site_instance_c| with a refptr.
812 // Initially each frame has proxies for the other sites.
813 EXPECT_EQ(
814 " Site A ------------ proxies for B C\n"
815 " |--Site B ------- proxies for A C\n"
816 " | +--Site C -- proxies for A B\n"
817 " +--Site A ------- proxies for B C\n"
818 "Where A = http://a.com/\n"
819 " B = http://bar.com/\n"
820 " C = http://baz.com/",
821 DepictFrameTree(root));
823 // Kill the render process for Site B.
824 RenderProcessHost* child_process_b =
825 root->child_at(0)->current_frame_host()->GetProcess();
826 RenderProcessHostWatcher crash_observer(
827 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
828 child_process_b->Shutdown(0, false);
829 crash_observer.Wait();
831 // The Site C frame (a child of the crashed Site B frame) should go away,
832 // and there should be no remaining proxies for site C anywhere.
833 EXPECT_EQ(
834 " Site A ------------ proxies for B\n"
835 " |--Site B ------- proxies for A\n"
836 " +--Site A ------- proxies for B\n"
837 "Where A = http://a.com/\n"
838 " B = http://bar.com/ (no process)",
839 DepictFrameTree(root));
842 // Now navigate the second iframe (node3) to Site B also.
843 FrameTreeNode* node3 = root->child_at(1);
844 GURL url = embedded_test_server()->GetURL("bar.com", "/title1.html");
845 NavigateFrameToURL(node3, url);
846 EXPECT_TRUE(observer.last_navigation_succeeded());
847 EXPECT_EQ(url, observer.last_navigation_url());
849 EXPECT_EQ(
850 " Site A ------------ proxies for B\n"
851 " |--Site B ------- proxies for A\n"
852 " +--Site B ------- proxies for A\n"
853 "Where A = http://a.com/\n"
854 " B = http://bar.com/",
855 DepictFrameTree(root));
858 // Verify that killing a cross-site frame's process B and then navigating a
859 // frame to B correctly recreates all proxies in B.
861 // 1 A A A
862 // / | \ / | \ / | \ / | \ .
863 // 2 3 4 -> B A A -> Kill B -> B* A A -> B* B A
865 // After the last step, the test sends a postMessage from node 3 to node 4,
866 // verifying that a proxy for node 4 has been recreated in process B. This
867 // verifies the fix for https://crbug.com/478892.
868 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
869 NavigatingToKilledProcessRestoresAllProxies) {
870 // Navigate to a page with three frames: one cross-site and two same-site.
871 GURL main_url(embedded_test_server()->GetURL(
872 "a.com", "/frame_tree/page_with_three_frames.html"));
873 NavigateToURL(shell(), main_url);
875 // It is safe to obtain the root frame tree node here, as it doesn't change.
876 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
877 ->GetFrameTree()
878 ->root();
879 TestNavigationObserver observer(shell()->web_contents());
881 EXPECT_EQ(
882 " Site A ------------ proxies for B\n"
883 " |--Site B ------- proxies for A\n"
884 " |--Site A ------- proxies for B\n"
885 " +--Site A ------- proxies for B\n"
886 "Where A = http://a.com/\n"
887 " B = http://b.com/",
888 DepictFrameTree(root));
890 // Kill the first subframe's b.com renderer.
891 RenderProcessHost* child_process =
892 root->child_at(0)->current_frame_host()->GetProcess();
893 RenderProcessHostWatcher crash_observer(
894 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
895 child_process->Shutdown(0, false);
896 crash_observer.Wait();
898 // Navigate the second subframe to b.com to recreate the b.com process.
899 GURL b_url = embedded_test_server()->GetURL("b.com", "/post_message.html");
900 NavigateFrameToURL(root->child_at(1), b_url);
901 // TODO(alexmos): This can be removed once TestFrameNavigationObserver is
902 // fixed to use DidFinishLoad.
903 EXPECT_TRUE(
904 WaitForRenderFrameReady(root->child_at(1)->current_frame_host()));
905 EXPECT_TRUE(observer.last_navigation_succeeded());
906 EXPECT_EQ(b_url, observer.last_navigation_url());
907 EXPECT_TRUE(root->child_at(1)->current_frame_host()->IsRenderFrameLive());
909 EXPECT_EQ(
910 " Site A ------------ proxies for B\n"
911 " |--Site B ------- proxies for A\n"
912 " |--Site B ------- proxies for A\n"
913 " +--Site A ------- proxies for B\n"
914 "Where A = http://a.com/\n"
915 " B = http://b.com/",
916 DepictFrameTree(root));
918 // Check that third subframe's proxy is available in the b.com process by
919 // sending it a postMessage from second subframe, and waiting for a reply.
920 PostMessageAndWaitForReply(root->child_at(1),
921 "postToSibling('subframe-msg','frame3')",
922 "\"done-frame2\"");
925 // Verify that proxy creation doesn't recreate a crashed process if no frame
926 // will be created in it.
928 // 1 A A A
929 // / | \ / | \ / | \ / | \ .
930 // 2 3 4 -> B A A -> Kill B -> B* A A -> B* A A
931 // \ .
932 // A
934 // The test kills process B (node 2), creates a child frame of node 4 in
935 // process A, and then checks that process B isn't resurrected to create a
936 // proxy for the new child frame. See https://crbug.com/476846.
937 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
938 CreateChildFrameAfterKillingProcess) {
939 // Navigate to a page with three frames: one cross-site and two same-site.
940 GURL main_url(embedded_test_server()->GetURL(
941 "a.com", "/frame_tree/page_with_three_frames.html"));
942 EXPECT_TRUE(NavigateToURL(shell(), main_url));
944 // It is safe to obtain the root frame tree node here, as it doesn't change.
945 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
946 ->GetFrameTree()
947 ->root();
949 EXPECT_EQ(
950 " Site A ------------ proxies for B\n"
951 " |--Site B ------- proxies for A\n"
952 " |--Site A ------- proxies for B\n"
953 " +--Site A ------- proxies for B\n"
954 "Where A = http://a.com/\n"
955 " B = http://b.com/",
956 DepictFrameTree(root));
957 SiteInstance* b_site_instance =
958 root->child_at(0)->current_frame_host()->GetSiteInstance();
960 // Kill the first subframe's renderer (B).
961 RenderProcessHost* child_process =
962 root->child_at(0)->current_frame_host()->GetProcess();
963 RenderProcessHostWatcher crash_observer(
964 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
965 child_process->Shutdown(0, false);
966 crash_observer.Wait();
968 // Add a new child frame to the third subframe.
969 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
970 EXPECT_TRUE(ExecuteScript(
971 root->child_at(2)->current_frame_host(),
972 "document.body.appendChild(document.createElement('iframe'));"));
973 frame_observer.Wait();
975 // The new frame should have a RenderFrameProxyHost for B, but it should not
976 // be alive, and B should still not have a process (verified by last line of
977 // expected DepictFrameTree output).
978 EXPECT_EQ(
979 " Site A ------------ proxies for B\n"
980 " |--Site B ------- proxies for A\n"
981 " |--Site A ------- proxies for B\n"
982 " +--Site A ------- proxies for B\n"
983 " +--Site A -- proxies for B\n"
984 "Where A = http://a.com/\n"
985 " B = http://b.com/ (no process)",
986 DepictFrameTree(root));
987 FrameTreeNode* grandchild = root->child_at(2)->child_at(0);
988 RenderFrameProxyHost* grandchild_rfph =
989 grandchild->render_manager()->GetRenderFrameProxyHost(b_site_instance);
990 EXPECT_FALSE(grandchild_rfph->is_render_frame_proxy_live());
992 // Navigate the second subframe to b.com to recreate process B.
993 TestNavigationObserver observer(shell()->web_contents());
994 GURL b_url = embedded_test_server()->GetURL("b.com", "/title1.html");
995 NavigateFrameToURL(root->child_at(1), b_url);
996 EXPECT_TRUE(observer.last_navigation_succeeded());
997 EXPECT_EQ(b_url, observer.last_navigation_url());
999 // Ensure that the grandchild RenderFrameProxy in B was created when process
1000 // B was restored.
1001 EXPECT_TRUE(grandchild_rfph->is_render_frame_proxy_live());
1004 // Verify that creating a child frame after killing and reloading an opener
1005 // process doesn't crash. See https://crbug.com/501152.
1006 // 1. Navigate to site A.
1007 // 2. Open a popup with window.open and navigate it cross-process to site B.
1008 // 3. Kill process A for the original tab.
1009 // 4. Reload the original tab to resurrect process A.
1010 // 5. Add a child frame to the top-level frame in the popup tab B.
1011 // In step 5, we try to create proxies for the child frame in all SiteInstances
1012 // for which its parent has proxies. This includes A. However, even though
1013 // process A is live (step 4), the parent proxy in A is not live (which was
1014 // incorrectly assumed previously). This is because step 4 does not resurrect
1015 // proxies for popups opened before the crash.
1016 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1017 CreateChildFrameAfterKillingOpener) {
1018 GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
1019 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1021 // It is safe to obtain the root frame tree node here, as it doesn't change.
1022 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1023 ->GetFrameTree()
1024 ->root();
1025 SiteInstance* site_instance_a = root->current_frame_host()->GetSiteInstance();
1027 // Open a popup and navigate it cross-process to b.com.
1028 ShellAddedObserver new_shell_observer;
1029 EXPECT_TRUE(ExecuteScript(root->current_frame_host(),
1030 "popup = window.open('about:blank');"));
1031 Shell* popup = new_shell_observer.GetShell();
1032 GURL popup_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
1033 EXPECT_TRUE(NavigateToURL(popup, popup_url));
1035 // Verify that each top-level frame has proxies in the other's SiteInstance.
1036 FrameTreeNode* popup_root =
1037 static_cast<WebContentsImpl*>(popup->web_contents())
1038 ->GetFrameTree()
1039 ->root();
1040 EXPECT_EQ(
1041 " Site A ------------ proxies for B\n"
1042 "Where A = http://a.com/\n"
1043 " B = http://b.com/",
1044 DepictFrameTree(root));
1045 EXPECT_EQ(
1046 " Site B ------------ proxies for A\n"
1047 "Where A = http://a.com/\n"
1048 " B = http://b.com/",
1049 DepictFrameTree(popup_root));
1051 // Kill the first window's renderer (a.com).
1052 RenderProcessHost* child_process = root->current_frame_host()->GetProcess();
1053 RenderProcessHostWatcher crash_observer(
1054 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1055 child_process->Shutdown(0, false);
1056 crash_observer.Wait();
1057 EXPECT_FALSE(root->current_frame_host()->IsRenderFrameLive());
1059 // The proxy for the popup in a.com should've died.
1060 RenderFrameProxyHost* rfph =
1061 popup_root->render_manager()->GetRenderFrameProxyHost(site_instance_a);
1062 EXPECT_FALSE(rfph->is_render_frame_proxy_live());
1064 // Recreate the a.com renderer.
1065 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1066 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
1068 // The popup's proxy in a.com should still not be live. Re-navigating the
1069 // main window to a.com doesn't reinitialize a.com proxies for popups
1070 // previously opened from the main window.
1071 EXPECT_FALSE(rfph->is_render_frame_proxy_live());
1073 // Add a new child frame on the popup.
1074 RenderFrameHostCreatedObserver frame_observer(popup->web_contents(), 1);
1075 EXPECT_TRUE(ExecuteScript(
1076 popup->web_contents(),
1077 "document.body.appendChild(document.createElement('iframe'));"));
1078 frame_observer.Wait();
1080 // Both the child frame's and its parent's proxies should still not be live.
1081 // The main page can't reach them since it lost reference to the popup after
1082 // it crashed, so there is no need to create them.
1083 EXPECT_FALSE(rfph->is_render_frame_proxy_live());
1084 RenderFrameProxyHost* child_rfph =
1085 popup_root->child_at(0)->render_manager()->GetRenderFrameProxyHost(
1086 site_instance_a);
1087 EXPECT_TRUE(child_rfph);
1088 EXPECT_FALSE(child_rfph->is_render_frame_proxy_live());
1091 // In A-embed-B-embed-C scenario, verify that killing process B clears proxies
1092 // of C from the tree.
1094 // 1 A A
1095 // / \ / \ / \ .
1096 // 2 3 -> B A -> Kill B -> B* A
1097 // / /
1098 // 4 C
1100 // node1 is the root.
1101 // Initially, both node1.proxy_hosts_ and node3.proxy_hosts_ contain C.
1102 // After we kill B, make sure proxies for C are cleared.
1103 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1104 KillingRendererClearsDescendantProxies) {
1105 GURL main_url(embedded_test_server()->GetURL(
1106 "a.com", "/frame_tree/page_with_two_frames_nested.html"));
1107 NavigateToURL(shell(), main_url);
1109 // It is safe to obtain the root frame tree node here, as it doesn't change.
1110 FrameTreeNode* root =
1111 static_cast<WebContentsImpl*>(shell()->web_contents())->
1112 GetFrameTree()->root();
1113 ASSERT_EQ(2U, root->child_count());
1115 GURL site_b_url(
1116 embedded_test_server()->GetURL(
1117 "bar.com", "/frame_tree/page_with_one_frame.html"));
1118 // We can't use a TestNavigationObserver to verify the URL here,
1119 // since the frame has children that may have clobbered it in the observer.
1120 EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
1122 // Ensure that a new process is created for node2.
1123 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1124 root->child_at(0)->current_frame_host()->GetSiteInstance());
1125 // Ensure that a new process is *not* created for node3.
1126 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
1127 root->child_at(1)->current_frame_host()->GetSiteInstance());
1129 ASSERT_EQ(1U, root->child_at(0)->child_count());
1131 // Make sure node4 points to the correct cross-site-page.
1132 FrameTreeNode* node4 = root->child_at(0)->child_at(0);
1133 GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
1134 EXPECT_EQ(site_c_url, node4->current_url());
1136 // |site_instance_c|'s frames and proxies are expected to go away once we kill
1137 // |child_process_b| below.
1138 scoped_refptr<SiteInstanceImpl> site_instance_c =
1139 node4->current_frame_host()->GetSiteInstance();
1141 // Initially proxies for both B and C will be present in the root.
1142 EXPECT_EQ(
1143 " Site A ------------ proxies for B C\n"
1144 " |--Site B ------- proxies for A C\n"
1145 " | +--Site C -- proxies for A B\n"
1146 " +--Site A ------- proxies for B C\n"
1147 "Where A = http://a.com/\n"
1148 " B = http://bar.com/\n"
1149 " C = http://baz.com/",
1150 DepictFrameTree(root));
1152 EXPECT_GT(site_instance_c->active_frame_count(), 0U);
1154 // Kill process B.
1155 RenderProcessHost* child_process_b =
1156 root->child_at(0)->current_frame_host()->GetProcess();
1157 RenderProcessHostWatcher crash_observer(
1158 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1159 child_process_b->Shutdown(0, false);
1160 crash_observer.Wait();
1162 // Make sure proxy C has gone from root.
1163 // Make sure proxy C has gone from node3 as well.
1164 // Make sure proxy B stays around in root and node3.
1165 EXPECT_EQ(
1166 " Site A ------------ proxies for B\n"
1167 " |--Site B ------- proxies for A\n"
1168 " +--Site A ------- proxies for B\n"
1169 "Where A = http://a.com/\n"
1170 " B = http://bar.com/ (no process)",
1171 DepictFrameTree(root));
1173 EXPECT_EQ(0U, site_instance_c->active_frame_count());
1176 // Crash a subframe and ensures its children are cleared from the FrameTree.
1177 // See http://crbug.com/338508.
1178 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrashSubframe) {
1179 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1180 NavigateToURL(shell(), main_url);
1182 StartFrameAtDataURL();
1184 // Load cross-site page into iframe.
1185 EXPECT_TRUE(NavigateIframeToURL(
1186 shell()->web_contents(), "test",
1187 embedded_test_server()->GetURL("/cross-site/foo.com/title2.html")));
1189 // Check the subframe process.
1190 FrameTreeNode* root =
1191 static_cast<WebContentsImpl*>(shell()->web_contents())->
1192 GetFrameTree()->root();
1193 ASSERT_EQ(2U, root->child_count());
1194 FrameTreeNode* child = root->child_at(0);
1195 EXPECT_EQ(main_url, root->current_url());
1196 EXPECT_EQ("foo.com", child->current_url().host());
1197 EXPECT_EQ("/title2.html", child->current_url().path());
1199 EXPECT_TRUE(
1200 child->current_frame_host()->render_view_host()->IsRenderViewLive());
1201 EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
1203 // Crash the subframe process.
1204 RenderProcessHost* root_process = root->current_frame_host()->GetProcess();
1205 RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
1207 RenderProcessHostWatcher crash_observer(
1208 child_process,
1209 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1210 child_process->Shutdown(0, false);
1211 crash_observer.Wait();
1214 // Ensure that the child frame still exists but has been cleared.
1215 EXPECT_EQ(2U, root->child_count());
1216 EXPECT_EQ(main_url, root->current_url());
1217 EXPECT_EQ(GURL(), child->current_url());
1219 EXPECT_FALSE(
1220 child->current_frame_host()->render_view_host()->IsRenderViewLive());
1221 EXPECT_FALSE(child->current_frame_host()->IsRenderFrameLive());
1222 EXPECT_FALSE(child->current_frame_host()->render_frame_created_);
1224 // Now crash the top-level page to clear the child frame.
1226 RenderProcessHostWatcher crash_observer(
1227 root_process,
1228 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1229 root_process->Shutdown(0, false);
1230 crash_observer.Wait();
1232 EXPECT_EQ(0U, root->child_count());
1233 EXPECT_EQ(GURL(), root->current_url());
1236 // When a new subframe is added, related SiteInstances that can reach the
1237 // subframe should create proxies for it (https://crbug.com/423587). This test
1238 // checks that if A embeds B and later adds a new subframe A2, A2 gets a proxy
1239 // in B's process.
1240 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CreateProxiesForNewFrames) {
1241 GURL main_url(embedded_test_server()->GetURL(
1242 "b.com", "/frame_tree/page_with_one_frame.html"));
1243 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1245 // It is safe to obtain the root frame tree node here, as it doesn't change.
1246 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1247 ->GetFrameTree()
1248 ->root();
1249 ASSERT_EQ(1U, root->child_count());
1251 // Make sure the frame starts out at the correct cross-site URL.
1252 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
1253 root->child_at(0)->current_url());
1255 EXPECT_EQ(
1256 " Site A ------------ proxies for B\n"
1257 " +--Site B ------- proxies for A\n"
1258 "Where A = http://b.com/\n"
1259 " B = http://baz.com/",
1260 DepictFrameTree(root));
1262 // Add a new child frame to the top-level frame.
1263 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
1264 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1265 "window.domAutomationController.send("
1266 " addFrame('data:text/html,foo'));"));
1267 frame_observer.Wait();
1269 // The new frame should have a proxy in Site B, for use by the old frame.
1270 EXPECT_EQ(
1271 " Site A ------------ proxies for B\n"
1272 " |--Site B ------- proxies for A\n"
1273 " +--Site A ------- proxies for B\n"
1274 "Where A = http://b.com/\n"
1275 " B = http://baz.com/",
1276 DepictFrameTree(root));
1279 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
1280 // security checks are back in place.
1281 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
1282 // on Android (http://crbug.com/187570).
1283 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1284 DISABLED_CrossSiteIframeRedirectOnce) {
1285 ASSERT_TRUE(test_server()->Start());
1286 net::SpawnedTestServer https_server(
1287 net::SpawnedTestServer::TYPE_HTTPS,
1288 net::SpawnedTestServer::kLocalhost,
1289 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1290 ASSERT_TRUE(https_server.Start());
1292 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
1293 GURL http_url(test_server()->GetURL("files/title1.html"));
1294 GURL https_url(https_server.GetURL("files/title1.html"));
1296 NavigateToURL(shell(), main_url);
1298 TestNavigationObserver observer(shell()->web_contents());
1300 // Load cross-site client-redirect page into Iframe.
1301 // Should be blocked.
1302 GURL client_redirect_https_url(https_server.GetURL(
1303 "client-redirect?files/title1.html"));
1304 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1305 client_redirect_https_url));
1306 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
1307 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
1308 EXPECT_FALSE(observer.last_navigation_succeeded());
1312 // Load cross-site server-redirect page into Iframe,
1313 // which redirects to same-site page.
1314 GURL server_redirect_http_url(https_server.GetURL(
1315 "server-redirect?" + http_url.spec()));
1316 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1317 server_redirect_http_url));
1318 EXPECT_EQ(observer.last_navigation_url(), http_url);
1319 EXPECT_TRUE(observer.last_navigation_succeeded());
1323 // Load cross-site server-redirect page into Iframe,
1324 // which redirects to cross-site page.
1325 GURL server_redirect_http_url(https_server.GetURL(
1326 "server-redirect?files/title1.html"));
1327 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1328 server_redirect_http_url));
1329 // DidFailProvisionalLoad when navigating to https_url.
1330 EXPECT_EQ(observer.last_navigation_url(), https_url);
1331 EXPECT_FALSE(observer.last_navigation_succeeded());
1335 // Load same-site server-redirect page into Iframe,
1336 // which redirects to cross-site page.
1337 GURL server_redirect_http_url(test_server()->GetURL(
1338 "server-redirect?" + https_url.spec()));
1339 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1340 server_redirect_http_url));
1342 EXPECT_EQ(observer.last_navigation_url(), https_url);
1343 EXPECT_FALSE(observer.last_navigation_succeeded());
1347 // Load same-site client-redirect page into Iframe,
1348 // which redirects to cross-site page.
1349 GURL client_redirect_http_url(test_server()->GetURL(
1350 "client-redirect?" + https_url.spec()));
1352 RedirectNotificationObserver load_observer2(
1353 NOTIFICATION_LOAD_STOP,
1354 Source<NavigationController>(
1355 &shell()->web_contents()->GetController()));
1357 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1358 client_redirect_http_url));
1360 // Same-site Client-Redirect Page should be loaded successfully.
1361 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1362 EXPECT_TRUE(observer.last_navigation_succeeded());
1364 // Redirecting to Cross-site Page should be blocked.
1365 load_observer2.Wait();
1366 EXPECT_EQ(observer.last_navigation_url(), https_url);
1367 EXPECT_FALSE(observer.last_navigation_succeeded());
1371 // Load same-site server-redirect page into Iframe,
1372 // which redirects to same-site page.
1373 GURL server_redirect_http_url(test_server()->GetURL(
1374 "server-redirect?files/title1.html"));
1375 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1376 server_redirect_http_url));
1377 EXPECT_EQ(observer.last_navigation_url(), http_url);
1378 EXPECT_TRUE(observer.last_navigation_succeeded());
1382 // Load same-site client-redirect page into Iframe,
1383 // which redirects to same-site page.
1384 GURL client_redirect_http_url(test_server()->GetURL(
1385 "client-redirect?" + http_url.spec()));
1386 RedirectNotificationObserver load_observer2(
1387 NOTIFICATION_LOAD_STOP,
1388 Source<NavigationController>(
1389 &shell()->web_contents()->GetController()));
1391 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1392 client_redirect_http_url));
1394 // Same-site Client-Redirect Page should be loaded successfully.
1395 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1396 EXPECT_TRUE(observer.last_navigation_succeeded());
1398 // Redirecting to Same-site Page should be loaded successfully.
1399 load_observer2.Wait();
1400 EXPECT_EQ(observer.last_navigation_url(), http_url);
1401 EXPECT_TRUE(observer.last_navigation_succeeded());
1405 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
1406 // security checks are back in place.
1407 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
1408 // on Android (http://crbug.com/187570).
1409 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1410 DISABLED_CrossSiteIframeRedirectTwice) {
1411 ASSERT_TRUE(test_server()->Start());
1412 net::SpawnedTestServer https_server(
1413 net::SpawnedTestServer::TYPE_HTTPS,
1414 net::SpawnedTestServer::kLocalhost,
1415 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1416 ASSERT_TRUE(https_server.Start());
1418 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
1419 GURL http_url(test_server()->GetURL("files/title1.html"));
1420 GURL https_url(https_server.GetURL("files/title1.html"));
1422 NavigateToURL(shell(), main_url);
1424 TestNavigationObserver observer(shell()->web_contents());
1426 // Load client-redirect page pointing to a cross-site client-redirect page,
1427 // which eventually redirects back to same-site page.
1428 GURL client_redirect_https_url(https_server.GetURL(
1429 "client-redirect?" + http_url.spec()));
1430 GURL client_redirect_http_url(test_server()->GetURL(
1431 "client-redirect?" + client_redirect_https_url.spec()));
1433 // We should wait until second client redirect get cancelled.
1434 RedirectNotificationObserver load_observer2(
1435 NOTIFICATION_LOAD_STOP,
1436 Source<NavigationController>(
1437 &shell()->web_contents()->GetController()));
1439 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1440 client_redirect_http_url));
1442 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
1443 load_observer2.Wait();
1444 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
1445 EXPECT_FALSE(observer.last_navigation_succeeded());
1449 // Load server-redirect page pointing to a cross-site server-redirect page,
1450 // which eventually redirect back to same-site page.
1451 GURL server_redirect_https_url(https_server.GetURL(
1452 "server-redirect?" + http_url.spec()));
1453 GURL server_redirect_http_url(test_server()->GetURL(
1454 "server-redirect?" + server_redirect_https_url.spec()));
1455 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1456 server_redirect_http_url));
1457 EXPECT_EQ(observer.last_navigation_url(), http_url);
1458 EXPECT_TRUE(observer.last_navigation_succeeded());
1462 // Load server-redirect page pointing to a cross-site server-redirect page,
1463 // which eventually redirects back to cross-site page.
1464 GURL server_redirect_https_url(https_server.GetURL(
1465 "server-redirect?" + https_url.spec()));
1466 GURL server_redirect_http_url(test_server()->GetURL(
1467 "server-redirect?" + server_redirect_https_url.spec()));
1468 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1469 server_redirect_http_url));
1471 // DidFailProvisionalLoad when navigating to https_url.
1472 EXPECT_EQ(observer.last_navigation_url(), https_url);
1473 EXPECT_FALSE(observer.last_navigation_succeeded());
1477 // Load server-redirect page pointing to a cross-site client-redirect page,
1478 // which eventually redirects back to same-site page.
1479 GURL client_redirect_http_url(https_server.GetURL(
1480 "client-redirect?" + http_url.spec()));
1481 GURL server_redirect_http_url(test_server()->GetURL(
1482 "server-redirect?" + client_redirect_http_url.spec()));
1483 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1484 server_redirect_http_url));
1486 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
1487 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1488 EXPECT_FALSE(observer.last_navigation_succeeded());
1492 // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
1493 // created in the FrameTree skipping the subtree of the navigating frame.
1494 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1495 ProxyCreationSkipsSubtree) {
1496 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1497 NavigateToURL(shell(), main_url);
1499 // It is safe to obtain the root frame tree node here, as it doesn't change.
1500 FrameTreeNode* root =
1501 static_cast<WebContentsImpl*>(shell()->web_contents())->
1502 GetFrameTree()->root();
1504 EXPECT_TRUE(root->child_at(1) != NULL);
1505 EXPECT_EQ(2U, root->child_at(1)->child_count());
1508 // Load same-site page into iframe.
1509 TestNavigationObserver observer(shell()->web_contents());
1510 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
1511 NavigateFrameToURL(root->child_at(0), http_url);
1512 EXPECT_EQ(http_url, observer.last_navigation_url());
1513 EXPECT_TRUE(observer.last_navigation_succeeded());
1514 EXPECT_EQ(
1515 " Site A\n"
1516 " |--Site A\n"
1517 " +--Site A\n"
1518 " |--Site A\n"
1519 " +--Site A\n"
1520 " +--Site A\n"
1521 "Where A = http://127.0.0.1/",
1522 DepictFrameTree(root));
1525 // Create the cross-site URL to navigate to.
1526 GURL cross_site_url =
1527 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html");
1529 // Load cross-site page into the second iframe without waiting for the
1530 // navigation to complete. Once LoadURLWithParams returns, we would expect
1531 // proxies to have been created in the frame tree, but children of the
1532 // navigating frame to still be present. The reason is that we don't run the
1533 // message loop, so no IPCs that alter the frame tree can be processed.
1534 FrameTreeNode* child = root->child_at(1);
1535 SiteInstance* site = NULL;
1536 bool browser_side_navigation =
1537 base::CommandLine::ForCurrentProcess()->HasSwitch(
1538 switches::kEnableBrowserSideNavigation);
1539 std::string cross_site_rfh_type =
1540 browser_side_navigation ? "speculative" : "pending";
1542 TestNavigationObserver observer(shell()->web_contents());
1543 TestFrameNavigationObserver navigation_observer(child);
1544 NavigationController::LoadURLParams params(cross_site_url);
1545 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
1546 params.frame_tree_node_id = child->frame_tree_node_id();
1547 child->navigator()->GetController()->LoadURLWithParams(params);
1549 if (browser_side_navigation) {
1550 site = child->render_manager()
1551 ->speculative_frame_host()
1552 ->GetSiteInstance();
1553 } else {
1554 site = child->render_manager()->pending_frame_host()->GetSiteInstance();
1556 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site);
1558 std::string tree = base::StringPrintf(
1559 " Site A ------------ proxies for B\n"
1560 " |--Site A ------- proxies for B\n"
1561 " +--Site A (B %s)\n"
1562 " |--Site A\n"
1563 " +--Site A\n"
1564 " +--Site A\n"
1565 "Where A = http://127.0.0.1/\n"
1566 " B = http://foo.com/",
1567 cross_site_rfh_type.c_str());
1568 EXPECT_EQ(tree, DepictFrameTree(root));
1570 // Now that the verification is done, run the message loop and wait for the
1571 // navigation to complete.
1572 navigation_observer.Wait();
1573 EXPECT_FALSE(child->render_manager()->pending_frame_host());
1574 EXPECT_TRUE(observer.last_navigation_succeeded());
1575 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
1577 EXPECT_EQ(
1578 " Site A ------------ proxies for B\n"
1579 " |--Site A ------- proxies for B\n"
1580 " +--Site B ------- proxies for A\n"
1581 "Where A = http://127.0.0.1/\n"
1582 " B = http://foo.com/",
1583 DepictFrameTree(root));
1586 // Load another cross-site page into the same iframe.
1587 cross_site_url = embedded_test_server()->GetURL("bar.com", "/title2.html");
1589 // Perform the same checks as the first cross-site navigation, since
1590 // there have been issues in subsequent cross-site navigations. Also ensure
1591 // that the SiteInstance has properly changed.
1592 // TODO(nasko): Once we have proper cleanup of resources, add code to
1593 // verify that the intermediate SiteInstance/RenderFrameHost have been
1594 // properly cleaned up.
1595 TestNavigationObserver observer(shell()->web_contents());
1596 TestFrameNavigationObserver navigation_observer(child);
1597 NavigationController::LoadURLParams params(cross_site_url);
1598 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
1599 params.frame_tree_node_id = child->frame_tree_node_id();
1600 child->navigator()->GetController()->LoadURLWithParams(params);
1602 SiteInstance* site2;
1603 if (browser_side_navigation) {
1604 site2 = child->render_manager()
1605 ->speculative_frame_host()
1606 ->GetSiteInstance();
1607 } else {
1608 site2 = child->render_manager()->pending_frame_host()->GetSiteInstance();
1610 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2);
1611 EXPECT_NE(site, site2);
1613 std::string tree = base::StringPrintf(
1614 " Site A ------------ proxies for B C\n"
1615 " |--Site A ------- proxies for B C\n"
1616 " +--Site B (C %s) -- proxies for A\n"
1617 "Where A = http://127.0.0.1/\n"
1618 " B = http://foo.com/\n"
1619 " C = http://bar.com/",
1620 cross_site_rfh_type.c_str());
1621 EXPECT_EQ(tree, DepictFrameTree(root));
1623 navigation_observer.Wait();
1624 EXPECT_TRUE(observer.last_navigation_succeeded());
1625 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
1626 EXPECT_EQ(0U, child->child_count());
1630 // Verify that origin replication works for an A-embed-B-embed-C hierarchy.
1631 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginReplication) {
1632 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1633 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1635 // It is safe to obtain the root frame tree node here, as it doesn't change.
1636 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1637 ->GetFrameTree()
1638 ->root();
1640 TestNavigationObserver observer(shell()->web_contents());
1642 // Navigate the first subframe to a cross-site page with two subframes.
1643 GURL foo_url(
1644 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1645 NavigateFrameToURL(root->child_at(0), foo_url);
1646 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1648 // We can't use a TestNavigationObserver to verify the URL here,
1649 // since the frame has children that may have clobbered it in the observer.
1650 EXPECT_EQ(foo_url, root->child_at(0)->current_url());
1652 // Ensure that a new process is created for the subframe.
1653 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1654 root->child_at(0)->current_frame_host()->GetSiteInstance());
1656 // Load cross-site page into subframe's subframe.
1657 ASSERT_EQ(2U, root->child_at(0)->child_count());
1658 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1659 NavigateFrameToURL(root->child_at(0)->child_at(0), bar_url);
1660 EXPECT_TRUE(observer.last_navigation_succeeded());
1661 EXPECT_EQ(bar_url, observer.last_navigation_url());
1663 // Check that a new process is created and is different from the top one and
1664 // the middle one.
1665 FrameTreeNode* bottom_child = root->child_at(0)->child_at(0);
1666 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1667 bottom_child->current_frame_host()->GetSiteInstance());
1668 EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
1669 bottom_child->current_frame_host()->GetSiteInstance());
1671 // Check that foo.com frame's location.ancestorOrigins contains the correct
1672 // origin for the parent. The origin should have been replicated as part of
1673 // the ViewMsg_New message that created the parent's RenderFrameProxy in
1674 // foo.com's process.
1675 int ancestor_origins_length = 0;
1676 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1677 root->child_at(0)->current_frame_host(),
1678 "window.domAutomationController.send(location.ancestorOrigins.length);",
1679 &ancestor_origins_length));
1680 EXPECT_EQ(1, ancestor_origins_length);
1681 std::string result;
1682 EXPECT_TRUE(ExecuteScriptAndExtractString(
1683 root->child_at(0)->current_frame_host(),
1684 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1685 &result));
1686 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1688 // Check that bar.com frame's location.ancestorOrigins contains the correct
1689 // origin for its two ancestors. The topmost parent origin should be
1690 // replicated as part of ViewMsg_New, and the middle frame (foo.com's) origin
1691 // should be replicated as part of FrameMsg_NewFrameProxy sent for foo.com's
1692 // frame in bar.com's process.
1693 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1694 bottom_child->current_frame_host(),
1695 "window.domAutomationController.send(location.ancestorOrigins.length);",
1696 &ancestor_origins_length));
1697 EXPECT_EQ(2, ancestor_origins_length);
1698 EXPECT_TRUE(ExecuteScriptAndExtractString(
1699 bottom_child->current_frame_host(),
1700 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1701 &result));
1702 EXPECT_EQ(result + "/", foo_url.GetOrigin().spec());
1703 EXPECT_TRUE(ExecuteScriptAndExtractString(
1704 bottom_child->current_frame_host(),
1705 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1706 &result));
1707 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1710 // Check that iframe sandbox flags are replicated correctly.
1711 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SandboxFlagsReplication) {
1712 GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
1713 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1715 // It is safe to obtain the root frame tree node here, as it doesn't change.
1716 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1717 ->GetFrameTree()
1718 ->root();
1720 TestNavigationObserver observer(shell()->web_contents());
1722 // Navigate the second (sandboxed) subframe to a cross-site page with a
1723 // subframe.
1724 GURL foo_url(
1725 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1726 NavigateFrameToURL(root->child_at(1), foo_url);
1727 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1729 // We can't use a TestNavigationObserver to verify the URL here,
1730 // since the frame has children that may have clobbered it in the observer.
1731 EXPECT_EQ(foo_url, root->child_at(1)->current_url());
1733 // Load cross-site page into subframe's subframe.
1734 ASSERT_EQ(2U, root->child_at(1)->child_count());
1735 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1736 NavigateFrameToURL(root->child_at(1)->child_at(0), bar_url);
1737 EXPECT_TRUE(observer.last_navigation_succeeded());
1738 EXPECT_EQ(bar_url, observer.last_navigation_url());
1740 // Opening a popup in the sandboxed foo.com iframe should fail.
1741 bool success = false;
1742 EXPECT_TRUE(
1743 ExecuteScriptAndExtractBool(root->child_at(1)->current_frame_host(),
1744 "window.domAutomationController.send("
1745 "!window.open('data:text/html,dataurl'));",
1746 &success));
1747 EXPECT_TRUE(success);
1748 EXPECT_EQ(1u, Shell::windows().size());
1750 // Opening a popup in a frame whose parent is sandboxed should also fail.
1751 // Here, bar.com frame's sandboxed parent frame is a remote frame in
1752 // bar.com's process.
1753 success = false;
1754 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1755 root->child_at(1)->child_at(0)->current_frame_host(),
1756 "window.domAutomationController.send("
1757 "!window.open('data:text/html,dataurl'));",
1758 &success));
1759 EXPECT_TRUE(success);
1760 EXPECT_EQ(1u, Shell::windows().size());
1762 // Same, but now try the case where bar.com frame's sandboxed parent is a
1763 // local frame in bar.com's process.
1764 success = false;
1765 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1766 root->child_at(2)->child_at(0)->current_frame_host(),
1767 "window.domAutomationController.send("
1768 "!window.open('data:text/html,dataurl'));",
1769 &success));
1770 EXPECT_TRUE(success);
1771 EXPECT_EQ(1u, Shell::windows().size());
1773 // Check that foo.com frame's location.ancestorOrigins contains the correct
1774 // origin for the parent, which should be unaffected by sandboxing.
1775 int ancestor_origins_length = 0;
1776 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1777 root->child_at(1)->current_frame_host(),
1778 "window.domAutomationController.send(location.ancestorOrigins.length);",
1779 &ancestor_origins_length));
1780 EXPECT_EQ(1, ancestor_origins_length);
1781 std::string result;
1782 EXPECT_TRUE(ExecuteScriptAndExtractString(
1783 root->child_at(1)->current_frame_host(),
1784 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1785 &result));
1786 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1788 // Now check location.ancestorOrigins for the bar.com frame. The middle frame
1789 // (foo.com's) origin should be unique, since that frame is sandboxed, and
1790 // the top frame should match |main_url|.
1791 FrameTreeNode* bottom_child = root->child_at(1)->child_at(0);
1792 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1793 bottom_child->current_frame_host(),
1794 "window.domAutomationController.send(location.ancestorOrigins.length);",
1795 &ancestor_origins_length));
1796 EXPECT_EQ(2, ancestor_origins_length);
1797 EXPECT_TRUE(ExecuteScriptAndExtractString(
1798 bottom_child->current_frame_host(),
1799 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1800 &result));
1801 EXPECT_EQ("null", result);
1802 EXPECT_TRUE(ExecuteScriptAndExtractString(
1803 bottom_child->current_frame_host(),
1804 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1805 &result));
1806 EXPECT_EQ(main_url.GetOrigin().spec(), result + "/");
1809 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1810 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicSandboxFlags) {
1811 GURL main_url(
1812 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1813 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1815 // It is safe to obtain the root frame tree node here, as it doesn't change.
1816 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1817 ->GetFrameTree()
1818 ->root();
1820 TestNavigationObserver observer(shell()->web_contents());
1821 ASSERT_EQ(2U, root->child_count());
1823 // Make sure first frame starts out at the correct cross-site page.
1824 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
1825 root->child_at(0)->current_url());
1827 // Navigate second frame to another cross-site page.
1828 GURL baz_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
1829 NavigateFrameToURL(root->child_at(1), baz_url);
1830 EXPECT_TRUE(observer.last_navigation_succeeded());
1831 EXPECT_EQ(baz_url, observer.last_navigation_url());
1833 // Both frames should not be sandboxed to start with.
1834 EXPECT_EQ(blink::WebSandboxFlags::None,
1835 root->child_at(0)->current_replication_state().sandbox_flags);
1836 EXPECT_EQ(blink::WebSandboxFlags::None,
1837 root->child_at(0)->effective_sandbox_flags());
1838 EXPECT_EQ(blink::WebSandboxFlags::None,
1839 root->child_at(1)->current_replication_state().sandbox_flags);
1840 EXPECT_EQ(blink::WebSandboxFlags::None,
1841 root->child_at(1)->effective_sandbox_flags());
1843 // Dynamically update sandbox flags for the first frame.
1844 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1845 "window.domAutomationController.send("
1846 "document.querySelector('iframe').sandbox="
1847 "'allow-scripts');"));
1849 // Check that updated sandbox flags are propagated to browser process.
1850 // The new flags should be set in current_replication_state(), while
1851 // effective_sandbox_flags() should still reflect the old flags, because
1852 // sandbox flag updates take place only after navigations. "allow-scripts"
1853 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
1854 // per blink::parseSandboxPolicy().
1855 blink::WebSandboxFlags expected_flags =
1856 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
1857 ~blink::WebSandboxFlags::AutomaticFeatures;
1858 EXPECT_EQ(expected_flags,
1859 root->child_at(0)->current_replication_state().sandbox_flags);
1860 EXPECT_EQ(blink::WebSandboxFlags::None,
1861 root->child_at(0)->effective_sandbox_flags());
1863 // Navigate the first frame to a page on the same site. The new sandbox
1864 // flags should take effect.
1865 GURL bar_url(
1866 embedded_test_server()->GetURL("bar.com", "/frame_tree/2-4.html"));
1867 NavigateFrameToURL(root->child_at(0), bar_url);
1868 // (The new page has a subframe; wait for it to load as well.)
1869 ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
1870 EXPECT_EQ(bar_url, root->child_at(0)->current_url());
1871 ASSERT_EQ(1U, root->child_at(0)->child_count());
1873 EXPECT_EQ(
1874 " Site A ------------ proxies for B C\n"
1875 " |--Site B ------- proxies for A C\n"
1876 " | +--Site B -- proxies for A C\n"
1877 " +--Site C ------- proxies for A B\n"
1878 "Where A = http://127.0.0.1/\n"
1879 " B = http://bar.com/\n"
1880 " C = http://baz.com/",
1881 DepictFrameTree(root));
1883 // Confirm that the browser process has updated the frame's current sandbox
1884 // flags.
1885 EXPECT_EQ(expected_flags,
1886 root->child_at(0)->current_replication_state().sandbox_flags);
1887 EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
1889 // Opening a popup in the now-sandboxed frame should fail.
1890 bool success = false;
1891 EXPECT_TRUE(
1892 ExecuteScriptAndExtractBool(root->child_at(0)->current_frame_host(),
1893 "window.domAutomationController.send("
1894 "!window.open('data:text/html,dataurl'));",
1895 &success));
1896 EXPECT_TRUE(success);
1897 EXPECT_EQ(1u, Shell::windows().size());
1899 // Navigate the child of the now-sandboxed frame to a page on baz.com. The
1900 // child should inherit the latest sandbox flags from its parent frame, which
1901 // is currently a proxy in baz.com's renderer process. This checks that the
1902 // proxies of |root->child_at(0)| were also updated with the latest sandbox
1903 // flags.
1904 GURL baz_child_url(embedded_test_server()->GetURL("baz.com", "/title2.html"));
1905 NavigateFrameToURL(root->child_at(0)->child_at(0), baz_child_url);
1906 EXPECT_TRUE(observer.last_navigation_succeeded());
1907 EXPECT_EQ(baz_child_url, observer.last_navigation_url());
1909 EXPECT_EQ(
1910 " Site A ------------ proxies for B C\n"
1911 " |--Site B ------- proxies for A C\n"
1912 " | +--Site C -- proxies for A B\n"
1913 " +--Site C ------- proxies for A B\n"
1914 "Where A = http://127.0.0.1/\n"
1915 " B = http://bar.com/\n"
1916 " C = http://baz.com/",
1917 DepictFrameTree(root));
1919 // Opening a popup in the child of a sandboxed frame should fail.
1920 success = false;
1921 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1922 root->child_at(0)->child_at(0)->current_frame_host(),
1923 "window.domAutomationController.send("
1924 "!window.open('data:text/html,dataurl'));",
1925 &success));
1926 EXPECT_TRUE(success);
1927 EXPECT_EQ(1u, Shell::windows().size());
1930 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1931 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1932 DynamicSandboxFlagsRemoteToLocal) {
1933 GURL main_url(
1934 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1935 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1937 // It is safe to obtain the root frame tree node here, as it doesn't change.
1938 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1939 ->GetFrameTree()
1940 ->root();
1942 TestNavigationObserver observer(shell()->web_contents());
1943 ASSERT_EQ(2U, root->child_count());
1945 // Make sure the two frames starts out at correct URLs.
1946 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
1947 root->child_at(0)->current_url());
1948 EXPECT_EQ(embedded_test_server()->GetURL("/title1.html"),
1949 root->child_at(1)->current_url());
1951 // Update the second frame's sandbox flags.
1952 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1953 "window.domAutomationController.send("
1954 "document.querySelectorAll('iframe')[1].sandbox="
1955 "'allow-scripts');"));
1957 // Check that the current sandbox flags are updated but the effective
1958 // sandbox flags are not.
1959 blink::WebSandboxFlags expected_flags =
1960 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
1961 ~blink::WebSandboxFlags::AutomaticFeatures;
1962 EXPECT_EQ(expected_flags,
1963 root->child_at(1)->current_replication_state().sandbox_flags);
1964 EXPECT_EQ(blink::WebSandboxFlags::None,
1965 root->child_at(1)->effective_sandbox_flags());
1967 // Navigate the second subframe to a page on bar.com. This will trigger a
1968 // remote-to-local frame swap in bar.com's process. The target page has
1969 // another frame, so use TestFrameNavigationObserver to wait for all frames
1970 // to be loaded.
1971 TestFrameNavigationObserver frame_observer(root->child_at(1), 2);
1972 GURL bar_url(embedded_test_server()->GetURL(
1973 "bar.com", "/frame_tree/page_with_one_frame.html"));
1974 NavigateFrameToURL(root->child_at(1), bar_url);
1975 frame_observer.Wait();
1976 EXPECT_EQ(bar_url, root->child_at(1)->current_url());
1977 ASSERT_EQ(1U, root->child_at(1)->child_count());
1979 // Confirm that the browser process has updated the current sandbox flags.
1980 EXPECT_EQ(expected_flags,
1981 root->child_at(1)->current_replication_state().sandbox_flags);
1982 EXPECT_EQ(expected_flags, root->child_at(1)->effective_sandbox_flags());
1984 // Opening a popup in the sandboxed second frame should fail.
1985 bool success = false;
1986 EXPECT_TRUE(
1987 ExecuteScriptAndExtractBool(root->child_at(1)->current_frame_host(),
1988 "window.domAutomationController.send("
1989 "!window.open('data:text/html,dataurl'));",
1990 &success));
1991 EXPECT_TRUE(success);
1992 EXPECT_EQ(1u, Shell::windows().size());
1994 // Make sure that the child frame inherits the sandbox flags of its
1995 // now-sandboxed parent frame.
1996 success = false;
1997 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1998 root->child_at(1)->child_at(0)->current_frame_host(),
1999 "window.domAutomationController.send("
2000 "!window.open('data:text/html,dataurl'));",
2001 &success));
2002 EXPECT_TRUE(success);
2003 EXPECT_EQ(1u, Shell::windows().size());
2006 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
2007 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2008 DynamicSandboxFlagsRendererInitiatedNavigation) {
2009 GURL main_url(
2010 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
2011 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2013 // It is safe to obtain the root frame tree node here, as it doesn't change.
2014 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2015 ->GetFrameTree()
2016 ->root();
2018 TestNavigationObserver observer(shell()->web_contents());
2019 ASSERT_EQ(1U, root->child_count());
2021 // Make sure the frame starts out at the correct cross-site page.
2022 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
2023 root->child_at(0)->current_url());
2025 // The frame should not be sandboxed to start with.
2026 EXPECT_EQ(blink::WebSandboxFlags::None,
2027 root->child_at(0)->current_replication_state().sandbox_flags);
2028 EXPECT_EQ(blink::WebSandboxFlags::None,
2029 root->child_at(0)->effective_sandbox_flags());
2031 // Dynamically update the frame's sandbox flags.
2032 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
2033 "window.domAutomationController.send("
2034 "document.querySelector('iframe').sandbox="
2035 "'allow-scripts');"));
2037 // Check that updated sandbox flags are propagated to browser process.
2038 // The new flags should be set in current_replication_state(), while
2039 // effective_sandbox_flags() should still reflect the old flags, because
2040 // sandbox flag updates take place only after navigations. "allow-scripts"
2041 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
2042 // per blink::parseSandboxPolicy().
2043 blink::WebSandboxFlags expected_flags =
2044 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
2045 ~blink::WebSandboxFlags::AutomaticFeatures;
2046 EXPECT_EQ(expected_flags,
2047 root->child_at(0)->current_replication_state().sandbox_flags);
2048 EXPECT_EQ(blink::WebSandboxFlags::None,
2049 root->child_at(0)->effective_sandbox_flags());
2051 // Perform a renderer-initiated same-site navigation in the first frame. The
2052 // new sandbox flags should take effect.
2053 TestFrameNavigationObserver frame_observer(root->child_at(0));
2054 ASSERT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
2055 "window.location.href='/title2.html'"));
2056 frame_observer.Wait();
2057 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title2.html"),
2058 root->child_at(0)->current_url());
2060 // Confirm that the browser process has updated the frame's current sandbox
2061 // flags.
2062 EXPECT_EQ(expected_flags,
2063 root->child_at(0)->current_replication_state().sandbox_flags);
2064 EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
2066 // Opening a popup in the now-sandboxed frame should fail.
2067 bool success = false;
2068 EXPECT_TRUE(
2069 ExecuteScriptAndExtractBool(root->child_at(0)->current_frame_host(),
2070 "window.domAutomationController.send("
2071 "!window.open('data:text/html,dataurl'));",
2072 &success));
2073 EXPECT_TRUE(success);
2074 EXPECT_EQ(1u, Shell::windows().size());
2077 // Verify that when a new child frame is added, the proxies created for it in
2078 // other SiteInstances have correct sandbox flags and origin.
2080 // A A A
2081 // / / \ / \ .
2082 // B -> B A -> B A
2083 // \ .
2084 // B
2086 // The test checks sandbox flags and origin for the proxy added in step 2, by
2087 // checking whether the grandchild frame added in step 3 sees proper sandbox
2088 // flags and origin for its (remote) parent. This wasn't addressed when
2089 // https://crbug.com/423587 was fixed.
2090 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2091 ProxiesForNewChildFramesHaveCorrectReplicationState) {
2092 GURL main_url(
2093 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
2094 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2096 // It is safe to obtain the root frame tree node here, as it doesn't change.
2097 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2098 ->GetFrameTree()
2099 ->root();
2100 TestNavigationObserver observer(shell()->web_contents());
2102 EXPECT_EQ(
2103 " Site A ------------ proxies for B\n"
2104 " +--Site B ------- proxies for A\n"
2105 "Where A = http://127.0.0.1/\n"
2106 " B = http://baz.com/",
2107 DepictFrameTree(root));
2109 // In the root frame, add a new sandboxed local frame, which itself has a
2110 // child frame on baz.com. Wait for three RenderFrameHosts to be created:
2111 // the new sandboxed local frame, its child (while it's still local), and a
2112 // pending RFH when starting the cross-site navigation to baz.com.
2113 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 3);
2114 EXPECT_TRUE(
2115 ExecuteScript(root->current_frame_host(),
2116 "window.domAutomationController.send("
2117 " addFrame('/frame_tree/page_with_one_frame.html',"
2118 " 'allow-scripts allow-same-origin'))"));
2119 frame_observer.Wait();
2121 // Wait for the cross-site navigation to baz.com in the grandchild to finish.
2122 FrameTreeNode* bottom_child = root->child_at(1)->child_at(0);
2123 TestFrameNavigationObserver navigation_observer(bottom_child);
2124 navigation_observer.Wait();
2126 EXPECT_EQ(
2127 " Site A ------------ proxies for B\n"
2128 " |--Site B ------- proxies for A\n"
2129 " +--Site A ------- proxies for B\n"
2130 " +--Site B -- proxies for A\n"
2131 "Where A = http://127.0.0.1/\n"
2132 " B = http://baz.com/",
2133 DepictFrameTree(root));
2135 // Use location.ancestorOrigins to check that the grandchild on baz.com sees
2136 // correct origin for its parent.
2137 int ancestor_origins_length = 0;
2138 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2139 bottom_child->current_frame_host(),
2140 "window.domAutomationController.send(location.ancestorOrigins.length);",
2141 &ancestor_origins_length));
2142 EXPECT_EQ(2, ancestor_origins_length);
2143 std::string parent_origin;
2144 EXPECT_TRUE(ExecuteScriptAndExtractString(
2145 bottom_child->current_frame_host(),
2146 "window.domAutomationController.send(location.ancestorOrigins[0]);",
2147 &parent_origin));
2148 EXPECT_EQ(main_url.GetOrigin().spec(), parent_origin + "/");
2150 // Check that the sandbox flags in the browser process are correct.
2151 // "allow-scripts" resets both WebSandboxFlags::Scripts and
2152 // WebSandboxFlags::AutomaticFeatures bits per blink::parseSandboxPolicy().
2153 blink::WebSandboxFlags expected_flags =
2154 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
2155 ~blink::WebSandboxFlags::AutomaticFeatures &
2156 ~blink::WebSandboxFlags::Origin;
2157 EXPECT_EQ(expected_flags,
2158 root->child_at(1)->current_replication_state().sandbox_flags);
2160 // The child of the sandboxed frame should've inherited sandbox flags, so it
2161 // should not be able to create popups.
2162 bool success = false;
2163 EXPECT_TRUE(
2164 ExecuteScriptAndExtractBool(bottom_child->current_frame_host(),
2165 "window.domAutomationController.send("
2166 "!window.open('data:text/html,dataurl'));",
2167 &success));
2168 EXPECT_TRUE(success);
2169 EXPECT_EQ(1u, Shell::windows().size());
2172 // Verify that a child frame can retrieve the name property set by its parent.
2173 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, WindowNameReplication) {
2174 GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
2175 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2177 // It is safe to obtain the root frame tree node here, as it doesn't change.
2178 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2179 ->GetFrameTree()
2180 ->root();
2182 TestNavigationObserver observer(shell()->web_contents());
2184 // Load cross-site page into iframe.
2185 GURL frame_url =
2186 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
2187 NavigateFrameToURL(root->child_at(0), frame_url);
2188 EXPECT_TRUE(observer.last_navigation_succeeded());
2189 EXPECT_EQ(frame_url, observer.last_navigation_url());
2191 // Ensure that a new process is created for the subframe.
2192 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
2193 root->child_at(0)->current_frame_host()->GetSiteInstance());
2195 // Check that the window.name seen by the frame matches the name attribute
2196 // specified by its parent in the iframe tag.
2197 std::string result;
2198 EXPECT_TRUE(ExecuteScriptAndExtractString(
2199 root->child_at(0)->current_frame_host(),
2200 "window.domAutomationController.send(window.name);", &result));
2201 EXPECT_EQ("3-1-name", result);
2204 // Verify that dynamic updates to a frame's window.name propagate to the
2205 // frame's proxies, so that the latest frame names can be used in navigations.
2206 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicWindowName) {
2207 GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
2208 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2210 // It is safe to obtain the root frame tree node here, as it doesn't change.
2211 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2212 ->GetFrameTree()
2213 ->root();
2214 TestNavigationObserver observer(shell()->web_contents());
2216 // Load cross-site page into iframe.
2217 GURL frame_url =
2218 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
2219 NavigateFrameToURL(root->child_at(0), frame_url);
2220 EXPECT_TRUE(observer.last_navigation_succeeded());
2221 EXPECT_EQ(frame_url, observer.last_navigation_url());
2223 // Browser process should know the child frame's original window.name
2224 // specified in the iframe element.
2225 EXPECT_EQ(root->child_at(0)->frame_name(), "3-1-name");
2227 // Update the child frame's window.name.
2228 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
2229 "window.domAutomationController.send("
2230 "window.name = 'updated-name');"));
2232 // The change should propagate to the browser process.
2233 EXPECT_EQ(root->child_at(0)->frame_name(), "updated-name");
2235 // The proxy in the parent process should also receive the updated name.
2236 // Check that it can reference the child frame by its new name.
2237 bool success = false;
2238 EXPECT_TRUE(
2239 ExecuteScriptAndExtractBool(shell()->web_contents(),
2240 "window.domAutomationController.send("
2241 "frames['updated-name'] == frames[0]);",
2242 &success));
2243 EXPECT_TRUE(success);
2245 // Issue a renderer-initiated navigation from the root frame to the child
2246 // frame using the frame's name. Make sure correct frame is navigated.
2248 // TODO(alexmos): When blink::createWindow is refactored to handle
2249 // RemoteFrames, this should also be tested via window.open(url, frame_name)
2250 // and a more complicated frame hierarchy (https://crbug.com/463742)
2251 TestFrameNavigationObserver frame_observer(root->child_at(0));
2252 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
2253 std::string script = base::StringPrintf(
2254 "window.domAutomationController.send("
2255 "frames['updated-name'].location.href = '%s');",
2256 foo_url.spec().c_str());
2257 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script));
2258 frame_observer.Wait();
2259 EXPECT_EQ(foo_url, root->child_at(0)->current_url());
2262 // Verify that when a frame is navigated to a new origin, the origin update
2263 // propagates to the frame's proxies.
2264 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginUpdatesReachProxies) {
2265 GURL main_url(
2266 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2267 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2269 // It is safe to obtain the root frame tree node here, as it doesn't change.
2270 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2271 ->GetFrameTree()
2272 ->root();
2273 TestNavigationObserver observer(shell()->web_contents());
2275 EXPECT_EQ(
2276 " Site A ------------ proxies for B\n"
2277 " |--Site B ------- proxies for A\n"
2278 " +--Site A ------- proxies for B\n"
2279 "Where A = http://127.0.0.1/\n"
2280 " B = http://bar.com/",
2281 DepictFrameTree(root));
2283 // Navigate second subframe to a baz.com. This should send an origin update
2284 // to the frame's proxy in the bar.com (first frame's) process.
2285 GURL frame_url = embedded_test_server()->GetURL("baz.com", "/title2.html");
2286 NavigateFrameToURL(root->child_at(1), frame_url);
2287 EXPECT_TRUE(observer.last_navigation_succeeded());
2288 EXPECT_EQ(frame_url, observer.last_navigation_url());
2290 // The first frame can't directly observe the second frame's origin with
2291 // JavaScript. Instead, try to navigate the second frame from the first
2292 // frame. This should fail with a console error message, which should
2293 // contain the second frame's updated origin (see blink::Frame::canNavigate).
2294 scoped_ptr<ConsoleObserverDelegate> console_delegate(
2295 new ConsoleObserverDelegate(
2296 shell()->web_contents(),
2297 "Unsafe JavaScript attempt to initiate navigation*"));
2298 shell()->web_contents()->SetDelegate(console_delegate.get());
2300 // frames[1] can't be used due to a bug where RemoteFrames are created out of
2301 // order (https://crbug.com/478792). Instead, target second frame by name.
2302 EXPECT_TRUE(ExecuteScript(
2303 root->child_at(0)->current_frame_host(),
2304 "window.domAutomationController.send("
2305 " parent.frames['frame2'].location.href = 'data:text/html,foo');"));
2306 console_delegate->Wait();
2308 std::string frame_origin =
2309 root->child_at(1)->current_replication_state().origin.string();
2310 EXPECT_EQ(frame_origin + "/", frame_url.GetOrigin().spec());
2311 EXPECT_TRUE(
2312 base::MatchPattern(console_delegate->message(), "*" + frame_origin + "*"))
2313 << "Error message does not contain the frame's latest origin ("
2314 << frame_origin << ")";
2317 // Ensure that navigating subframes in --site-per-process mode properly fires
2318 // the DidStopLoading event on WebContentsObserver.
2319 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteDidStopLoading) {
2320 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
2321 NavigateToURL(shell(), main_url);
2323 // It is safe to obtain the root frame tree node here, as it doesn't change.
2324 FrameTreeNode* root =
2325 static_cast<WebContentsImpl*>(shell()->web_contents())->
2326 GetFrameTree()->root();
2328 TestNavigationObserver observer(shell()->web_contents());
2330 // Load same-site page into iframe.
2331 FrameTreeNode* child = root->child_at(0);
2332 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
2333 NavigateFrameToURL(child, http_url);
2334 EXPECT_EQ(http_url, observer.last_navigation_url());
2335 EXPECT_TRUE(observer.last_navigation_succeeded());
2337 // Load cross-site page into iframe.
2338 TestNavigationObserver nav_observer(shell()->web_contents(), 1);
2339 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
2340 NavigationController::LoadURLParams params(url);
2341 params.transition_type = ui::PAGE_TRANSITION_LINK;
2342 params.frame_tree_node_id = child->frame_tree_node_id();
2343 child->navigator()->GetController()->LoadURLWithParams(params);
2344 nav_observer.Wait();
2346 // Verify that the navigation succeeded and the expected URL was loaded.
2347 EXPECT_TRUE(observer.last_navigation_succeeded());
2348 EXPECT_EQ(url, observer.last_navigation_url());
2351 // Ensure that the renderer does not crash when navigating a frame that has a
2352 // sibling RemoteFrame. See https://crbug.com/426953.
2353 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2354 NavigateWithSiblingRemoteFrame) {
2355 GURL main_url(
2356 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2357 NavigateToURL(shell(), main_url);
2359 // It is safe to obtain the root frame tree node here, as it doesn't change.
2360 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2361 ->GetFrameTree()
2362 ->root();
2363 TestNavigationObserver observer(shell()->web_contents());
2365 // Make sure the first frame is out of process.
2366 ASSERT_EQ(2U, root->child_count());
2367 FrameTreeNode* node2 = root->child_at(0);
2368 EXPECT_NE(root->current_frame_host()->GetSiteInstance(),
2369 node2->current_frame_host()->GetSiteInstance());
2371 // Make sure the second frame is in the parent's process.
2372 FrameTreeNode* node3 = root->child_at(1);
2373 EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
2374 node3->current_frame_host()->GetSiteInstance());
2376 // Navigate the second iframe (node3) to a URL in its own process.
2377 GURL title_url = embedded_test_server()->GetURL("/title2.html");
2378 NavigateFrameToURL(node3, title_url);
2379 EXPECT_TRUE(observer.last_navigation_succeeded());
2380 EXPECT_EQ(title_url, observer.last_navigation_url());
2381 EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
2382 node3->current_frame_host()->GetSiteInstance());
2383 EXPECT_TRUE(node3->current_frame_host()->IsRenderFrameLive());
2386 // Verify that load events for iframe elements work when the child frame is
2387 // out-of-process. In such cases, the load event is forwarded from the child
2388 // frame to the parent frame via the browser process.
2389 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, LoadEventForwarding) {
2390 // Load a page with a cross-site frame. The parent page has an onload
2391 // handler in the iframe element that appends "LOADED" to the document title.
2393 GURL main_url(
2394 embedded_test_server()->GetURL("/frame_with_load_event.html"));
2395 base::string16 expected_title(base::UTF8ToUTF16("LOADED"));
2396 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
2397 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2398 EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
2401 // It is safe to obtain the root frame tree node here, as it doesn't change.
2402 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2403 ->GetFrameTree()
2404 ->root();
2406 // Load another cross-site page into the iframe and check that the load event
2407 // is fired.
2409 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
2410 base::string16 expected_title(base::UTF8ToUTF16("LOADEDLOADED"));
2411 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
2412 TestNavigationObserver observer(shell()->web_contents());
2413 NavigateFrameToURL(root->child_at(0), foo_url);
2414 EXPECT_TRUE(observer.last_navigation_succeeded());
2415 EXPECT_EQ(foo_url, observer.last_navigation_url());
2416 EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
2420 // Check that postMessage can be routed between cross-site iframes.
2421 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SubframePostMessage) {
2422 GURL main_url(embedded_test_server()->GetURL(
2423 "/frame_tree/page_with_post_message_frames.html"));
2424 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2426 // It is safe to obtain the root frame tree node here, as it doesn't change.
2427 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2428 ->GetFrameTree()
2429 ->root();
2431 ASSERT_EQ(2U, root->child_count());
2433 // Verify the frames start at correct URLs. First frame should be
2434 // same-site; second frame should be cross-site.
2435 GURL same_site_url(embedded_test_server()->GetURL("/post_message.html"));
2436 EXPECT_EQ(same_site_url, root->child_at(0)->current_url());
2437 GURL foo_url(embedded_test_server()->GetURL("foo.com",
2438 "/post_message.html"));
2439 EXPECT_EQ(foo_url, root->child_at(1)->current_url());
2440 EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
2441 root->child_at(1)->current_frame_host()->GetSiteInstance());
2443 // Send a message from first, same-site frame to second, cross-site frame.
2444 // Expect the second frame to reply back to the first frame.
2445 PostMessageAndWaitForReply(root->child_at(0),
2446 "postToSibling('subframe-msg','subframe2')",
2447 "\"done-subframe1\"");
2449 // Send a postMessage from second, cross-site frame to its parent. Expect
2450 // parent to send a reply to the frame.
2451 base::string16 expected_title(base::ASCIIToUTF16("subframe-msg"));
2452 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
2453 PostMessageAndWaitForReply(root->child_at(1), "postToParent('subframe-msg')",
2454 "\"done-subframe2\"");
2455 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
2457 // Verify the total number of received messages for each subframe. First
2458 // frame should have one message (reply from second frame). Second frame
2459 // should have two messages (message from first frame and reply from parent).
2460 // Parent should have one message (from second frame).
2461 EXPECT_EQ(1, GetReceivedMessages(root->child_at(0)));
2462 EXPECT_EQ(2, GetReceivedMessages(root->child_at(1)));
2463 EXPECT_EQ(1, GetReceivedMessages(root));
2466 // Check that postMessage can be sent from a subframe on a cross-process opener
2467 // tab, and that its event.source points to a valid proxy.
2468 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2469 PostMessageWithSubframeOnOpenerChain) {
2470 GURL main_url(embedded_test_server()->GetURL(
2471 "a.com", "/frame_tree/page_with_post_message_frames.html"));
2472 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2474 // It is safe to obtain the root frame tree node here, as it doesn't change.
2475 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2476 ->GetFrameTree()
2477 ->root();
2479 ASSERT_EQ(2U, root->child_count());
2481 // Verify the initial state of the world. First frame should be same-site;
2482 // second frame should be cross-site.
2483 EXPECT_EQ(
2484 " Site A ------------ proxies for B\n"
2485 " |--Site A ------- proxies for B\n"
2486 " +--Site B ------- proxies for A\n"
2487 "Where A = http://a.com/\n"
2488 " B = http://foo.com/",
2489 DepictFrameTree(root));
2491 // Open a popup from the first subframe (so that popup's window.opener points
2492 // to the subframe) and navigate it to bar.com.
2493 ShellAddedObserver new_shell_observer;
2494 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
2495 "openPopup('about:blank');"));
2496 Shell* popup = new_shell_observer.GetShell();
2497 GURL popup_url(
2498 embedded_test_server()->GetURL("bar.com", "/post_message.html"));
2499 EXPECT_TRUE(NavigateToURL(popup, popup_url));
2501 // From the popup, open another popup for baz.com. This will be used to
2502 // check that the whole opener chain is processed when creating proxies and
2503 // not just an immediate opener.
2504 ShellAddedObserver new_shell_observer2;
2505 EXPECT_TRUE(
2506 ExecuteScript(popup->web_contents(), "openPopup('about:blank');"));
2507 Shell* popup2 = new_shell_observer2.GetShell();
2508 GURL popup2_url(
2509 embedded_test_server()->GetURL("baz.com", "/post_message.html"));
2510 EXPECT_TRUE(NavigateToURL(popup2, popup2_url));
2512 // Ensure that we've created proxies for SiteInstances of both popups (C, D)
2513 // in the main window's frame tree.
2514 EXPECT_EQ(
2515 " Site A ------------ proxies for B C D\n"
2516 " |--Site A ------- proxies for B C D\n"
2517 " +--Site B ------- proxies for A C D\n"
2518 "Where A = http://a.com/\n"
2519 " B = http://foo.com/\n"
2520 " C = http://bar.com/\n"
2521 " D = http://baz.com/",
2522 DepictFrameTree(root));
2524 // Check the first popup's frame tree as well. Note that it doesn't have a
2525 // proxy for foo.com, since foo.com can't reach the popup. It does have a
2526 // proxy for its opener a.com (which can reach it via the window.open
2527 // reference) and second popup (which can reach it via window.opener).
2528 FrameTreeNode* popup_root =
2529 static_cast<WebContentsImpl*>(popup->web_contents())
2530 ->GetFrameTree()
2531 ->root();
2532 EXPECT_EQ(
2533 " Site C ------------ proxies for A D\n"
2534 "Where A = http://a.com/\n"
2535 " C = http://bar.com/\n"
2536 " D = http://baz.com/",
2537 DepictFrameTree(popup_root));
2539 // Send a message from first subframe on main page to the first popup and
2540 // wait for a reply back. The reply verifies that the proxy for the opener
2541 // tab's subframe is targeted properly.
2542 PostMessageAndWaitForReply(root->child_at(0), "postToPopup('subframe-msg')",
2543 "\"done-subframe1\"");
2545 // Send a postMessage from the popup to window.opener and ensure that it
2546 // reaches subframe1. This verifies that the subframe opener information
2547 // propagated to the popup's RenderFrame. Wait for subframe1 to send a reply
2548 // message to the popup.
2549 EXPECT_TRUE(ExecuteScript(popup->web_contents(), "window.name = 'popup';"));
2550 PostMessageAndWaitForReply(popup_root, "postToOpener('subframe-msg', '*')",
2551 "\"done-popup\"");
2553 // Second a postMessage from popup2 to window.opener.opener, which should
2554 // resolve to subframe1. This tests opener chains of length greater than 1.
2555 // As before, subframe1 will send a reply to popup2.
2556 FrameTreeNode* popup2_root =
2557 static_cast<WebContentsImpl*>(popup2->web_contents())
2558 ->GetFrameTree()
2559 ->root();
2560 EXPECT_TRUE(ExecuteScript(popup2->web_contents(), "window.name = 'popup2';"));
2561 PostMessageAndWaitForReply(popup2_root,
2562 "postToOpenerOfOpener('subframe-msg', '*')",
2563 "\"done-popup2\"");
2565 // Verify the total number of received messages for each subframe:
2566 // - 3 for first subframe (two from first popup, one from second popup)
2567 // - 2 for popup (both from first subframe)
2568 // - 1 for popup2 (reply from first subframe)
2569 // - 0 for other frames
2570 EXPECT_EQ(0, GetReceivedMessages(root));
2571 EXPECT_EQ(3, GetReceivedMessages(root->child_at(0)));
2572 EXPECT_EQ(0, GetReceivedMessages(root->child_at(1)));
2573 EXPECT_EQ(2, GetReceivedMessages(popup_root));
2574 EXPECT_EQ(1, GetReceivedMessages(popup2_root));
2577 // Check that parent.frames[num] references correct sibling frames when the
2578 // parent is remote. See https://crbug.com/478792.
2579 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, IndexedFrameAccess) {
2580 // Start on a page with three same-site subframes.
2581 GURL main_url(
2582 embedded_test_server()->GetURL("a.com", "/frame_tree/top.html"));
2583 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2585 // It is safe to obtain the root frame tree node here, as it doesn't change.
2586 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2587 ->GetFrameTree()
2588 ->root();
2589 ASSERT_EQ(3U, root->child_count());
2590 FrameTreeNode* child0 = root->child_at(0);
2591 FrameTreeNode* child1 = root->child_at(1);
2592 FrameTreeNode* child2 = root->child_at(2);
2594 // Send each of the frames to a different site. Each new renderer will first
2595 // create proxies for the parent and two sibling subframes and then create
2596 // and insert the new RenderFrame into the frame tree.
2597 GURL b_url(embedded_test_server()->GetURL("b.com", "/post_message.html"));
2598 GURL c_url(embedded_test_server()->GetURL("c.com", "/post_message.html"));
2599 GURL d_url(embedded_test_server()->GetURL("d.com", "/post_message.html"));
2600 NavigateFrameToURL(child0, b_url);
2601 // TODO(alexmos): The calls to WaitForRenderFrameReady can be removed once
2602 // TestFrameNavigationObserver is fixed to use DidFinishLoad.
2603 EXPECT_TRUE(WaitForRenderFrameReady(child0->current_frame_host()));
2604 NavigateFrameToURL(child1, c_url);
2605 EXPECT_TRUE(WaitForRenderFrameReady(child1->current_frame_host()));
2606 NavigateFrameToURL(child2, d_url);
2607 EXPECT_TRUE(WaitForRenderFrameReady(child2->current_frame_host()));
2609 EXPECT_EQ(
2610 " Site A ------------ proxies for B C D\n"
2611 " |--Site B ------- proxies for A C D\n"
2612 " |--Site C ------- proxies for A B D\n"
2613 " +--Site D ------- proxies for A B C\n"
2614 "Where A = http://a.com/\n"
2615 " B = http://b.com/\n"
2616 " C = http://c.com/\n"
2617 " D = http://d.com/",
2618 DepictFrameTree(root));
2620 // Check that each subframe sees itself at correct index in parent.frames.
2621 bool success = false;
2622 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2623 child0->current_frame_host(),
2624 "window.domAutomationController.send(window === parent.frames[0]);",
2625 &success));
2626 EXPECT_TRUE(success);
2628 success = false;
2629 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2630 child1->current_frame_host(),
2631 "window.domAutomationController.send(window === parent.frames[1]);",
2632 &success));
2633 EXPECT_TRUE(success);
2635 success = false;
2636 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2637 child2->current_frame_host(),
2638 "window.domAutomationController.send(window === parent.frames[2]);",
2639 &success));
2640 EXPECT_TRUE(success);
2642 // Send a postMessage from B to parent.frames[1], which should go to C, and
2643 // wait for reply.
2644 PostMessageAndWaitForReply(child0, "postToSibling('subframe-msg', 1)",
2645 "\"done-1-1-name\"");
2647 // Send a postMessage from C to parent.frames[2], which should go to D, and
2648 // wait for reply.
2649 PostMessageAndWaitForReply(child1, "postToSibling('subframe-msg', 2)",
2650 "\"done-1-2-name\"");
2652 // Verify the total number of received messages for each subframe.
2653 EXPECT_EQ(1, GetReceivedMessages(child0));
2654 EXPECT_EQ(2, GetReceivedMessages(child1));
2655 EXPECT_EQ(1, GetReceivedMessages(child2));
2658 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RFPHDestruction) {
2659 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
2660 NavigateToURL(shell(), main_url);
2662 // It is safe to obtain the root frame tree node here, as it doesn't change.
2663 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2664 ->GetFrameTree()
2665 ->root();
2667 TestNavigationObserver observer(shell()->web_contents());
2669 // Load cross-site page into iframe.
2670 FrameTreeNode* child = root->child_at(0);
2671 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
2672 NavigateFrameToURL(root->child_at(0), url);
2673 EXPECT_TRUE(observer.last_navigation_succeeded());
2674 EXPECT_EQ(url, observer.last_navigation_url());
2675 EXPECT_EQ(
2676 " Site A ------------ proxies for B\n"
2677 " |--Site B ------- proxies for A\n"
2678 " +--Site A ------- proxies for B\n"
2679 " |--Site A -- proxies for B\n"
2680 " +--Site A -- proxies for B\n"
2681 " +--Site A -- proxies for B\n"
2682 "Where A = http://127.0.0.1/\n"
2683 " B = http://foo.com/",
2684 DepictFrameTree(root));
2686 // Load another cross-site page.
2687 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
2688 NavigateIframeToURL(shell()->web_contents(), "test", url);
2689 EXPECT_TRUE(observer.last_navigation_succeeded());
2690 EXPECT_EQ(url, observer.last_navigation_url());
2691 EXPECT_EQ(
2692 " Site A ------------ proxies for C\n"
2693 " |--Site C ------- proxies for A\n"
2694 " +--Site A ------- proxies for C\n"
2695 " |--Site A -- proxies for C\n"
2696 " +--Site A -- proxies for C\n"
2697 " +--Site A -- proxies for C\n"
2698 "Where A = http://127.0.0.1/\n"
2699 " C = http://bar.com/",
2700 DepictFrameTree(root));
2702 // Navigate back to the parent's origin.
2703 url = embedded_test_server()->GetURL("/title1.html");
2704 NavigateFrameToURL(child, url);
2705 EXPECT_EQ(url, observer.last_navigation_url());
2706 EXPECT_TRUE(observer.last_navigation_succeeded());
2707 EXPECT_EQ(
2708 " Site A\n"
2709 " |--Site A\n"
2710 " +--Site A\n"
2711 " |--Site A\n"
2712 " +--Site A\n"
2713 " +--Site A\n"
2714 "Where A = http://127.0.0.1/",
2715 DepictFrameTree(root));
2718 } // namespace content