Disable flaky tests on cros-trunk
[chromium-blink-merge.git] / content / browser / site_per_process_browsertest.cc
blob72a0993ac650b43371969a814e44bbe16431bd8e
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 // Helper function to perform a window.open from the |caller_frame| targeting a
80 // frame with the specified name.
81 void NavigateNamedFrame(const ToRenderFrameHost& caller_frame,
82 const GURL& url,
83 const std::string& name) {
84 bool success = false;
85 EXPECT_TRUE(ExecuteScriptAndExtractBool(
86 caller_frame,
87 "window.domAutomationController.send("
88 " !!window.open('" + url.spec() + "', '" + name + "'));",
89 &success));
90 EXPECT_TRUE(success);
93 class RedirectNotificationObserver : public NotificationObserver {
94 public:
95 // Register to listen for notifications of the given type from either a
96 // specific source, or from all sources if |source| is
97 // NotificationService::AllSources().
98 RedirectNotificationObserver(int notification_type,
99 const NotificationSource& source);
100 ~RedirectNotificationObserver() override;
102 // Wait until the specified notification occurs. If the notification was
103 // emitted between the construction of this object and this call then it
104 // returns immediately.
105 void Wait();
107 // Returns NotificationService::AllSources() if we haven't observed a
108 // notification yet.
109 const NotificationSource& source() const {
110 return source_;
113 const NotificationDetails& details() const {
114 return details_;
117 // NotificationObserver:
118 void Observe(int type,
119 const NotificationSource& source,
120 const NotificationDetails& details) override;
122 private:
123 bool seen_;
124 bool seen_twice_;
125 bool running_;
126 NotificationRegistrar registrar_;
128 NotificationSource source_;
129 NotificationDetails details_;
130 scoped_refptr<MessageLoopRunner> message_loop_runner_;
132 DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver);
135 RedirectNotificationObserver::RedirectNotificationObserver(
136 int notification_type,
137 const NotificationSource& source)
138 : seen_(false),
139 running_(false),
140 source_(NotificationService::AllSources()) {
141 registrar_.Add(this, notification_type, source);
144 RedirectNotificationObserver::~RedirectNotificationObserver() {}
146 void RedirectNotificationObserver::Wait() {
147 if (seen_ && seen_twice_)
148 return;
150 running_ = true;
151 message_loop_runner_ = new MessageLoopRunner;
152 message_loop_runner_->Run();
153 EXPECT_TRUE(seen_);
156 void RedirectNotificationObserver::Observe(
157 int type,
158 const NotificationSource& source,
159 const NotificationDetails& details) {
160 source_ = source;
161 details_ = details;
162 seen_twice_ = seen_;
163 seen_ = true;
164 if (!running_)
165 return;
167 message_loop_runner_->Quit();
168 running_ = false;
171 // This observer keeps track of the number of created RenderFrameHosts. Tests
172 // can use this to ensure that a certain number of child frames has been
173 // created after navigating.
174 class RenderFrameHostCreatedObserver : public WebContentsObserver {
175 public:
176 RenderFrameHostCreatedObserver(WebContents* web_contents,
177 int expected_frame_count)
178 : WebContentsObserver(web_contents),
179 expected_frame_count_(expected_frame_count),
180 frames_created_(0),
181 message_loop_runner_(new MessageLoopRunner) {}
183 ~RenderFrameHostCreatedObserver() override;
185 // Runs a nested message loop and blocks until the expected number of
186 // RenderFrameHosts is created.
187 void Wait();
189 private:
190 // WebContentsObserver
191 void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
193 // The number of RenderFrameHosts to wait for.
194 int expected_frame_count_;
196 // The number of RenderFrameHosts that have been created.
197 int frames_created_;
199 // The MessageLoopRunner used to spin the message loop.
200 scoped_refptr<MessageLoopRunner> message_loop_runner_;
202 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver);
205 RenderFrameHostCreatedObserver::~RenderFrameHostCreatedObserver() {
208 void RenderFrameHostCreatedObserver::Wait() {
209 message_loop_runner_->Run();
212 void RenderFrameHostCreatedObserver::RenderFrameCreated(
213 RenderFrameHost* render_frame_host) {
214 frames_created_++;
215 if (frames_created_ == expected_frame_count_) {
216 message_loop_runner_->Quit();
220 // A WebContentsDelegate that catches messages sent to the console.
221 class ConsoleObserverDelegate : public WebContentsDelegate {
222 public:
223 ConsoleObserverDelegate(WebContents* web_contents, const std::string& filter)
224 : web_contents_(web_contents),
225 filter_(filter),
226 message_(""),
227 message_loop_runner_(new MessageLoopRunner) {}
229 ~ConsoleObserverDelegate() override {}
231 bool AddMessageToConsole(WebContents* source,
232 int32 level,
233 const base::string16& message,
234 int32 line_no,
235 const base::string16& source_id) override;
237 std::string message() { return message_; }
239 void Wait();
241 private:
242 WebContents* web_contents_;
243 std::string filter_;
244 std::string message_;
246 // The MessageLoopRunner used to spin the message loop.
247 scoped_refptr<MessageLoopRunner> message_loop_runner_;
249 DISALLOW_COPY_AND_ASSIGN(ConsoleObserverDelegate);
252 void ConsoleObserverDelegate::Wait() {
253 message_loop_runner_->Run();
256 bool ConsoleObserverDelegate::AddMessageToConsole(
257 WebContents* source,
258 int32 level,
259 const base::string16& message,
260 int32 line_no,
261 const base::string16& source_id) {
262 DCHECK(source == web_contents_);
264 std::string ascii_message = base::UTF16ToASCII(message);
265 if (base::MatchPattern(ascii_message, filter_)) {
266 message_ = ascii_message;
267 message_loop_runner_->Quit();
269 return false;
272 } // namespace
275 // SitePerProcessBrowserTest
278 SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
281 std::string SitePerProcessBrowserTest::DepictFrameTree(FrameTreeNode* node) {
282 return visualizer_.DepictFrameTree(node);
285 void SitePerProcessBrowserTest::StartFrameAtDataURL() {
286 std::string data_url_script =
287 "var iframes = document.getElementById('test');iframes.src="
288 "'data:text/html,dataurl';";
289 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script));
292 void SitePerProcessBrowserTest::SetUpCommandLine(
293 base::CommandLine* command_line) {
294 IsolateAllSitesForTesting(command_line);
297 void SitePerProcessBrowserTest::SetUpOnMainThread() {
298 host_resolver()->AddRule("*", "127.0.0.1");
299 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
300 SetupCrossSiteRedirector(embedded_test_server());
303 // Ensure that navigating subframes in --site-per-process mode works and the
304 // correct documents are committed.
305 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
306 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
307 NavigateToURL(shell(), main_url);
309 // It is safe to obtain the root frame tree node here, as it doesn't change.
310 FrameTreeNode* root =
311 static_cast<WebContentsImpl*>(shell()->web_contents())->
312 GetFrameTree()->root();
314 TestNavigationObserver observer(shell()->web_contents());
316 // Load same-site page into iframe.
317 FrameTreeNode* child = root->child_at(0);
318 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
319 NavigateFrameToURL(child, http_url);
320 EXPECT_EQ(http_url, observer.last_navigation_url());
321 EXPECT_TRUE(observer.last_navigation_succeeded());
323 // There should be only one RenderWidgetHost when there are no
324 // cross-process iframes.
325 std::set<RenderWidgetHostView*> views_set =
326 static_cast<WebContentsImpl*>(shell()->web_contents())
327 ->GetRenderWidgetHostViewsInTree();
328 EXPECT_EQ(1U, views_set.size());
331 EXPECT_EQ(
332 " Site A\n"
333 " |--Site A\n"
334 " +--Site A\n"
335 " |--Site A\n"
336 " +--Site A\n"
337 " +--Site A\n"
338 "Where A = http://127.0.0.1/",
339 DepictFrameTree(root));
341 // Load cross-site page into iframe.
342 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
343 NavigateFrameToURL(root->child_at(0), url);
344 // Verify that the navigation succeeded and the expected URL was loaded.
345 EXPECT_TRUE(observer.last_navigation_succeeded());
346 EXPECT_EQ(url, observer.last_navigation_url());
348 // Ensure that we have created a new process for the subframe.
349 ASSERT_EQ(2U, root->child_count());
350 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
351 RenderViewHost* rvh = child->current_frame_host()->render_view_host();
352 RenderProcessHost* rph = child->current_frame_host()->GetProcess();
353 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
354 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
355 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph);
357 // There should be now two RenderWidgetHosts, one for each process
358 // rendering a frame.
359 std::set<RenderWidgetHostView*> views_set =
360 static_cast<WebContentsImpl*>(shell()->web_contents())
361 ->GetRenderWidgetHostViewsInTree();
362 EXPECT_EQ(2U, views_set.size());
364 RenderFrameProxyHost* proxy_to_parent =
365 child->render_manager()->GetProxyToParent();
366 EXPECT_TRUE(proxy_to_parent);
367 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
368 // The out-of-process iframe should have its own RenderWidgetHost,
369 // independent of any RenderViewHost.
370 EXPECT_NE(
371 rvh->GetView(),
372 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
373 EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
375 EXPECT_EQ(
376 " Site A ------------ proxies for B\n"
377 " |--Site B ------- proxies for A\n"
378 " +--Site A ------- proxies for B\n"
379 " |--Site A -- proxies for B\n"
380 " +--Site A -- proxies for B\n"
381 " +--Site A -- proxies for B\n"
382 "Where A = http://127.0.0.1/\n"
383 " B = http://foo.com/",
384 DepictFrameTree(root));
386 // Load another cross-site page into the same iframe.
387 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
388 NavigateFrameToURL(root->child_at(0), url);
389 EXPECT_TRUE(observer.last_navigation_succeeded());
390 EXPECT_EQ(url, observer.last_navigation_url());
392 // Check again that a new process is created and is different from the
393 // top level one and the previous one.
394 ASSERT_EQ(2U, root->child_count());
395 child = root->child_at(0);
396 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
397 child->current_frame_host()->render_view_host());
398 EXPECT_NE(rvh, child->current_frame_host()->render_view_host());
399 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
400 child->current_frame_host()->GetSiteInstance());
401 EXPECT_NE(site_instance,
402 child->current_frame_host()->GetSiteInstance());
403 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
404 child->current_frame_host()->GetProcess());
405 EXPECT_NE(rph, child->current_frame_host()->GetProcess());
407 std::set<RenderWidgetHostView*> views_set =
408 static_cast<WebContentsImpl*>(shell()->web_contents())
409 ->GetRenderWidgetHostViewsInTree();
410 EXPECT_EQ(2U, views_set.size());
412 EXPECT_EQ(proxy_to_parent, child->render_manager()->GetProxyToParent());
413 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
414 EXPECT_NE(
415 child->current_frame_host()->render_view_host()->GetView(),
416 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
417 EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
419 EXPECT_EQ(
420 " Site A ------------ proxies for C\n"
421 " |--Site C ------- proxies for A\n"
422 " +--Site A ------- proxies for C\n"
423 " |--Site A -- proxies for C\n"
424 " +--Site A -- proxies for C\n"
425 " +--Site A -- proxies for C\n"
426 "Where A = http://127.0.0.1/\n"
427 " C = http://bar.com/",
428 DepictFrameTree(root));
431 // Tests OOPIF rendering by checking that the RWH of the iframe generates
432 // OnSwapCompositorFrame message.
433 #if defined(OS_ANDROID)
434 // http://crbug.com/471850
435 #define MAYBE_CompositorFrameSwapped DISABLED_CompositorFrameSwapped
436 #else
437 #define MAYBE_CompositorFrameSwapped CompositorFrameSwapped
438 #endif
439 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
440 MAYBE_CompositorFrameSwapped) {
441 GURL main_url(
442 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
443 NavigateToURL(shell(), main_url);
445 // It is safe to obtain the root frame tree node here, as it doesn't change.
446 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
447 ->GetFrameTree()
448 ->root();
449 ASSERT_EQ(1U, root->child_count());
451 FrameTreeNode* child_node = root->child_at(0);
452 GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
453 EXPECT_EQ(site_url, child_node->current_url());
454 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
455 child_node->current_frame_host()->GetSiteInstance());
456 RenderWidgetHostViewBase* rwhv_base = static_cast<RenderWidgetHostViewBase*>(
457 child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
459 // Wait for OnSwapCompositorFrame message.
460 while (rwhv_base->RendererFrameNumber() <= 0) {
461 // TODO(lazyboy): Find a better way to avoid sleeping like this. See
462 // http://crbug.com/405282 for details.
463 base::RunLoop run_loop;
464 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
465 FROM_HERE, run_loop.QuitClosure(),
466 base::TimeDelta::FromMilliseconds(10));
467 run_loop.Run();
471 // Ensure that OOPIFs are deleted after navigating to a new main frame.
472 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CleanupCrossSiteIframe) {
473 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
474 NavigateToURL(shell(), main_url);
476 // It is safe to obtain the root frame tree node here, as it doesn't change.
477 FrameTreeNode* root =
478 static_cast<WebContentsImpl*>(shell()->web_contents())->
479 GetFrameTree()->root();
481 TestNavigationObserver observer(shell()->web_contents());
483 // Load a cross-site page into both iframes.
484 GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html");
485 NavigateFrameToURL(root->child_at(0), foo_url);
486 EXPECT_TRUE(observer.last_navigation_succeeded());
487 EXPECT_EQ(foo_url, observer.last_navigation_url());
488 NavigateFrameToURL(root->child_at(1), foo_url);
489 EXPECT_TRUE(observer.last_navigation_succeeded());
490 EXPECT_EQ(foo_url, observer.last_navigation_url());
492 // Ensure that we have created a new process for the subframes.
493 EXPECT_EQ(
494 " Site A ------------ proxies for B\n"
495 " |--Site B ------- proxies for A\n"
496 " +--Site B ------- proxies for A\n"
497 "Where A = http://127.0.0.1/\n"
498 " B = http://foo.com/",
499 DepictFrameTree(root));
501 int subframe_process_id = root->child_at(0)
502 ->current_frame_host()
503 ->GetSiteInstance()
504 ->GetProcess()
505 ->GetID();
506 int subframe_rvh_id = root->child_at(0)
507 ->current_frame_host()
508 ->render_view_host()
509 ->GetRoutingID();
510 EXPECT_TRUE(RenderViewHost::FromID(subframe_process_id, subframe_rvh_id));
512 // Use Javascript in the parent to remove one of the frames and ensure that
513 // the subframe goes away.
514 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
515 "document.body.removeChild("
516 "document.querySelectorAll('iframe')[0])"));
517 ASSERT_EQ(1U, root->child_count());
519 // Load a new same-site page in the top-level frame and ensure the other
520 // subframe goes away.
521 GURL new_url(embedded_test_server()->GetURL("/title1.html"));
522 NavigateToURL(shell(), new_url);
523 ASSERT_EQ(0U, root->child_count());
525 // Ensure the RVH for the subframe gets cleaned up when the frame goes away.
526 EXPECT_FALSE(RenderViewHost::FromID(subframe_process_id, subframe_rvh_id));
529 // Ensure that root frames cannot be detached.
530 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RestrictFrameDetach) {
531 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
532 NavigateToURL(shell(), main_url);
534 // It is safe to obtain the root frame tree node here, as it doesn't change.
535 FrameTreeNode* root =
536 static_cast<WebContentsImpl*>(shell()->web_contents())->
537 GetFrameTree()->root();
539 TestNavigationObserver observer(shell()->web_contents());
541 // Load cross-site pages into both iframes.
542 GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html");
543 NavigateFrameToURL(root->child_at(0), foo_url);
544 EXPECT_TRUE(observer.last_navigation_succeeded());
545 EXPECT_EQ(foo_url, observer.last_navigation_url());
546 GURL bar_url = embedded_test_server()->GetURL("bar.com", "/title2.html");
547 NavigateFrameToURL(root->child_at(1), bar_url);
548 EXPECT_TRUE(observer.last_navigation_succeeded());
549 EXPECT_EQ(bar_url, observer.last_navigation_url());
551 // Ensure that we have created new processes for the subframes.
552 ASSERT_EQ(2U, root->child_count());
553 FrameTreeNode* foo_child = root->child_at(0);
554 SiteInstance* foo_site_instance =
555 foo_child->current_frame_host()->GetSiteInstance();
556 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), foo_site_instance);
557 FrameTreeNode* bar_child = root->child_at(1);
558 SiteInstance* bar_site_instance =
559 bar_child->current_frame_host()->GetSiteInstance();
560 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), bar_site_instance);
562 EXPECT_EQ(
563 " Site A ------------ proxies for B C\n"
564 " |--Site B ------- proxies for A C\n"
565 " +--Site C ------- proxies for A B\n"
566 "Where A = http://127.0.0.1/\n"
567 " B = http://foo.com/\n"
568 " C = http://bar.com/",
569 DepictFrameTree(root));
571 // Simulate an attempt to detach the root frame from foo_site_instance. This
572 // should kill foo_site_instance's process.
573 RenderFrameProxyHost* foo_mainframe_rfph =
574 root->render_manager()->GetRenderFrameProxyHost(foo_site_instance);
575 content::RenderProcessHostWatcher foo_terminated(
576 foo_mainframe_rfph->GetProcess(),
577 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
578 FrameHostMsg_Detach evil_msg2(foo_mainframe_rfph->GetRoutingID());
579 IPC::IpcSecurityTestUtil::PwnMessageReceived(
580 foo_mainframe_rfph->GetProcess()->GetChannel(), evil_msg2);
581 foo_terminated.Wait();
583 EXPECT_EQ(
584 " Site A ------------ proxies for B C\n"
585 " |--Site B ------- proxies for A C\n"
586 " +--Site C ------- proxies for A B\n"
587 "Where A = http://127.0.0.1/\n"
588 " B = http://foo.com/ (no process)\n"
589 " C = http://bar.com/",
590 DepictFrameTree(root));
593 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
594 NavigateRemoteFrame) {
595 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
596 NavigateToURL(shell(), main_url);
598 // It is safe to obtain the root frame tree node here, as it doesn't change.
599 FrameTreeNode* root =
600 static_cast<WebContentsImpl*>(shell()->web_contents())->
601 GetFrameTree()->root();
603 TestNavigationObserver observer(shell()->web_contents());
605 // Load same-site page into iframe.
606 FrameTreeNode* child = root->child_at(0);
607 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
608 NavigateFrameToURL(child, http_url);
609 EXPECT_EQ(http_url, observer.last_navigation_url());
610 EXPECT_TRUE(observer.last_navigation_succeeded());
612 // Load cross-site page into iframe.
613 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
614 NavigateFrameToURL(root->child_at(0), url);
615 EXPECT_TRUE(observer.last_navigation_succeeded());
616 EXPECT_EQ(url, observer.last_navigation_url());
618 // Ensure that we have created a new process for the subframe.
619 ASSERT_EQ(2U, root->child_count());
620 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
621 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
623 // Emulate the main frame changing the src of the iframe such that it
624 // navigates cross-site.
625 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
626 NavigateIframeToURL(shell()->web_contents(), "test", url);
627 EXPECT_TRUE(observer.last_navigation_succeeded());
628 EXPECT_EQ(url, observer.last_navigation_url());
630 // Check again that a new process is created and is different from the
631 // top level one and the previous one.
632 ASSERT_EQ(2U, root->child_count());
633 child = root->child_at(0);
634 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
635 child->current_frame_host()->GetSiteInstance());
636 EXPECT_NE(site_instance,
637 child->current_frame_host()->GetSiteInstance());
639 // Navigate back to the parent's origin and ensure we return to the
640 // parent's process.
641 NavigateFrameToURL(child, http_url);
642 EXPECT_EQ(http_url, observer.last_navigation_url());
643 EXPECT_TRUE(observer.last_navigation_succeeded());
644 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
645 child->current_frame_host()->GetSiteInstance());
648 #if defined(OS_WIN)
649 // http://crbug.com/465722
650 #define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
651 DISABLED_NavigateRemoteFrameToBlankAndDataURLs
652 #else
653 #define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
654 NavigateRemoteFrameToBlankAndDataURLs
655 #endif
657 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
658 MAYBE_NavigateRemoteFrameToBlankAndDataURLs) {
659 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
660 NavigateToURL(shell(), main_url);
662 // It is safe to obtain the root frame tree node here, as it doesn't change.
663 FrameTreeNode* root =
664 static_cast<WebContentsImpl*>(shell()->web_contents())->
665 GetFrameTree()->root();
667 TestNavigationObserver observer(shell()->web_contents());
669 // Load same-site page into iframe.
670 FrameTreeNode* child = root->child_at(0);
671 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
672 NavigateFrameToURL(child, http_url);
673 EXPECT_EQ(http_url, observer.last_navigation_url());
674 EXPECT_TRUE(observer.last_navigation_succeeded());
676 // Load cross-site page into iframe.
677 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
678 NavigateFrameToURL(root->child_at(0), url);
679 EXPECT_TRUE(observer.last_navigation_succeeded());
680 EXPECT_EQ(url, observer.last_navigation_url());
681 ASSERT_EQ(2U, root->child_count());
682 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
683 root->child_at(0)->current_frame_host()->GetSiteInstance());
685 // Navigate iframe to a data URL. The navigation happens from a script in the
686 // parent frame, so the data URL should be committed in the same SiteInstance
687 // as the parent frame.
688 GURL data_url("data:text/html,dataurl");
689 NavigateIframeToURL(shell()->web_contents(), "test", data_url);
690 EXPECT_TRUE(observer.last_navigation_succeeded());
691 EXPECT_EQ(data_url, observer.last_navigation_url());
693 // Ensure that we have navigated using the top level process.
694 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
695 root->child_at(0)->current_frame_host()->GetSiteInstance());
697 // Load cross-site page into iframe.
698 url = embedded_test_server()->GetURL("bar.com", "/title2.html");
699 NavigateFrameToURL(root->child_at(0), url);
700 EXPECT_TRUE(observer.last_navigation_succeeded());
701 EXPECT_EQ(url, observer.last_navigation_url());
702 ASSERT_EQ(2U, root->child_count());
703 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
704 root->child_at(0)->current_frame_host()->GetSiteInstance());
706 // Navigate iframe to about:blank. The navigation happens from a script in the
707 // parent frame, so it should be committed in the same SiteInstance as the
708 // parent frame.
709 GURL about_blank_url("about:blank");
710 NavigateIframeToURL(shell()->web_contents(), "test", about_blank_url);
711 EXPECT_TRUE(observer.last_navigation_succeeded());
712 EXPECT_EQ(about_blank_url, observer.last_navigation_url());
714 // Ensure that we have navigated using the top level process.
715 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
716 root->child_at(0)->current_frame_host()->GetSiteInstance());
719 // This test checks that killing a renderer process of a remote frame
720 // and then navigating some other frame to the same SiteInstance of the killed
721 // process works properly.
722 // This can be illustrated as follows,
723 // where 1/2/3 are FrameTreeNode-s and A/B are processes and B* is the killed
724 // B process:
726 // 1 A A A
727 // / \ -> / \ -> Kill B -> / \ -> Navigate 3 to B -> / \ .
728 // 2 3 B A B* A B* B
730 // Initially, node1.proxy_hosts_ = {B}
731 // After we kill B, we make sure B stays in node1.proxy_hosts_, then we navigate
732 // 3 to B and we expect that to complete normally.
733 // See http://crbug.com/432107.
735 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
736 // site B and stays in not rendered state.
737 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
738 NavigateRemoteFrameToKilledProcess) {
739 GURL main_url(embedded_test_server()->GetURL(
740 "/frame_tree/page_with_two_frames.html"));
741 NavigateToURL(shell(), main_url);
743 // It is safe to obtain the root frame tree node here, as it doesn't change.
744 FrameTreeNode* root =
745 static_cast<WebContentsImpl*>(shell()->web_contents())->
746 GetFrameTree()->root();
748 TestNavigationObserver observer(shell()->web_contents());
749 ASSERT_EQ(2U, root->child_count());
751 // Make sure node2 points to the correct cross-site page.
752 GURL site_b_url = embedded_test_server()->GetURL("bar.com", "/title1.html");
753 FrameTreeNode* node2 = root->child_at(0);
754 EXPECT_EQ(site_b_url, node2->current_url());
756 // Kill that cross-site renderer.
757 RenderProcessHost* child_process =
758 node2->current_frame_host()->GetProcess();
759 RenderProcessHostWatcher crash_observer(
760 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
761 child_process->Shutdown(0, false);
762 crash_observer.Wait();
764 // Now navigate the second iframe (node3) to the same site as the node2.
765 FrameTreeNode* node3 = root->child_at(1);
766 NavigateFrameToURL(node3, site_b_url);
767 EXPECT_TRUE(observer.last_navigation_succeeded());
768 EXPECT_EQ(site_b_url, observer.last_navigation_url());
771 // This test is similar to
772 // SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess with
773 // addition that node2 also has a cross-origin frame to site C.
775 // 1 A A A
776 // / \ / \ / \ / \ .
777 // 2 3 -> B A -> Kill B -> B* A -> Navigate 3 -> B* B
778 // / /
779 // 4 C
781 // Initially, node1.proxy_hosts_ = {B, C}
782 // After we kill B, we make sure B stays in node1.proxy_hosts_, but
783 // C gets cleared from node1.proxy_hosts_.
785 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
786 // site B and stays in not rendered state.
787 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
788 NavigateRemoteFrameToKilledProcessWithSubtree) {
789 GURL main_url(embedded_test_server()->GetURL(
790 "a.com", "/frame_tree/page_with_two_frames_nested.html"));
791 NavigateToURL(shell(), main_url);
793 // It is safe to obtain the root frame tree node here, as it doesn't change.
794 FrameTreeNode* root =
795 static_cast<WebContentsImpl*>(shell()->web_contents())->
796 GetFrameTree()->root();
797 TestNavigationObserver observer(shell()->web_contents());
799 ASSERT_EQ(2U, root->child_count());
801 GURL site_b_url(
802 embedded_test_server()->GetURL(
803 "bar.com", "/frame_tree/page_with_one_frame.html"));
804 // We can't use a TestNavigationObserver to verify the URL here,
805 // since the frame has children that may have clobbered it in the observer.
806 EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
808 // Ensure that a new process is created for node2.
809 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
810 root->child_at(0)->current_frame_host()->GetSiteInstance());
811 // Ensure that a new process is *not* created for node3.
812 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
813 root->child_at(1)->current_frame_host()->GetSiteInstance());
815 ASSERT_EQ(1U, root->child_at(0)->child_count());
817 // Make sure node4 points to the correct cross-site page.
818 FrameTreeNode* node4 = root->child_at(0)->child_at(0);
819 GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
820 EXPECT_EQ(site_c_url, node4->current_url());
822 // |site_instance_c| is expected to go away once we kill |child_process_b|
823 // below, so create a local scope so we can extend the lifetime of
824 // |site_instance_c| with a refptr.
826 // Initially each frame has proxies for the other sites.
827 EXPECT_EQ(
828 " Site A ------------ proxies for B C\n"
829 " |--Site B ------- proxies for A C\n"
830 " | +--Site C -- proxies for A B\n"
831 " +--Site A ------- proxies for B C\n"
832 "Where A = http://a.com/\n"
833 " B = http://bar.com/\n"
834 " C = http://baz.com/",
835 DepictFrameTree(root));
837 // Kill the render process for Site B.
838 RenderProcessHost* child_process_b =
839 root->child_at(0)->current_frame_host()->GetProcess();
840 RenderProcessHostWatcher crash_observer(
841 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
842 child_process_b->Shutdown(0, false);
843 crash_observer.Wait();
845 // The Site C frame (a child of the crashed Site B frame) should go away,
846 // and there should be no remaining proxies for site C anywhere.
847 EXPECT_EQ(
848 " Site A ------------ proxies for B\n"
849 " |--Site B ------- proxies for A\n"
850 " +--Site A ------- proxies for B\n"
851 "Where A = http://a.com/\n"
852 " B = http://bar.com/ (no process)",
853 DepictFrameTree(root));
856 // Now navigate the second iframe (node3) to Site B also.
857 FrameTreeNode* node3 = root->child_at(1);
858 GURL url = embedded_test_server()->GetURL("bar.com", "/title1.html");
859 NavigateFrameToURL(node3, url);
860 EXPECT_TRUE(observer.last_navigation_succeeded());
861 EXPECT_EQ(url, observer.last_navigation_url());
863 EXPECT_EQ(
864 " Site A ------------ proxies for B\n"
865 " |--Site B ------- proxies for A\n"
866 " +--Site B ------- proxies for A\n"
867 "Where A = http://a.com/\n"
868 " B = http://bar.com/",
869 DepictFrameTree(root));
872 // Verify that killing a cross-site frame's process B and then navigating a
873 // frame to B correctly recreates all proxies in B.
875 // 1 A A A
876 // / | \ / | \ / | \ / | \ .
877 // 2 3 4 -> B A A -> Kill B -> B* A A -> B* B A
879 // After the last step, the test sends a postMessage from node 3 to node 4,
880 // verifying that a proxy for node 4 has been recreated in process B. This
881 // verifies the fix for https://crbug.com/478892.
882 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
883 NavigatingToKilledProcessRestoresAllProxies) {
884 // Navigate to a page with three frames: one cross-site and two same-site.
885 GURL main_url(embedded_test_server()->GetURL(
886 "a.com", "/frame_tree/page_with_three_frames.html"));
887 NavigateToURL(shell(), main_url);
889 // It is safe to obtain the root frame tree node here, as it doesn't change.
890 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
891 ->GetFrameTree()
892 ->root();
893 TestNavigationObserver observer(shell()->web_contents());
895 EXPECT_EQ(
896 " Site A ------------ proxies for B\n"
897 " |--Site B ------- proxies for A\n"
898 " |--Site A ------- proxies for B\n"
899 " +--Site A ------- proxies for B\n"
900 "Where A = http://a.com/\n"
901 " B = http://b.com/",
902 DepictFrameTree(root));
904 // Kill the first subframe's b.com renderer.
905 RenderProcessHost* child_process =
906 root->child_at(0)->current_frame_host()->GetProcess();
907 RenderProcessHostWatcher crash_observer(
908 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
909 child_process->Shutdown(0, false);
910 crash_observer.Wait();
912 // Navigate the second subframe to b.com to recreate the b.com process.
913 GURL b_url = embedded_test_server()->GetURL("b.com", "/post_message.html");
914 NavigateFrameToURL(root->child_at(1), b_url);
915 // TODO(alexmos): This can be removed once TestFrameNavigationObserver is
916 // fixed to use DidFinishLoad.
917 EXPECT_TRUE(
918 WaitForRenderFrameReady(root->child_at(1)->current_frame_host()));
919 EXPECT_TRUE(observer.last_navigation_succeeded());
920 EXPECT_EQ(b_url, observer.last_navigation_url());
921 EXPECT_TRUE(root->child_at(1)->current_frame_host()->IsRenderFrameLive());
923 EXPECT_EQ(
924 " Site A ------------ proxies for B\n"
925 " |--Site B ------- proxies for A\n"
926 " |--Site B ------- proxies for A\n"
927 " +--Site A ------- proxies for B\n"
928 "Where A = http://a.com/\n"
929 " B = http://b.com/",
930 DepictFrameTree(root));
932 // Check that third subframe's proxy is available in the b.com process by
933 // sending it a postMessage from second subframe, and waiting for a reply.
934 PostMessageAndWaitForReply(root->child_at(1),
935 "postToSibling('subframe-msg','frame3')",
936 "\"done-frame2\"");
939 // Verify that proxy creation doesn't recreate a crashed process if no frame
940 // will be created in it.
942 // 1 A A A
943 // / | \ / | \ / | \ / | \ .
944 // 2 3 4 -> B A A -> Kill B -> B* A A -> B* A A
945 // \ .
946 // A
948 // The test kills process B (node 2), creates a child frame of node 4 in
949 // process A, and then checks that process B isn't resurrected to create a
950 // proxy for the new child frame. See https://crbug.com/476846.
951 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
952 CreateChildFrameAfterKillingProcess) {
953 // Navigate to a page with three frames: one cross-site and two same-site.
954 GURL main_url(embedded_test_server()->GetURL(
955 "a.com", "/frame_tree/page_with_three_frames.html"));
956 EXPECT_TRUE(NavigateToURL(shell(), main_url));
958 // It is safe to obtain the root frame tree node here, as it doesn't change.
959 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
960 ->GetFrameTree()
961 ->root();
963 EXPECT_EQ(
964 " Site A ------------ proxies for B\n"
965 " |--Site B ------- proxies for A\n"
966 " |--Site A ------- proxies for B\n"
967 " +--Site A ------- proxies for B\n"
968 "Where A = http://a.com/\n"
969 " B = http://b.com/",
970 DepictFrameTree(root));
971 SiteInstance* b_site_instance =
972 root->child_at(0)->current_frame_host()->GetSiteInstance();
974 // Kill the first subframe's renderer (B).
975 RenderProcessHost* child_process =
976 root->child_at(0)->current_frame_host()->GetProcess();
977 RenderProcessHostWatcher crash_observer(
978 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
979 child_process->Shutdown(0, false);
980 crash_observer.Wait();
982 // Add a new child frame to the third subframe.
983 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
984 EXPECT_TRUE(ExecuteScript(
985 root->child_at(2)->current_frame_host(),
986 "document.body.appendChild(document.createElement('iframe'));"));
987 frame_observer.Wait();
989 // The new frame should have a RenderFrameProxyHost for B, but it should not
990 // be alive, and B should still not have a process (verified by last line of
991 // expected DepictFrameTree output).
992 EXPECT_EQ(
993 " Site A ------------ proxies for B\n"
994 " |--Site B ------- proxies for A\n"
995 " |--Site A ------- proxies for B\n"
996 " +--Site A ------- proxies for B\n"
997 " +--Site A -- proxies for B\n"
998 "Where A = http://a.com/\n"
999 " B = http://b.com/ (no process)",
1000 DepictFrameTree(root));
1001 FrameTreeNode* grandchild = root->child_at(2)->child_at(0);
1002 RenderFrameProxyHost* grandchild_rfph =
1003 grandchild->render_manager()->GetRenderFrameProxyHost(b_site_instance);
1004 EXPECT_FALSE(grandchild_rfph->is_render_frame_proxy_live());
1006 // Navigate the second subframe to b.com to recreate process B.
1007 TestNavigationObserver observer(shell()->web_contents());
1008 GURL b_url = embedded_test_server()->GetURL("b.com", "/title1.html");
1009 NavigateFrameToURL(root->child_at(1), b_url);
1010 EXPECT_TRUE(observer.last_navigation_succeeded());
1011 EXPECT_EQ(b_url, observer.last_navigation_url());
1013 // Ensure that the grandchild RenderFrameProxy in B was created when process
1014 // B was restored.
1015 EXPECT_TRUE(grandchild_rfph->is_render_frame_proxy_live());
1018 // Verify that creating a child frame after killing and reloading an opener
1019 // process doesn't crash. See https://crbug.com/501152.
1020 // 1. Navigate to site A.
1021 // 2. Open a popup with window.open and navigate it cross-process to site B.
1022 // 3. Kill process A for the original tab.
1023 // 4. Reload the original tab to resurrect process A.
1024 // 5. Add a child frame to the top-level frame in the popup tab B.
1025 // In step 5, we try to create proxies for the child frame in all SiteInstances
1026 // for which its parent has proxies. This includes A. However, even though
1027 // process A is live (step 4), the parent proxy in A is not live (which was
1028 // incorrectly assumed previously). This is because step 4 does not resurrect
1029 // proxies for popups opened before the crash.
1030 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1031 CreateChildFrameAfterKillingOpener) {
1032 GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
1033 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1035 // It is safe to obtain the root frame tree node here, as it doesn't change.
1036 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1037 ->GetFrameTree()
1038 ->root();
1039 SiteInstance* site_instance_a = root->current_frame_host()->GetSiteInstance();
1041 // Open a popup and navigate it cross-process to b.com.
1042 ShellAddedObserver new_shell_observer;
1043 EXPECT_TRUE(ExecuteScript(root->current_frame_host(),
1044 "popup = window.open('about:blank');"));
1045 Shell* popup = new_shell_observer.GetShell();
1046 GURL popup_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
1047 EXPECT_TRUE(NavigateToURL(popup, popup_url));
1049 // Verify that each top-level frame has proxies in the other's SiteInstance.
1050 FrameTreeNode* popup_root =
1051 static_cast<WebContentsImpl*>(popup->web_contents())
1052 ->GetFrameTree()
1053 ->root();
1054 EXPECT_EQ(
1055 " Site A ------------ proxies for B\n"
1056 "Where A = http://a.com/\n"
1057 " B = http://b.com/",
1058 DepictFrameTree(root));
1059 EXPECT_EQ(
1060 " Site B ------------ proxies for A\n"
1061 "Where A = http://a.com/\n"
1062 " B = http://b.com/",
1063 DepictFrameTree(popup_root));
1065 // Kill the first window's renderer (a.com).
1066 RenderProcessHost* child_process = root->current_frame_host()->GetProcess();
1067 RenderProcessHostWatcher crash_observer(
1068 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1069 child_process->Shutdown(0, false);
1070 crash_observer.Wait();
1071 EXPECT_FALSE(root->current_frame_host()->IsRenderFrameLive());
1073 // The proxy for the popup in a.com should've died.
1074 RenderFrameProxyHost* rfph =
1075 popup_root->render_manager()->GetRenderFrameProxyHost(site_instance_a);
1076 EXPECT_FALSE(rfph->is_render_frame_proxy_live());
1078 // Recreate the a.com renderer.
1079 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1080 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
1082 // The popup's proxy in a.com should still not be live. Re-navigating the
1083 // main window to a.com doesn't reinitialize a.com proxies for popups
1084 // previously opened from the main window.
1085 EXPECT_FALSE(rfph->is_render_frame_proxy_live());
1087 // Add a new child frame on the popup.
1088 RenderFrameHostCreatedObserver frame_observer(popup->web_contents(), 1);
1089 EXPECT_TRUE(ExecuteScript(
1090 popup->web_contents(),
1091 "document.body.appendChild(document.createElement('iframe'));"));
1092 frame_observer.Wait();
1094 // Both the child frame's and its parent's proxies should still not be live.
1095 // The main page can't reach them since it lost reference to the popup after
1096 // it crashed, so there is no need to create them.
1097 EXPECT_FALSE(rfph->is_render_frame_proxy_live());
1098 RenderFrameProxyHost* child_rfph =
1099 popup_root->child_at(0)->render_manager()->GetRenderFrameProxyHost(
1100 site_instance_a);
1101 EXPECT_TRUE(child_rfph);
1102 EXPECT_FALSE(child_rfph->is_render_frame_proxy_live());
1105 // In A-embed-B-embed-C scenario, verify that killing process B clears proxies
1106 // of C from the tree.
1108 // 1 A A
1109 // / \ / \ / \ .
1110 // 2 3 -> B A -> Kill B -> B* A
1111 // / /
1112 // 4 C
1114 // node1 is the root.
1115 // Initially, both node1.proxy_hosts_ and node3.proxy_hosts_ contain C.
1116 // After we kill B, make sure proxies for C are cleared.
1117 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1118 KillingRendererClearsDescendantProxies) {
1119 GURL main_url(embedded_test_server()->GetURL(
1120 "a.com", "/frame_tree/page_with_two_frames_nested.html"));
1121 NavigateToURL(shell(), main_url);
1123 // It is safe to obtain the root frame tree node here, as it doesn't change.
1124 FrameTreeNode* root =
1125 static_cast<WebContentsImpl*>(shell()->web_contents())->
1126 GetFrameTree()->root();
1127 ASSERT_EQ(2U, root->child_count());
1129 GURL site_b_url(
1130 embedded_test_server()->GetURL(
1131 "bar.com", "/frame_tree/page_with_one_frame.html"));
1132 // We can't use a TestNavigationObserver to verify the URL here,
1133 // since the frame has children that may have clobbered it in the observer.
1134 EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
1136 // Ensure that a new process is created for node2.
1137 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1138 root->child_at(0)->current_frame_host()->GetSiteInstance());
1139 // Ensure that a new process is *not* created for node3.
1140 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
1141 root->child_at(1)->current_frame_host()->GetSiteInstance());
1143 ASSERT_EQ(1U, root->child_at(0)->child_count());
1145 // Make sure node4 points to the correct cross-site-page.
1146 FrameTreeNode* node4 = root->child_at(0)->child_at(0);
1147 GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
1148 EXPECT_EQ(site_c_url, node4->current_url());
1150 // |site_instance_c|'s frames and proxies are expected to go away once we kill
1151 // |child_process_b| below.
1152 scoped_refptr<SiteInstanceImpl> site_instance_c =
1153 node4->current_frame_host()->GetSiteInstance();
1155 // Initially proxies for both B and C will be present in the root.
1156 EXPECT_EQ(
1157 " Site A ------------ proxies for B C\n"
1158 " |--Site B ------- proxies for A C\n"
1159 " | +--Site C -- proxies for A B\n"
1160 " +--Site A ------- proxies for B C\n"
1161 "Where A = http://a.com/\n"
1162 " B = http://bar.com/\n"
1163 " C = http://baz.com/",
1164 DepictFrameTree(root));
1166 EXPECT_GT(site_instance_c->active_frame_count(), 0U);
1168 // Kill process B.
1169 RenderProcessHost* child_process_b =
1170 root->child_at(0)->current_frame_host()->GetProcess();
1171 RenderProcessHostWatcher crash_observer(
1172 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1173 child_process_b->Shutdown(0, false);
1174 crash_observer.Wait();
1176 // Make sure proxy C has gone from root.
1177 // Make sure proxy C has gone from node3 as well.
1178 // Make sure proxy B stays around in root and node3.
1179 EXPECT_EQ(
1180 " Site A ------------ proxies for B\n"
1181 " |--Site B ------- proxies for A\n"
1182 " +--Site A ------- proxies for B\n"
1183 "Where A = http://a.com/\n"
1184 " B = http://bar.com/ (no process)",
1185 DepictFrameTree(root));
1187 EXPECT_EQ(0U, site_instance_c->active_frame_count());
1190 // Crash a subframe and ensures its children are cleared from the FrameTree.
1191 // See http://crbug.com/338508.
1192 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrashSubframe) {
1193 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1194 NavigateToURL(shell(), main_url);
1196 StartFrameAtDataURL();
1198 // Load cross-site page into iframe.
1199 EXPECT_TRUE(NavigateIframeToURL(
1200 shell()->web_contents(), "test",
1201 embedded_test_server()->GetURL("/cross-site/foo.com/title2.html")));
1203 // Check the subframe process.
1204 FrameTreeNode* root =
1205 static_cast<WebContentsImpl*>(shell()->web_contents())->
1206 GetFrameTree()->root();
1207 ASSERT_EQ(2U, root->child_count());
1208 FrameTreeNode* child = root->child_at(0);
1209 EXPECT_EQ(main_url, root->current_url());
1210 EXPECT_EQ("foo.com", child->current_url().host());
1211 EXPECT_EQ("/title2.html", child->current_url().path());
1213 EXPECT_TRUE(
1214 child->current_frame_host()->render_view_host()->IsRenderViewLive());
1215 EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
1217 // Crash the subframe process.
1218 RenderProcessHost* root_process = root->current_frame_host()->GetProcess();
1219 RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
1221 RenderProcessHostWatcher crash_observer(
1222 child_process,
1223 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1224 child_process->Shutdown(0, false);
1225 crash_observer.Wait();
1228 // Ensure that the child frame still exists but has been cleared.
1229 EXPECT_EQ(2U, root->child_count());
1230 EXPECT_EQ(main_url, root->current_url());
1231 EXPECT_EQ(GURL(), child->current_url());
1233 EXPECT_FALSE(
1234 child->current_frame_host()->render_view_host()->IsRenderViewLive());
1235 EXPECT_FALSE(child->current_frame_host()->IsRenderFrameLive());
1236 EXPECT_FALSE(child->current_frame_host()->render_frame_created_);
1238 // Now crash the top-level page to clear the child frame.
1240 RenderProcessHostWatcher crash_observer(
1241 root_process,
1242 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1243 root_process->Shutdown(0, false);
1244 crash_observer.Wait();
1246 EXPECT_EQ(0U, root->child_count());
1247 EXPECT_EQ(GURL(), root->current_url());
1250 // When a new subframe is added, related SiteInstances that can reach the
1251 // subframe should create proxies for it (https://crbug.com/423587). This test
1252 // checks that if A embeds B and later adds a new subframe A2, A2 gets a proxy
1253 // in B's process.
1254 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CreateProxiesForNewFrames) {
1255 GURL main_url(embedded_test_server()->GetURL(
1256 "b.com", "/frame_tree/page_with_one_frame.html"));
1257 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1259 // It is safe to obtain the root frame tree node here, as it doesn't change.
1260 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1261 ->GetFrameTree()
1262 ->root();
1263 ASSERT_EQ(1U, root->child_count());
1265 // Make sure the frame starts out at the correct cross-site URL.
1266 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
1267 root->child_at(0)->current_url());
1269 EXPECT_EQ(
1270 " Site A ------------ proxies for B\n"
1271 " +--Site B ------- proxies for A\n"
1272 "Where A = http://b.com/\n"
1273 " B = http://baz.com/",
1274 DepictFrameTree(root));
1276 // Add a new child frame to the top-level frame.
1277 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
1278 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1279 "window.domAutomationController.send("
1280 " addFrame('data:text/html,foo'));"));
1281 frame_observer.Wait();
1283 // The new frame should have a proxy in Site B, for use by the old frame.
1284 EXPECT_EQ(
1285 " Site A ------------ proxies for B\n"
1286 " |--Site B ------- proxies for A\n"
1287 " +--Site A ------- proxies for B\n"
1288 "Where A = http://b.com/\n"
1289 " B = http://baz.com/",
1290 DepictFrameTree(root));
1293 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
1294 // security checks are back in place.
1295 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
1296 // on Android (http://crbug.com/187570).
1297 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1298 DISABLED_CrossSiteIframeRedirectOnce) {
1299 ASSERT_TRUE(test_server()->Start());
1300 net::SpawnedTestServer https_server(
1301 net::SpawnedTestServer::TYPE_HTTPS,
1302 net::SpawnedTestServer::kLocalhost,
1303 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1304 ASSERT_TRUE(https_server.Start());
1306 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
1307 GURL http_url(test_server()->GetURL("files/title1.html"));
1308 GURL https_url(https_server.GetURL("files/title1.html"));
1310 NavigateToURL(shell(), main_url);
1312 TestNavigationObserver observer(shell()->web_contents());
1314 // Load cross-site client-redirect page into Iframe.
1315 // Should be blocked.
1316 GURL client_redirect_https_url(https_server.GetURL(
1317 "client-redirect?files/title1.html"));
1318 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1319 client_redirect_https_url));
1320 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
1321 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
1322 EXPECT_FALSE(observer.last_navigation_succeeded());
1326 // Load cross-site server-redirect page into Iframe,
1327 // which redirects to same-site page.
1328 GURL server_redirect_http_url(https_server.GetURL(
1329 "server-redirect?" + http_url.spec()));
1330 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1331 server_redirect_http_url));
1332 EXPECT_EQ(observer.last_navigation_url(), http_url);
1333 EXPECT_TRUE(observer.last_navigation_succeeded());
1337 // Load cross-site server-redirect page into Iframe,
1338 // which redirects to cross-site page.
1339 GURL server_redirect_http_url(https_server.GetURL(
1340 "server-redirect?files/title1.html"));
1341 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1342 server_redirect_http_url));
1343 // DidFailProvisionalLoad when navigating to https_url.
1344 EXPECT_EQ(observer.last_navigation_url(), https_url);
1345 EXPECT_FALSE(observer.last_navigation_succeeded());
1349 // Load same-site server-redirect page into Iframe,
1350 // which redirects to cross-site page.
1351 GURL server_redirect_http_url(test_server()->GetURL(
1352 "server-redirect?" + https_url.spec()));
1353 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1354 server_redirect_http_url));
1356 EXPECT_EQ(observer.last_navigation_url(), https_url);
1357 EXPECT_FALSE(observer.last_navigation_succeeded());
1361 // Load same-site client-redirect page into Iframe,
1362 // which redirects to cross-site page.
1363 GURL client_redirect_http_url(test_server()->GetURL(
1364 "client-redirect?" + https_url.spec()));
1366 RedirectNotificationObserver load_observer2(
1367 NOTIFICATION_LOAD_STOP,
1368 Source<NavigationController>(
1369 &shell()->web_contents()->GetController()));
1371 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1372 client_redirect_http_url));
1374 // Same-site Client-Redirect Page should be loaded successfully.
1375 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1376 EXPECT_TRUE(observer.last_navigation_succeeded());
1378 // Redirecting to Cross-site Page should be blocked.
1379 load_observer2.Wait();
1380 EXPECT_EQ(observer.last_navigation_url(), https_url);
1381 EXPECT_FALSE(observer.last_navigation_succeeded());
1385 // Load same-site server-redirect page into Iframe,
1386 // which redirects to same-site page.
1387 GURL server_redirect_http_url(test_server()->GetURL(
1388 "server-redirect?files/title1.html"));
1389 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1390 server_redirect_http_url));
1391 EXPECT_EQ(observer.last_navigation_url(), http_url);
1392 EXPECT_TRUE(observer.last_navigation_succeeded());
1396 // Load same-site client-redirect page into Iframe,
1397 // which redirects to same-site page.
1398 GURL client_redirect_http_url(test_server()->GetURL(
1399 "client-redirect?" + http_url.spec()));
1400 RedirectNotificationObserver load_observer2(
1401 NOTIFICATION_LOAD_STOP,
1402 Source<NavigationController>(
1403 &shell()->web_contents()->GetController()));
1405 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1406 client_redirect_http_url));
1408 // Same-site Client-Redirect Page should be loaded successfully.
1409 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1410 EXPECT_TRUE(observer.last_navigation_succeeded());
1412 // Redirecting to Same-site Page should be loaded successfully.
1413 load_observer2.Wait();
1414 EXPECT_EQ(observer.last_navigation_url(), http_url);
1415 EXPECT_TRUE(observer.last_navigation_succeeded());
1419 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
1420 // security checks are back in place.
1421 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
1422 // on Android (http://crbug.com/187570).
1423 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1424 DISABLED_CrossSiteIframeRedirectTwice) {
1425 ASSERT_TRUE(test_server()->Start());
1426 net::SpawnedTestServer https_server(
1427 net::SpawnedTestServer::TYPE_HTTPS,
1428 net::SpawnedTestServer::kLocalhost,
1429 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1430 ASSERT_TRUE(https_server.Start());
1432 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
1433 GURL http_url(test_server()->GetURL("files/title1.html"));
1434 GURL https_url(https_server.GetURL("files/title1.html"));
1436 NavigateToURL(shell(), main_url);
1438 TestNavigationObserver observer(shell()->web_contents());
1440 // Load client-redirect page pointing to a cross-site client-redirect page,
1441 // which eventually redirects back to same-site page.
1442 GURL client_redirect_https_url(https_server.GetURL(
1443 "client-redirect?" + http_url.spec()));
1444 GURL client_redirect_http_url(test_server()->GetURL(
1445 "client-redirect?" + client_redirect_https_url.spec()));
1447 // We should wait until second client redirect get cancelled.
1448 RedirectNotificationObserver load_observer2(
1449 NOTIFICATION_LOAD_STOP,
1450 Source<NavigationController>(
1451 &shell()->web_contents()->GetController()));
1453 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1454 client_redirect_http_url));
1456 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
1457 load_observer2.Wait();
1458 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
1459 EXPECT_FALSE(observer.last_navigation_succeeded());
1463 // Load server-redirect page pointing to a cross-site server-redirect page,
1464 // which eventually redirect back to same-site page.
1465 GURL server_redirect_https_url(https_server.GetURL(
1466 "server-redirect?" + http_url.spec()));
1467 GURL server_redirect_http_url(test_server()->GetURL(
1468 "server-redirect?" + server_redirect_https_url.spec()));
1469 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1470 server_redirect_http_url));
1471 EXPECT_EQ(observer.last_navigation_url(), http_url);
1472 EXPECT_TRUE(observer.last_navigation_succeeded());
1476 // Load server-redirect page pointing to a cross-site server-redirect page,
1477 // which eventually redirects back to cross-site page.
1478 GURL server_redirect_https_url(https_server.GetURL(
1479 "server-redirect?" + https_url.spec()));
1480 GURL server_redirect_http_url(test_server()->GetURL(
1481 "server-redirect?" + server_redirect_https_url.spec()));
1482 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1483 server_redirect_http_url));
1485 // DidFailProvisionalLoad when navigating to https_url.
1486 EXPECT_EQ(observer.last_navigation_url(), https_url);
1487 EXPECT_FALSE(observer.last_navigation_succeeded());
1491 // Load server-redirect page pointing to a cross-site client-redirect page,
1492 // which eventually redirects back to same-site page.
1493 GURL client_redirect_http_url(https_server.GetURL(
1494 "client-redirect?" + http_url.spec()));
1495 GURL server_redirect_http_url(test_server()->GetURL(
1496 "server-redirect?" + client_redirect_http_url.spec()));
1497 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1498 server_redirect_http_url));
1500 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
1501 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1502 EXPECT_FALSE(observer.last_navigation_succeeded());
1506 // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
1507 // created in the FrameTree skipping the subtree of the navigating frame.
1508 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1509 ProxyCreationSkipsSubtree) {
1510 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1511 NavigateToURL(shell(), main_url);
1513 // It is safe to obtain the root frame tree node here, as it doesn't change.
1514 FrameTreeNode* root =
1515 static_cast<WebContentsImpl*>(shell()->web_contents())->
1516 GetFrameTree()->root();
1518 EXPECT_TRUE(root->child_at(1) != NULL);
1519 EXPECT_EQ(2U, root->child_at(1)->child_count());
1522 // Load same-site page into iframe.
1523 TestNavigationObserver observer(shell()->web_contents());
1524 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
1525 NavigateFrameToURL(root->child_at(0), http_url);
1526 EXPECT_EQ(http_url, observer.last_navigation_url());
1527 EXPECT_TRUE(observer.last_navigation_succeeded());
1528 EXPECT_EQ(
1529 " Site A\n"
1530 " |--Site A\n"
1531 " +--Site A\n"
1532 " |--Site A\n"
1533 " +--Site A\n"
1534 " +--Site A\n"
1535 "Where A = http://127.0.0.1/",
1536 DepictFrameTree(root));
1539 // Create the cross-site URL to navigate to.
1540 GURL cross_site_url =
1541 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html");
1543 // Load cross-site page into the second iframe without waiting for the
1544 // navigation to complete. Once LoadURLWithParams returns, we would expect
1545 // proxies to have been created in the frame tree, but children of the
1546 // navigating frame to still be present. The reason is that we don't run the
1547 // message loop, so no IPCs that alter the frame tree can be processed.
1548 FrameTreeNode* child = root->child_at(1);
1549 SiteInstance* site = NULL;
1550 bool browser_side_navigation =
1551 base::CommandLine::ForCurrentProcess()->HasSwitch(
1552 switches::kEnableBrowserSideNavigation);
1553 std::string cross_site_rfh_type =
1554 browser_side_navigation ? "speculative" : "pending";
1556 TestNavigationObserver observer(shell()->web_contents());
1557 TestFrameNavigationObserver navigation_observer(child);
1558 NavigationController::LoadURLParams params(cross_site_url);
1559 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
1560 params.frame_tree_node_id = child->frame_tree_node_id();
1561 child->navigator()->GetController()->LoadURLWithParams(params);
1563 if (browser_side_navigation) {
1564 site = child->render_manager()
1565 ->speculative_frame_host()
1566 ->GetSiteInstance();
1567 } else {
1568 site = child->render_manager()->pending_frame_host()->GetSiteInstance();
1570 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site);
1572 std::string tree = base::StringPrintf(
1573 " Site A ------------ proxies for B\n"
1574 " |--Site A ------- proxies for B\n"
1575 " +--Site A (B %s)\n"
1576 " |--Site A\n"
1577 " +--Site A\n"
1578 " +--Site A\n"
1579 "Where A = http://127.0.0.1/\n"
1580 " B = http://foo.com/",
1581 cross_site_rfh_type.c_str());
1582 EXPECT_EQ(tree, DepictFrameTree(root));
1584 // Now that the verification is done, run the message loop and wait for the
1585 // navigation to complete.
1586 navigation_observer.Wait();
1587 EXPECT_FALSE(child->render_manager()->pending_frame_host());
1588 EXPECT_TRUE(observer.last_navigation_succeeded());
1589 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
1591 EXPECT_EQ(
1592 " Site A ------------ proxies for B\n"
1593 " |--Site A ------- proxies for B\n"
1594 " +--Site B ------- proxies for A\n"
1595 "Where A = http://127.0.0.1/\n"
1596 " B = http://foo.com/",
1597 DepictFrameTree(root));
1600 // Load another cross-site page into the same iframe.
1601 cross_site_url = embedded_test_server()->GetURL("bar.com", "/title2.html");
1603 // Perform the same checks as the first cross-site navigation, since
1604 // there have been issues in subsequent cross-site navigations. Also ensure
1605 // that the SiteInstance has properly changed.
1606 // TODO(nasko): Once we have proper cleanup of resources, add code to
1607 // verify that the intermediate SiteInstance/RenderFrameHost have been
1608 // properly cleaned up.
1609 TestNavigationObserver observer(shell()->web_contents());
1610 TestFrameNavigationObserver navigation_observer(child);
1611 NavigationController::LoadURLParams params(cross_site_url);
1612 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
1613 params.frame_tree_node_id = child->frame_tree_node_id();
1614 child->navigator()->GetController()->LoadURLWithParams(params);
1616 SiteInstance* site2;
1617 if (browser_side_navigation) {
1618 site2 = child->render_manager()
1619 ->speculative_frame_host()
1620 ->GetSiteInstance();
1621 } else {
1622 site2 = child->render_manager()->pending_frame_host()->GetSiteInstance();
1624 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2);
1625 EXPECT_NE(site, site2);
1627 std::string tree = base::StringPrintf(
1628 " Site A ------------ proxies for B C\n"
1629 " |--Site A ------- proxies for B C\n"
1630 " +--Site B (C %s) -- proxies for A\n"
1631 "Where A = http://127.0.0.1/\n"
1632 " B = http://foo.com/\n"
1633 " C = http://bar.com/",
1634 cross_site_rfh_type.c_str());
1635 EXPECT_EQ(tree, DepictFrameTree(root));
1637 navigation_observer.Wait();
1638 EXPECT_TRUE(observer.last_navigation_succeeded());
1639 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
1640 EXPECT_EQ(0U, child->child_count());
1644 // Verify that origin replication works for an A-embed-B-embed-C hierarchy.
1645 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginReplication) {
1646 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1647 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1649 // It is safe to obtain the root frame tree node here, as it doesn't change.
1650 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1651 ->GetFrameTree()
1652 ->root();
1654 TestNavigationObserver observer(shell()->web_contents());
1656 // Navigate the first subframe to a cross-site page with two subframes.
1657 GURL foo_url(
1658 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1659 NavigateFrameToURL(root->child_at(0), foo_url);
1660 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1662 // We can't use a TestNavigationObserver to verify the URL here,
1663 // since the frame has children that may have clobbered it in the observer.
1664 EXPECT_EQ(foo_url, root->child_at(0)->current_url());
1666 // Ensure that a new process is created for the subframe.
1667 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1668 root->child_at(0)->current_frame_host()->GetSiteInstance());
1670 // Load cross-site page into subframe's subframe.
1671 ASSERT_EQ(2U, root->child_at(0)->child_count());
1672 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1673 NavigateFrameToURL(root->child_at(0)->child_at(0), bar_url);
1674 EXPECT_TRUE(observer.last_navigation_succeeded());
1675 EXPECT_EQ(bar_url, observer.last_navigation_url());
1677 // Check that a new process is created and is different from the top one and
1678 // the middle one.
1679 FrameTreeNode* bottom_child = root->child_at(0)->child_at(0);
1680 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1681 bottom_child->current_frame_host()->GetSiteInstance());
1682 EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
1683 bottom_child->current_frame_host()->GetSiteInstance());
1685 // Check that foo.com frame's location.ancestorOrigins contains the correct
1686 // origin for the parent. The origin should have been replicated as part of
1687 // the ViewMsg_New message that created the parent's RenderFrameProxy in
1688 // foo.com's process.
1689 int ancestor_origins_length = 0;
1690 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1691 root->child_at(0)->current_frame_host(),
1692 "window.domAutomationController.send(location.ancestorOrigins.length);",
1693 &ancestor_origins_length));
1694 EXPECT_EQ(1, ancestor_origins_length);
1695 std::string result;
1696 EXPECT_TRUE(ExecuteScriptAndExtractString(
1697 root->child_at(0)->current_frame_host(),
1698 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1699 &result));
1700 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1702 // Check that bar.com frame's location.ancestorOrigins contains the correct
1703 // origin for its two ancestors. The topmost parent origin should be
1704 // replicated as part of ViewMsg_New, and the middle frame (foo.com's) origin
1705 // should be replicated as part of FrameMsg_NewFrameProxy sent for foo.com's
1706 // frame in bar.com's process.
1707 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1708 bottom_child->current_frame_host(),
1709 "window.domAutomationController.send(location.ancestorOrigins.length);",
1710 &ancestor_origins_length));
1711 EXPECT_EQ(2, ancestor_origins_length);
1712 EXPECT_TRUE(ExecuteScriptAndExtractString(
1713 bottom_child->current_frame_host(),
1714 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1715 &result));
1716 EXPECT_EQ(result + "/", foo_url.GetOrigin().spec());
1717 EXPECT_TRUE(ExecuteScriptAndExtractString(
1718 bottom_child->current_frame_host(),
1719 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1720 &result));
1721 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1724 // Check that iframe sandbox flags are replicated correctly.
1725 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SandboxFlagsReplication) {
1726 GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
1727 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1729 // It is safe to obtain the root frame tree node here, as it doesn't change.
1730 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1731 ->GetFrameTree()
1732 ->root();
1734 TestNavigationObserver observer(shell()->web_contents());
1736 // Navigate the second (sandboxed) subframe to a cross-site page with a
1737 // subframe.
1738 GURL foo_url(
1739 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1740 NavigateFrameToURL(root->child_at(1), foo_url);
1741 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1743 // We can't use a TestNavigationObserver to verify the URL here,
1744 // since the frame has children that may have clobbered it in the observer.
1745 EXPECT_EQ(foo_url, root->child_at(1)->current_url());
1747 // Load cross-site page into subframe's subframe.
1748 ASSERT_EQ(2U, root->child_at(1)->child_count());
1749 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1750 NavigateFrameToURL(root->child_at(1)->child_at(0), bar_url);
1751 EXPECT_TRUE(observer.last_navigation_succeeded());
1752 EXPECT_EQ(bar_url, observer.last_navigation_url());
1754 // Opening a popup in the sandboxed foo.com iframe should fail.
1755 bool success = false;
1756 EXPECT_TRUE(
1757 ExecuteScriptAndExtractBool(root->child_at(1)->current_frame_host(),
1758 "window.domAutomationController.send("
1759 "!window.open('data:text/html,dataurl'));",
1760 &success));
1761 EXPECT_TRUE(success);
1762 EXPECT_EQ(1u, Shell::windows().size());
1764 // Opening a popup in a frame whose parent is sandboxed should also fail.
1765 // Here, bar.com frame's sandboxed parent frame is a remote frame in
1766 // bar.com's process.
1767 success = false;
1768 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1769 root->child_at(1)->child_at(0)->current_frame_host(),
1770 "window.domAutomationController.send("
1771 "!window.open('data:text/html,dataurl'));",
1772 &success));
1773 EXPECT_TRUE(success);
1774 EXPECT_EQ(1u, Shell::windows().size());
1776 // Same, but now try the case where bar.com frame's sandboxed parent is a
1777 // local frame in bar.com's process.
1778 success = false;
1779 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1780 root->child_at(2)->child_at(0)->current_frame_host(),
1781 "window.domAutomationController.send("
1782 "!window.open('data:text/html,dataurl'));",
1783 &success));
1784 EXPECT_TRUE(success);
1785 EXPECT_EQ(1u, Shell::windows().size());
1787 // Check that foo.com frame's location.ancestorOrigins contains the correct
1788 // origin for the parent, which should be unaffected by sandboxing.
1789 int ancestor_origins_length = 0;
1790 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1791 root->child_at(1)->current_frame_host(),
1792 "window.domAutomationController.send(location.ancestorOrigins.length);",
1793 &ancestor_origins_length));
1794 EXPECT_EQ(1, ancestor_origins_length);
1795 std::string result;
1796 EXPECT_TRUE(ExecuteScriptAndExtractString(
1797 root->child_at(1)->current_frame_host(),
1798 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1799 &result));
1800 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1802 // Now check location.ancestorOrigins for the bar.com frame. The middle frame
1803 // (foo.com's) origin should be unique, since that frame is sandboxed, and
1804 // the top frame should match |main_url|.
1805 FrameTreeNode* bottom_child = root->child_at(1)->child_at(0);
1806 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1807 bottom_child->current_frame_host(),
1808 "window.domAutomationController.send(location.ancestorOrigins.length);",
1809 &ancestor_origins_length));
1810 EXPECT_EQ(2, ancestor_origins_length);
1811 EXPECT_TRUE(ExecuteScriptAndExtractString(
1812 bottom_child->current_frame_host(),
1813 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1814 &result));
1815 EXPECT_EQ("null", result);
1816 EXPECT_TRUE(ExecuteScriptAndExtractString(
1817 bottom_child->current_frame_host(),
1818 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1819 &result));
1820 EXPECT_EQ(main_url.GetOrigin().spec(), result + "/");
1823 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1824 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicSandboxFlags) {
1825 GURL main_url(
1826 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1827 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1829 // It is safe to obtain the root frame tree node here, as it doesn't change.
1830 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1831 ->GetFrameTree()
1832 ->root();
1834 TestNavigationObserver observer(shell()->web_contents());
1835 ASSERT_EQ(2U, root->child_count());
1837 // Make sure first frame starts out at the correct cross-site page.
1838 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
1839 root->child_at(0)->current_url());
1841 // Navigate second frame to another cross-site page.
1842 GURL baz_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
1843 NavigateFrameToURL(root->child_at(1), baz_url);
1844 EXPECT_TRUE(observer.last_navigation_succeeded());
1845 EXPECT_EQ(baz_url, observer.last_navigation_url());
1847 // Both frames should not be sandboxed to start with.
1848 EXPECT_EQ(blink::WebSandboxFlags::None,
1849 root->child_at(0)->current_replication_state().sandbox_flags);
1850 EXPECT_EQ(blink::WebSandboxFlags::None,
1851 root->child_at(0)->effective_sandbox_flags());
1852 EXPECT_EQ(blink::WebSandboxFlags::None,
1853 root->child_at(1)->current_replication_state().sandbox_flags);
1854 EXPECT_EQ(blink::WebSandboxFlags::None,
1855 root->child_at(1)->effective_sandbox_flags());
1857 // Dynamically update sandbox flags for the first frame.
1858 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1859 "window.domAutomationController.send("
1860 "document.querySelector('iframe').sandbox="
1861 "'allow-scripts');"));
1863 // Check that updated sandbox flags are propagated to browser process.
1864 // The new flags should be set in current_replication_state(), while
1865 // effective_sandbox_flags() should still reflect the old flags, because
1866 // sandbox flag updates take place only after navigations. "allow-scripts"
1867 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
1868 // per blink::parseSandboxPolicy().
1869 blink::WebSandboxFlags expected_flags =
1870 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
1871 ~blink::WebSandboxFlags::AutomaticFeatures;
1872 EXPECT_EQ(expected_flags,
1873 root->child_at(0)->current_replication_state().sandbox_flags);
1874 EXPECT_EQ(blink::WebSandboxFlags::None,
1875 root->child_at(0)->effective_sandbox_flags());
1877 // Navigate the first frame to a page on the same site. The new sandbox
1878 // flags should take effect.
1879 GURL bar_url(
1880 embedded_test_server()->GetURL("bar.com", "/frame_tree/2-4.html"));
1881 NavigateFrameToURL(root->child_at(0), bar_url);
1882 // (The new page has a subframe; wait for it to load as well.)
1883 ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
1884 EXPECT_EQ(bar_url, root->child_at(0)->current_url());
1885 ASSERT_EQ(1U, root->child_at(0)->child_count());
1887 EXPECT_EQ(
1888 " Site A ------------ proxies for B C\n"
1889 " |--Site B ------- proxies for A C\n"
1890 " | +--Site B -- proxies for A C\n"
1891 " +--Site C ------- proxies for A B\n"
1892 "Where A = http://127.0.0.1/\n"
1893 " B = http://bar.com/\n"
1894 " C = http://baz.com/",
1895 DepictFrameTree(root));
1897 // Confirm that the browser process has updated the frame's current sandbox
1898 // flags.
1899 EXPECT_EQ(expected_flags,
1900 root->child_at(0)->current_replication_state().sandbox_flags);
1901 EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
1903 // Opening a popup in the now-sandboxed frame should fail.
1904 bool success = false;
1905 EXPECT_TRUE(
1906 ExecuteScriptAndExtractBool(root->child_at(0)->current_frame_host(),
1907 "window.domAutomationController.send("
1908 "!window.open('data:text/html,dataurl'));",
1909 &success));
1910 EXPECT_TRUE(success);
1911 EXPECT_EQ(1u, Shell::windows().size());
1913 // Navigate the child of the now-sandboxed frame to a page on baz.com. The
1914 // child should inherit the latest sandbox flags from its parent frame, which
1915 // is currently a proxy in baz.com's renderer process. This checks that the
1916 // proxies of |root->child_at(0)| were also updated with the latest sandbox
1917 // flags.
1918 GURL baz_child_url(embedded_test_server()->GetURL("baz.com", "/title2.html"));
1919 NavigateFrameToURL(root->child_at(0)->child_at(0), baz_child_url);
1920 EXPECT_TRUE(observer.last_navigation_succeeded());
1921 EXPECT_EQ(baz_child_url, observer.last_navigation_url());
1923 EXPECT_EQ(
1924 " Site A ------------ proxies for B C\n"
1925 " |--Site B ------- proxies for A C\n"
1926 " | +--Site C -- proxies for A B\n"
1927 " +--Site C ------- proxies for A B\n"
1928 "Where A = http://127.0.0.1/\n"
1929 " B = http://bar.com/\n"
1930 " C = http://baz.com/",
1931 DepictFrameTree(root));
1933 // Opening a popup in the child of a sandboxed frame should fail.
1934 success = false;
1935 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1936 root->child_at(0)->child_at(0)->current_frame_host(),
1937 "window.domAutomationController.send("
1938 "!window.open('data:text/html,dataurl'));",
1939 &success));
1940 EXPECT_TRUE(success);
1941 EXPECT_EQ(1u, Shell::windows().size());
1944 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1945 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1946 DynamicSandboxFlagsRemoteToLocal) {
1947 GURL main_url(
1948 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1949 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1951 // It is safe to obtain the root frame tree node here, as it doesn't change.
1952 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1953 ->GetFrameTree()
1954 ->root();
1956 TestNavigationObserver observer(shell()->web_contents());
1957 ASSERT_EQ(2U, root->child_count());
1959 // Make sure the two frames starts out at correct URLs.
1960 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
1961 root->child_at(0)->current_url());
1962 EXPECT_EQ(embedded_test_server()->GetURL("/title1.html"),
1963 root->child_at(1)->current_url());
1965 // Update the second frame's sandbox flags.
1966 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1967 "window.domAutomationController.send("
1968 "document.querySelectorAll('iframe')[1].sandbox="
1969 "'allow-scripts');"));
1971 // Check that the current sandbox flags are updated but the effective
1972 // sandbox flags are not.
1973 blink::WebSandboxFlags expected_flags =
1974 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
1975 ~blink::WebSandboxFlags::AutomaticFeatures;
1976 EXPECT_EQ(expected_flags,
1977 root->child_at(1)->current_replication_state().sandbox_flags);
1978 EXPECT_EQ(blink::WebSandboxFlags::None,
1979 root->child_at(1)->effective_sandbox_flags());
1981 // Navigate the second subframe to a page on bar.com. This will trigger a
1982 // remote-to-local frame swap in bar.com's process. The target page has
1983 // another frame, so use TestFrameNavigationObserver to wait for all frames
1984 // to be loaded.
1985 TestFrameNavigationObserver frame_observer(root->child_at(1), 2);
1986 GURL bar_url(embedded_test_server()->GetURL(
1987 "bar.com", "/frame_tree/page_with_one_frame.html"));
1988 NavigateFrameToURL(root->child_at(1), bar_url);
1989 frame_observer.Wait();
1990 EXPECT_EQ(bar_url, root->child_at(1)->current_url());
1991 ASSERT_EQ(1U, root->child_at(1)->child_count());
1993 // Confirm that the browser process has updated the current sandbox flags.
1994 EXPECT_EQ(expected_flags,
1995 root->child_at(1)->current_replication_state().sandbox_flags);
1996 EXPECT_EQ(expected_flags, root->child_at(1)->effective_sandbox_flags());
1998 // Opening a popup in the sandboxed second frame should fail.
1999 bool success = false;
2000 EXPECT_TRUE(
2001 ExecuteScriptAndExtractBool(root->child_at(1)->current_frame_host(),
2002 "window.domAutomationController.send("
2003 "!window.open('data:text/html,dataurl'));",
2004 &success));
2005 EXPECT_TRUE(success);
2006 EXPECT_EQ(1u, Shell::windows().size());
2008 // Make sure that the child frame inherits the sandbox flags of its
2009 // now-sandboxed parent frame.
2010 success = false;
2011 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2012 root->child_at(1)->child_at(0)->current_frame_host(),
2013 "window.domAutomationController.send("
2014 "!window.open('data:text/html,dataurl'));",
2015 &success));
2016 EXPECT_TRUE(success);
2017 EXPECT_EQ(1u, Shell::windows().size());
2020 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
2021 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2022 DynamicSandboxFlagsRendererInitiatedNavigation) {
2023 GURL main_url(
2024 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
2025 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2027 // It is safe to obtain the root frame tree node here, as it doesn't change.
2028 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2029 ->GetFrameTree()
2030 ->root();
2032 TestNavigationObserver observer(shell()->web_contents());
2033 ASSERT_EQ(1U, root->child_count());
2035 // Make sure the frame starts out at the correct cross-site page.
2036 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
2037 root->child_at(0)->current_url());
2039 // The frame should not be sandboxed to start with.
2040 EXPECT_EQ(blink::WebSandboxFlags::None,
2041 root->child_at(0)->current_replication_state().sandbox_flags);
2042 EXPECT_EQ(blink::WebSandboxFlags::None,
2043 root->child_at(0)->effective_sandbox_flags());
2045 // Dynamically update the frame's sandbox flags.
2046 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
2047 "window.domAutomationController.send("
2048 "document.querySelector('iframe').sandbox="
2049 "'allow-scripts');"));
2051 // Check that updated sandbox flags are propagated to browser process.
2052 // The new flags should be set in current_replication_state(), while
2053 // effective_sandbox_flags() should still reflect the old flags, because
2054 // sandbox flag updates take place only after navigations. "allow-scripts"
2055 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
2056 // per blink::parseSandboxPolicy().
2057 blink::WebSandboxFlags expected_flags =
2058 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
2059 ~blink::WebSandboxFlags::AutomaticFeatures;
2060 EXPECT_EQ(expected_flags,
2061 root->child_at(0)->current_replication_state().sandbox_flags);
2062 EXPECT_EQ(blink::WebSandboxFlags::None,
2063 root->child_at(0)->effective_sandbox_flags());
2065 // Perform a renderer-initiated same-site navigation in the first frame. The
2066 // new sandbox flags should take effect.
2067 TestFrameNavigationObserver frame_observer(root->child_at(0));
2068 ASSERT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
2069 "window.location.href='/title2.html'"));
2070 frame_observer.Wait();
2071 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title2.html"),
2072 root->child_at(0)->current_url());
2074 // Confirm that the browser process has updated the frame's current sandbox
2075 // flags.
2076 EXPECT_EQ(expected_flags,
2077 root->child_at(0)->current_replication_state().sandbox_flags);
2078 EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
2080 // Opening a popup in the now-sandboxed frame should fail.
2081 bool success = false;
2082 EXPECT_TRUE(
2083 ExecuteScriptAndExtractBool(root->child_at(0)->current_frame_host(),
2084 "window.domAutomationController.send("
2085 "!window.open('data:text/html,dataurl'));",
2086 &success));
2087 EXPECT_TRUE(success);
2088 EXPECT_EQ(1u, Shell::windows().size());
2091 // Verify that when a new child frame is added, the proxies created for it in
2092 // other SiteInstances have correct sandbox flags and origin.
2094 // A A A
2095 // / / \ / \ .
2096 // B -> B A -> B A
2097 // \ .
2098 // B
2100 // The test checks sandbox flags and origin for the proxy added in step 2, by
2101 // checking whether the grandchild frame added in step 3 sees proper sandbox
2102 // flags and origin for its (remote) parent. This wasn't addressed when
2103 // https://crbug.com/423587 was fixed.
2104 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2105 ProxiesForNewChildFramesHaveCorrectReplicationState) {
2106 GURL main_url(
2107 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
2108 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2110 // It is safe to obtain the root frame tree node here, as it doesn't change.
2111 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2112 ->GetFrameTree()
2113 ->root();
2114 TestNavigationObserver observer(shell()->web_contents());
2116 EXPECT_EQ(
2117 " Site A ------------ proxies for B\n"
2118 " +--Site B ------- proxies for A\n"
2119 "Where A = http://127.0.0.1/\n"
2120 " B = http://baz.com/",
2121 DepictFrameTree(root));
2123 // In the root frame, add a new sandboxed local frame, which itself has a
2124 // child frame on baz.com. Wait for three RenderFrameHosts to be created:
2125 // the new sandboxed local frame, its child (while it's still local), and a
2126 // pending RFH when starting the cross-site navigation to baz.com.
2127 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 3);
2128 EXPECT_TRUE(
2129 ExecuteScript(root->current_frame_host(),
2130 "window.domAutomationController.send("
2131 " addFrame('/frame_tree/page_with_one_frame.html',"
2132 " 'allow-scripts allow-same-origin'))"));
2133 frame_observer.Wait();
2135 // Wait for the cross-site navigation to baz.com in the grandchild to finish.
2136 FrameTreeNode* bottom_child = root->child_at(1)->child_at(0);
2137 TestFrameNavigationObserver navigation_observer(bottom_child);
2138 navigation_observer.Wait();
2140 EXPECT_EQ(
2141 " Site A ------------ proxies for B\n"
2142 " |--Site B ------- proxies for A\n"
2143 " +--Site A ------- proxies for B\n"
2144 " +--Site B -- proxies for A\n"
2145 "Where A = http://127.0.0.1/\n"
2146 " B = http://baz.com/",
2147 DepictFrameTree(root));
2149 // Use location.ancestorOrigins to check that the grandchild on baz.com sees
2150 // correct origin for its parent.
2151 int ancestor_origins_length = 0;
2152 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2153 bottom_child->current_frame_host(),
2154 "window.domAutomationController.send(location.ancestorOrigins.length);",
2155 &ancestor_origins_length));
2156 EXPECT_EQ(2, ancestor_origins_length);
2157 std::string parent_origin;
2158 EXPECT_TRUE(ExecuteScriptAndExtractString(
2159 bottom_child->current_frame_host(),
2160 "window.domAutomationController.send(location.ancestorOrigins[0]);",
2161 &parent_origin));
2162 EXPECT_EQ(main_url.GetOrigin().spec(), parent_origin + "/");
2164 // Check that the sandbox flags in the browser process are correct.
2165 // "allow-scripts" resets both WebSandboxFlags::Scripts and
2166 // WebSandboxFlags::AutomaticFeatures bits per blink::parseSandboxPolicy().
2167 blink::WebSandboxFlags expected_flags =
2168 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
2169 ~blink::WebSandboxFlags::AutomaticFeatures &
2170 ~blink::WebSandboxFlags::Origin;
2171 EXPECT_EQ(expected_flags,
2172 root->child_at(1)->current_replication_state().sandbox_flags);
2174 // The child of the sandboxed frame should've inherited sandbox flags, so it
2175 // should not be able to create popups.
2176 bool success = false;
2177 EXPECT_TRUE(
2178 ExecuteScriptAndExtractBool(bottom_child->current_frame_host(),
2179 "window.domAutomationController.send("
2180 "!window.open('data:text/html,dataurl'));",
2181 &success));
2182 EXPECT_TRUE(success);
2183 EXPECT_EQ(1u, Shell::windows().size());
2186 // Verify that a child frame can retrieve the name property set by its parent.
2187 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, WindowNameReplication) {
2188 GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
2189 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2191 // It is safe to obtain the root frame tree node here, as it doesn't change.
2192 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2193 ->GetFrameTree()
2194 ->root();
2196 TestNavigationObserver observer(shell()->web_contents());
2198 // Load cross-site page into iframe.
2199 GURL frame_url =
2200 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
2201 NavigateFrameToURL(root->child_at(0), frame_url);
2202 EXPECT_TRUE(observer.last_navigation_succeeded());
2203 EXPECT_EQ(frame_url, observer.last_navigation_url());
2205 // Ensure that a new process is created for the subframe.
2206 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
2207 root->child_at(0)->current_frame_host()->GetSiteInstance());
2209 // Check that the window.name seen by the frame matches the name attribute
2210 // specified by its parent in the iframe tag.
2211 std::string result;
2212 EXPECT_TRUE(ExecuteScriptAndExtractString(
2213 root->child_at(0)->current_frame_host(),
2214 "window.domAutomationController.send(window.name);", &result));
2215 EXPECT_EQ("3-1-name", result);
2218 // Verify that dynamic updates to a frame's window.name propagate to the
2219 // frame's proxies, so that the latest frame names can be used in navigations.
2220 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicWindowName) {
2221 GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
2222 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2224 // It is safe to obtain the root frame tree node here, as it doesn't change.
2225 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2226 ->GetFrameTree()
2227 ->root();
2228 TestNavigationObserver observer(shell()->web_contents());
2230 // Load cross-site page into iframe.
2231 GURL frame_url =
2232 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
2233 NavigateFrameToURL(root->child_at(0), frame_url);
2234 EXPECT_TRUE(observer.last_navigation_succeeded());
2235 EXPECT_EQ(frame_url, observer.last_navigation_url());
2237 // Browser process should know the child frame's original window.name
2238 // specified in the iframe element.
2239 EXPECT_EQ(root->child_at(0)->frame_name(), "3-1-name");
2241 // Update the child frame's window.name.
2242 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
2243 "window.domAutomationController.send("
2244 "window.name = 'updated-name');"));
2246 // The change should propagate to the browser process.
2247 EXPECT_EQ(root->child_at(0)->frame_name(), "updated-name");
2249 // The proxy in the parent process should also receive the updated name.
2250 // Check that it can reference the child frame by its new name.
2251 bool success = false;
2252 EXPECT_TRUE(
2253 ExecuteScriptAndExtractBool(shell()->web_contents(),
2254 "window.domAutomationController.send("
2255 "frames['updated-name'] == frames[0]);",
2256 &success));
2257 EXPECT_TRUE(success);
2259 // Issue a renderer-initiated navigation from the root frame to the child
2260 // frame using the frame's name. Make sure correct frame is navigated.
2262 // TODO(alexmos): When blink::createWindow is refactored to handle
2263 // RemoteFrames, this should also be tested via window.open(url, frame_name)
2264 // and a more complicated frame hierarchy (https://crbug.com/463742)
2265 TestFrameNavigationObserver frame_observer(root->child_at(0));
2266 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
2267 std::string script = base::StringPrintf(
2268 "window.domAutomationController.send("
2269 "frames['updated-name'].location.href = '%s');",
2270 foo_url.spec().c_str());
2271 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script));
2272 frame_observer.Wait();
2273 EXPECT_EQ(foo_url, root->child_at(0)->current_url());
2276 // Verify that when a frame is navigated to a new origin, the origin update
2277 // propagates to the frame's proxies.
2278 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginUpdatesReachProxies) {
2279 GURL main_url(
2280 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2281 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2283 // It is safe to obtain the root frame tree node here, as it doesn't change.
2284 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2285 ->GetFrameTree()
2286 ->root();
2287 TestNavigationObserver observer(shell()->web_contents());
2289 EXPECT_EQ(
2290 " Site A ------------ proxies for B\n"
2291 " |--Site B ------- proxies for A\n"
2292 " +--Site A ------- proxies for B\n"
2293 "Where A = http://127.0.0.1/\n"
2294 " B = http://bar.com/",
2295 DepictFrameTree(root));
2297 // Navigate second subframe to a baz.com. This should send an origin update
2298 // to the frame's proxy in the bar.com (first frame's) process.
2299 GURL frame_url = embedded_test_server()->GetURL("baz.com", "/title2.html");
2300 NavigateFrameToURL(root->child_at(1), frame_url);
2301 EXPECT_TRUE(observer.last_navigation_succeeded());
2302 EXPECT_EQ(frame_url, observer.last_navigation_url());
2304 // The first frame can't directly observe the second frame's origin with
2305 // JavaScript. Instead, try to navigate the second frame from the first
2306 // frame. This should fail with a console error message, which should
2307 // contain the second frame's updated origin (see blink::Frame::canNavigate).
2308 scoped_ptr<ConsoleObserverDelegate> console_delegate(
2309 new ConsoleObserverDelegate(
2310 shell()->web_contents(),
2311 "Unsafe JavaScript attempt to initiate navigation*"));
2312 shell()->web_contents()->SetDelegate(console_delegate.get());
2314 // frames[1] can't be used due to a bug where RemoteFrames are created out of
2315 // order (https://crbug.com/478792). Instead, target second frame by name.
2316 EXPECT_TRUE(ExecuteScript(
2317 root->child_at(0)->current_frame_host(),
2318 "window.domAutomationController.send("
2319 " parent.frames['frame2'].location.href = 'data:text/html,foo');"));
2320 console_delegate->Wait();
2322 std::string frame_origin =
2323 root->child_at(1)->current_replication_state().origin.Serialize();
2324 EXPECT_EQ(frame_origin + "/", frame_url.GetOrigin().spec());
2325 EXPECT_TRUE(
2326 base::MatchPattern(console_delegate->message(), "*" + frame_origin + "*"))
2327 << "Error message does not contain the frame's latest origin ("
2328 << frame_origin << ")";
2331 // Ensure that navigating subframes in --site-per-process mode properly fires
2332 // the DidStopLoading event on WebContentsObserver.
2333 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteDidStopLoading) {
2334 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
2335 NavigateToURL(shell(), main_url);
2337 // It is safe to obtain the root frame tree node here, as it doesn't change.
2338 FrameTreeNode* root =
2339 static_cast<WebContentsImpl*>(shell()->web_contents())->
2340 GetFrameTree()->root();
2342 TestNavigationObserver observer(shell()->web_contents());
2344 // Load same-site page into iframe.
2345 FrameTreeNode* child = root->child_at(0);
2346 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
2347 NavigateFrameToURL(child, http_url);
2348 EXPECT_EQ(http_url, observer.last_navigation_url());
2349 EXPECT_TRUE(observer.last_navigation_succeeded());
2351 // Load cross-site page into iframe.
2352 TestNavigationObserver nav_observer(shell()->web_contents(), 1);
2353 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
2354 NavigationController::LoadURLParams params(url);
2355 params.transition_type = ui::PAGE_TRANSITION_LINK;
2356 params.frame_tree_node_id = child->frame_tree_node_id();
2357 child->navigator()->GetController()->LoadURLWithParams(params);
2358 nav_observer.Wait();
2360 // Verify that the navigation succeeded and the expected URL was loaded.
2361 EXPECT_TRUE(observer.last_navigation_succeeded());
2362 EXPECT_EQ(url, observer.last_navigation_url());
2365 // Ensure that the renderer does not crash when navigating a frame that has a
2366 // sibling RemoteFrame. See https://crbug.com/426953.
2367 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2368 NavigateWithSiblingRemoteFrame) {
2369 GURL main_url(
2370 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2371 NavigateToURL(shell(), main_url);
2373 // It is safe to obtain the root frame tree node here, as it doesn't change.
2374 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2375 ->GetFrameTree()
2376 ->root();
2377 TestNavigationObserver observer(shell()->web_contents());
2379 // Make sure the first frame is out of process.
2380 ASSERT_EQ(2U, root->child_count());
2381 FrameTreeNode* node2 = root->child_at(0);
2382 EXPECT_NE(root->current_frame_host()->GetSiteInstance(),
2383 node2->current_frame_host()->GetSiteInstance());
2385 // Make sure the second frame is in the parent's process.
2386 FrameTreeNode* node3 = root->child_at(1);
2387 EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
2388 node3->current_frame_host()->GetSiteInstance());
2390 // Navigate the second iframe (node3) to a URL in its own process.
2391 GURL title_url = embedded_test_server()->GetURL("/title2.html");
2392 NavigateFrameToURL(node3, title_url);
2393 EXPECT_TRUE(observer.last_navigation_succeeded());
2394 EXPECT_EQ(title_url, observer.last_navigation_url());
2395 EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
2396 node3->current_frame_host()->GetSiteInstance());
2397 EXPECT_TRUE(node3->current_frame_host()->IsRenderFrameLive());
2400 // Verify that load events for iframe elements work when the child frame is
2401 // out-of-process. In such cases, the load event is forwarded from the child
2402 // frame to the parent frame via the browser process.
2403 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, LoadEventForwarding) {
2404 // Load a page with a cross-site frame. The parent page has an onload
2405 // handler in the iframe element that appends "LOADED" to the document title.
2407 GURL main_url(
2408 embedded_test_server()->GetURL("/frame_with_load_event.html"));
2409 base::string16 expected_title(base::UTF8ToUTF16("LOADED"));
2410 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
2411 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2412 EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
2415 // It is safe to obtain the root frame tree node here, as it doesn't change.
2416 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2417 ->GetFrameTree()
2418 ->root();
2420 // Load another cross-site page into the iframe and check that the load event
2421 // is fired.
2423 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
2424 base::string16 expected_title(base::UTF8ToUTF16("LOADEDLOADED"));
2425 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
2426 TestNavigationObserver observer(shell()->web_contents());
2427 NavigateFrameToURL(root->child_at(0), foo_url);
2428 EXPECT_TRUE(observer.last_navigation_succeeded());
2429 EXPECT_EQ(foo_url, observer.last_navigation_url());
2430 EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
2434 // Check that postMessage can be routed between cross-site iframes.
2435 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SubframePostMessage) {
2436 GURL main_url(embedded_test_server()->GetURL(
2437 "/frame_tree/page_with_post_message_frames.html"));
2438 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2440 // It is safe to obtain the root frame tree node here, as it doesn't change.
2441 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2442 ->GetFrameTree()
2443 ->root();
2445 ASSERT_EQ(2U, root->child_count());
2447 // Verify the frames start at correct URLs. First frame should be
2448 // same-site; second frame should be cross-site.
2449 GURL same_site_url(embedded_test_server()->GetURL("/post_message.html"));
2450 EXPECT_EQ(same_site_url, root->child_at(0)->current_url());
2451 GURL foo_url(embedded_test_server()->GetURL("foo.com",
2452 "/post_message.html"));
2453 EXPECT_EQ(foo_url, root->child_at(1)->current_url());
2454 EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
2455 root->child_at(1)->current_frame_host()->GetSiteInstance());
2457 // Send a message from first, same-site frame to second, cross-site frame.
2458 // Expect the second frame to reply back to the first frame.
2459 PostMessageAndWaitForReply(root->child_at(0),
2460 "postToSibling('subframe-msg','subframe2')",
2461 "\"done-subframe1\"");
2463 // Send a postMessage from second, cross-site frame to its parent. Expect
2464 // parent to send a reply to the frame.
2465 base::string16 expected_title(base::ASCIIToUTF16("subframe-msg"));
2466 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
2467 PostMessageAndWaitForReply(root->child_at(1), "postToParent('subframe-msg')",
2468 "\"done-subframe2\"");
2469 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
2471 // Verify the total number of received messages for each subframe. First
2472 // frame should have one message (reply from second frame). Second frame
2473 // should have two messages (message from first frame and reply from parent).
2474 // Parent should have one message (from second frame).
2475 EXPECT_EQ(1, GetReceivedMessages(root->child_at(0)));
2476 EXPECT_EQ(2, GetReceivedMessages(root->child_at(1)));
2477 EXPECT_EQ(1, GetReceivedMessages(root));
2480 // Check that postMessage can be sent from a subframe on a cross-process opener
2481 // tab, and that its event.source points to a valid proxy.
2482 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2483 PostMessageWithSubframeOnOpenerChain) {
2484 GURL main_url(embedded_test_server()->GetURL(
2485 "a.com", "/frame_tree/page_with_post_message_frames.html"));
2486 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2488 // It is safe to obtain the root frame tree node here, as it doesn't change.
2489 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2490 ->GetFrameTree()
2491 ->root();
2493 ASSERT_EQ(2U, root->child_count());
2495 // Verify the initial state of the world. First frame should be same-site;
2496 // second frame should be cross-site.
2497 EXPECT_EQ(
2498 " Site A ------------ proxies for B\n"
2499 " |--Site A ------- proxies for B\n"
2500 " +--Site B ------- proxies for A\n"
2501 "Where A = http://a.com/\n"
2502 " B = http://foo.com/",
2503 DepictFrameTree(root));
2505 // Open a popup from the first subframe (so that popup's window.opener points
2506 // to the subframe) and navigate it to bar.com.
2507 ShellAddedObserver new_shell_observer;
2508 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
2509 "openPopup('about:blank');"));
2510 Shell* popup = new_shell_observer.GetShell();
2511 GURL popup_url(
2512 embedded_test_server()->GetURL("bar.com", "/post_message.html"));
2513 EXPECT_TRUE(NavigateToURL(popup, popup_url));
2515 // From the popup, open another popup for baz.com. This will be used to
2516 // check that the whole opener chain is processed when creating proxies and
2517 // not just an immediate opener.
2518 ShellAddedObserver new_shell_observer2;
2519 EXPECT_TRUE(
2520 ExecuteScript(popup->web_contents(), "openPopup('about:blank');"));
2521 Shell* popup2 = new_shell_observer2.GetShell();
2522 GURL popup2_url(
2523 embedded_test_server()->GetURL("baz.com", "/post_message.html"));
2524 EXPECT_TRUE(NavigateToURL(popup2, popup2_url));
2526 // Ensure that we've created proxies for SiteInstances of both popups (C, D)
2527 // in the main window's frame tree.
2528 EXPECT_EQ(
2529 " Site A ------------ proxies for B C D\n"
2530 " |--Site A ------- proxies for B C D\n"
2531 " +--Site B ------- proxies for A C D\n"
2532 "Where A = http://a.com/\n"
2533 " B = http://foo.com/\n"
2534 " C = http://bar.com/\n"
2535 " D = http://baz.com/",
2536 DepictFrameTree(root));
2538 // Check the first popup's frame tree as well. Note that it doesn't have a
2539 // proxy for foo.com, since foo.com can't reach the popup. It does have a
2540 // proxy for its opener a.com (which can reach it via the window.open
2541 // reference) and second popup (which can reach it via window.opener).
2542 FrameTreeNode* popup_root =
2543 static_cast<WebContentsImpl*>(popup->web_contents())
2544 ->GetFrameTree()
2545 ->root();
2546 EXPECT_EQ(
2547 " Site C ------------ proxies for A D\n"
2548 "Where A = http://a.com/\n"
2549 " C = http://bar.com/\n"
2550 " D = http://baz.com/",
2551 DepictFrameTree(popup_root));
2553 // Send a message from first subframe on main page to the first popup and
2554 // wait for a reply back. The reply verifies that the proxy for the opener
2555 // tab's subframe is targeted properly.
2556 PostMessageAndWaitForReply(root->child_at(0), "postToPopup('subframe-msg')",
2557 "\"done-subframe1\"");
2559 // Send a postMessage from the popup to window.opener and ensure that it
2560 // reaches subframe1. This verifies that the subframe opener information
2561 // propagated to the popup's RenderFrame. Wait for subframe1 to send a reply
2562 // message to the popup.
2563 EXPECT_TRUE(ExecuteScript(popup->web_contents(), "window.name = 'popup';"));
2564 PostMessageAndWaitForReply(popup_root, "postToOpener('subframe-msg', '*')",
2565 "\"done-popup\"");
2567 // Second a postMessage from popup2 to window.opener.opener, which should
2568 // resolve to subframe1. This tests opener chains of length greater than 1.
2569 // As before, subframe1 will send a reply to popup2.
2570 FrameTreeNode* popup2_root =
2571 static_cast<WebContentsImpl*>(popup2->web_contents())
2572 ->GetFrameTree()
2573 ->root();
2574 EXPECT_TRUE(ExecuteScript(popup2->web_contents(), "window.name = 'popup2';"));
2575 PostMessageAndWaitForReply(popup2_root,
2576 "postToOpenerOfOpener('subframe-msg', '*')",
2577 "\"done-popup2\"");
2579 // Verify the total number of received messages for each subframe:
2580 // - 3 for first subframe (two from first popup, one from second popup)
2581 // - 2 for popup (both from first subframe)
2582 // - 1 for popup2 (reply from first subframe)
2583 // - 0 for other frames
2584 EXPECT_EQ(0, GetReceivedMessages(root));
2585 EXPECT_EQ(3, GetReceivedMessages(root->child_at(0)));
2586 EXPECT_EQ(0, GetReceivedMessages(root->child_at(1)));
2587 EXPECT_EQ(2, GetReceivedMessages(popup_root));
2588 EXPECT_EQ(1, GetReceivedMessages(popup2_root));
2591 // Check that parent.frames[num] references correct sibling frames when the
2592 // parent is remote. See https://crbug.com/478792.
2593 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, IndexedFrameAccess) {
2594 // Start on a page with three same-site subframes.
2595 GURL main_url(
2596 embedded_test_server()->GetURL("a.com", "/frame_tree/top.html"));
2597 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2599 // It is safe to obtain the root frame tree node here, as it doesn't change.
2600 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2601 ->GetFrameTree()
2602 ->root();
2603 ASSERT_EQ(3U, root->child_count());
2604 FrameTreeNode* child0 = root->child_at(0);
2605 FrameTreeNode* child1 = root->child_at(1);
2606 FrameTreeNode* child2 = root->child_at(2);
2608 // Send each of the frames to a different site. Each new renderer will first
2609 // create proxies for the parent and two sibling subframes and then create
2610 // and insert the new RenderFrame into the frame tree.
2611 GURL b_url(embedded_test_server()->GetURL("b.com", "/post_message.html"));
2612 GURL c_url(embedded_test_server()->GetURL("c.com", "/post_message.html"));
2613 GURL d_url(embedded_test_server()->GetURL("d.com", "/post_message.html"));
2614 NavigateFrameToURL(child0, b_url);
2615 // TODO(alexmos): The calls to WaitForRenderFrameReady can be removed once
2616 // TestFrameNavigationObserver is fixed to use DidFinishLoad.
2617 EXPECT_TRUE(WaitForRenderFrameReady(child0->current_frame_host()));
2618 NavigateFrameToURL(child1, c_url);
2619 EXPECT_TRUE(WaitForRenderFrameReady(child1->current_frame_host()));
2620 NavigateFrameToURL(child2, d_url);
2621 EXPECT_TRUE(WaitForRenderFrameReady(child2->current_frame_host()));
2623 EXPECT_EQ(
2624 " Site A ------------ proxies for B C D\n"
2625 " |--Site B ------- proxies for A C D\n"
2626 " |--Site C ------- proxies for A B D\n"
2627 " +--Site D ------- proxies for A B C\n"
2628 "Where A = http://a.com/\n"
2629 " B = http://b.com/\n"
2630 " C = http://c.com/\n"
2631 " D = http://d.com/",
2632 DepictFrameTree(root));
2634 // Check that each subframe sees itself at correct index in parent.frames.
2635 bool success = false;
2636 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2637 child0->current_frame_host(),
2638 "window.domAutomationController.send(window === parent.frames[0]);",
2639 &success));
2640 EXPECT_TRUE(success);
2642 success = false;
2643 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2644 child1->current_frame_host(),
2645 "window.domAutomationController.send(window === parent.frames[1]);",
2646 &success));
2647 EXPECT_TRUE(success);
2649 success = false;
2650 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2651 child2->current_frame_host(),
2652 "window.domAutomationController.send(window === parent.frames[2]);",
2653 &success));
2654 EXPECT_TRUE(success);
2656 // Send a postMessage from B to parent.frames[1], which should go to C, and
2657 // wait for reply.
2658 PostMessageAndWaitForReply(child0, "postToSibling('subframe-msg', 1)",
2659 "\"done-1-1-name\"");
2661 // Send a postMessage from C to parent.frames[2], which should go to D, and
2662 // wait for reply.
2663 PostMessageAndWaitForReply(child1, "postToSibling('subframe-msg', 2)",
2664 "\"done-1-2-name\"");
2666 // Verify the total number of received messages for each subframe.
2667 EXPECT_EQ(1, GetReceivedMessages(child0));
2668 EXPECT_EQ(2, GetReceivedMessages(child1));
2669 EXPECT_EQ(1, GetReceivedMessages(child2));
2672 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RFPHDestruction) {
2673 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
2674 NavigateToURL(shell(), main_url);
2676 // It is safe to obtain the root frame tree node here, as it doesn't change.
2677 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2678 ->GetFrameTree()
2679 ->root();
2681 TestNavigationObserver observer(shell()->web_contents());
2683 // Load cross-site page into iframe.
2684 FrameTreeNode* child = root->child_at(0);
2685 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
2686 NavigateFrameToURL(root->child_at(0), url);
2687 EXPECT_TRUE(observer.last_navigation_succeeded());
2688 EXPECT_EQ(url, observer.last_navigation_url());
2689 EXPECT_EQ(
2690 " Site A ------------ proxies for B\n"
2691 " |--Site B ------- proxies for A\n"
2692 " +--Site A ------- proxies for B\n"
2693 " |--Site A -- proxies for B\n"
2694 " +--Site A -- proxies for B\n"
2695 " +--Site A -- proxies for B\n"
2696 "Where A = http://127.0.0.1/\n"
2697 " B = http://foo.com/",
2698 DepictFrameTree(root));
2700 // Load another cross-site page.
2701 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
2702 NavigateIframeToURL(shell()->web_contents(), "test", url);
2703 EXPECT_TRUE(observer.last_navigation_succeeded());
2704 EXPECT_EQ(url, observer.last_navigation_url());
2705 EXPECT_EQ(
2706 " Site A ------------ proxies for C\n"
2707 " |--Site C ------- proxies for A\n"
2708 " +--Site A ------- proxies for C\n"
2709 " |--Site A -- proxies for C\n"
2710 " +--Site A -- proxies for C\n"
2711 " +--Site A -- proxies for C\n"
2712 "Where A = http://127.0.0.1/\n"
2713 " C = http://bar.com/",
2714 DepictFrameTree(root));
2716 // Navigate back to the parent's origin.
2717 url = embedded_test_server()->GetURL("/title1.html");
2718 NavigateFrameToURL(child, url);
2719 EXPECT_EQ(url, observer.last_navigation_url());
2720 EXPECT_TRUE(observer.last_navigation_succeeded());
2721 EXPECT_EQ(
2722 " Site A\n"
2723 " |--Site A\n"
2724 " +--Site A\n"
2725 " |--Site A\n"
2726 " +--Site A\n"
2727 " +--Site A\n"
2728 "Where A = http://127.0.0.1/",
2729 DepictFrameTree(root));
2732 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OpenPopupWithRemoteParent) {
2733 GURL main_url(
2734 embedded_test_server()->GetURL("a.com", "/site_per_process_main.html"));
2735 NavigateToURL(shell(), main_url);
2737 // It is safe to obtain the root frame tree node here, as it doesn't change.
2738 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2739 ->GetFrameTree()
2740 ->root();
2742 // Navigate first child cross-site.
2743 GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
2744 NavigateFrameToURL(root->child_at(0), frame_url);
2746 // Open a popup from the first child.
2747 Shell* new_shell = OpenPopup(root->child_at(0)->current_frame_host(),
2748 GURL(url::kAboutBlankURL), "");
2749 EXPECT_TRUE(new_shell);
2751 // Check that the popup's opener is correct on both the browser and renderer
2752 // sides.
2753 FrameTreeNode* popup_root =
2754 static_cast<WebContentsImpl*>(new_shell->web_contents())
2755 ->GetFrameTree()
2756 ->root();
2757 EXPECT_EQ(root->child_at(0), popup_root->opener());
2759 std::string opener_url;
2760 EXPECT_TRUE(ExecuteScriptAndExtractString(
2761 popup_root->current_frame_host(),
2762 "window.domAutomationController.send(window.opener.location.href);",
2763 &opener_url));
2764 EXPECT_EQ(frame_url.spec(), opener_url);
2766 // Now try the same with a cross-site popup and make sure it ends up in a new
2767 // process and with a correct opener.
2768 GURL popup_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
2769 Shell* cross_site_popup =
2770 OpenPopup(root->child_at(0)->current_frame_host(), popup_url, "");
2771 EXPECT_TRUE(cross_site_popup);
2773 FrameTreeNode* cross_site_popup_root =
2774 static_cast<WebContentsImpl*>(cross_site_popup->web_contents())
2775 ->GetFrameTree()
2776 ->root();
2777 EXPECT_EQ(cross_site_popup_root->current_url(), popup_url);
2779 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
2780 cross_site_popup->web_contents()->GetSiteInstance());
2781 EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
2782 cross_site_popup->web_contents()->GetSiteInstance());
2784 EXPECT_EQ(root->child_at(0), cross_site_popup_root->opener());
2786 // Ensure the popup's window.opener points to the right subframe. Note that
2787 // we can't check the opener's location as above since it's cross-origin.
2788 bool success = false;
2789 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2790 cross_site_popup_root->current_frame_host(),
2791 "window.domAutomationController.send("
2792 " window.opener === window.opener.top.frames[0]);",
2793 &success));
2794 EXPECT_TRUE(success);
2797 // Verify that named frames are discoverable from their opener's ancestors.
2798 // See https://crbug.com/511474.
2799 // Disable this flaky test on the official cros-trunk for now.
2800 // See crbug.com/515302.
2801 #if defined(OFFICIAL_BUILD)
2802 #define MAYBE_DiscoverNamedFrameFromAncestorOfOpener \
2803 DISABLED_DiscoverNamedFrameFromAncestorOfOpener
2804 #else
2805 #define MAYBE_DiscoverNamedFrameFromAncestorOfOpener \
2806 DiscoverNamedFrameFromAncestorOfOpener
2807 #endif // defined(OFFICIAL_BUILD)
2808 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2809 MAYBE_DiscoverNamedFrameFromAncestorOfOpener) {
2810 GURL main_url(
2811 embedded_test_server()->GetURL("a.com", "/site_per_process_main.html"));
2812 NavigateToURL(shell(), main_url);
2814 // It is safe to obtain the root frame tree node here, as it doesn't change.
2815 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2816 ->GetFrameTree()
2817 ->root();
2819 // Navigate first child cross-site.
2820 GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
2821 NavigateFrameToURL(root->child_at(0), frame_url);
2823 // Open a popup named "foo" from the first child.
2824 Shell* foo_shell = OpenPopup(root->child_at(0)->current_frame_host(),
2825 GURL(url::kAboutBlankURL), "foo");
2826 EXPECT_TRUE(foo_shell);
2828 // Check that a proxy was created for the "foo" popup in a.com.
2829 FrameTreeNode* foo_root =
2830 static_cast<WebContentsImpl*>(foo_shell->web_contents())
2831 ->GetFrameTree()
2832 ->root();
2833 SiteInstance* site_instance_a = root->current_frame_host()->GetSiteInstance();
2834 RenderFrameProxyHost* popup_rfph_for_a =
2835 foo_root->render_manager()->GetRenderFrameProxyHost(site_instance_a);
2836 EXPECT_TRUE(popup_rfph_for_a);
2838 // Verify that the main frame can find the "foo" popup by name. If
2839 // window.open targets the correct frame, the "foo" popup's current URL
2840 // should be updated to |named_frame_url|.
2841 GURL named_frame_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
2842 NavigateNamedFrame(shell()->web_contents(), named_frame_url, "foo");
2843 EXPECT_TRUE(WaitForLoadStop(foo_shell->web_contents()));
2844 EXPECT_EQ(named_frame_url, foo_root->current_url());
2846 // Navigate the popup cross-site and ensure it's still reachable via
2847 // window.open from the main frame.
2848 GURL d_url(embedded_test_server()->GetURL("d.com", "/title3.html"));
2849 NavigateToURL(foo_shell, d_url);
2850 EXPECT_EQ(d_url, foo_root->current_url());
2851 NavigateNamedFrame(shell()->web_contents(), named_frame_url, "foo");
2852 EXPECT_TRUE(WaitForLoadStop(foo_shell->web_contents()));
2853 EXPECT_EQ(named_frame_url, foo_root->current_url());
2856 // Similar to DiscoverNamedFrameFromAncestorOfOpener, but check that if a
2857 // window is created without a name and acquires window.name later, it will
2858 // still be discoverable from its opener's ancestors. Also, instead of using
2859 // an opener's ancestor, this test uses a popup with same origin as that
2860 // ancestor. See https://crbug.com/511474.
2861 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2862 DiscoverFrameAfterSettingWindowName) {
2863 GURL main_url(
2864 embedded_test_server()->GetURL("a.com", "/site_per_process_main.html"));
2865 NavigateToURL(shell(), main_url);
2867 // It is safe to obtain the root frame tree node here, as it doesn't change.
2868 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2869 ->GetFrameTree()
2870 ->root();
2872 // Open a same-site popup from the main frame.
2873 GURL a_com_url(embedded_test_server()->GetURL("a.com", "/title3.html"));
2874 Shell* a_com_shell =
2875 OpenPopup(root->child_at(0)->current_frame_host(), a_com_url, "");
2876 EXPECT_TRUE(a_com_shell);
2878 // Navigate first child on main frame cross-site.
2879 GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
2880 NavigateFrameToURL(root->child_at(0), frame_url);
2882 // Open an unnamed popup from the first child frame.
2883 Shell* foo_shell = OpenPopup(root->child_at(0)->current_frame_host(),
2884 GURL(url::kAboutBlankURL), "");
2885 EXPECT_TRUE(foo_shell);
2887 // There should be no proxy created for the "foo" popup in a.com, since
2888 // there's no way for the two a.com frames to access it yet.
2889 FrameTreeNode* foo_root =
2890 static_cast<WebContentsImpl*>(foo_shell->web_contents())
2891 ->GetFrameTree()
2892 ->root();
2893 SiteInstance* site_instance_a = root->current_frame_host()->GetSiteInstance();
2894 EXPECT_FALSE(
2895 foo_root->render_manager()->GetRenderFrameProxyHost(site_instance_a));
2897 // Set window.name in the popup's frame.
2898 EXPECT_TRUE(ExecuteScript(foo_shell->web_contents(), "window.name = 'foo'"));
2900 // A proxy for the popup should now exist in a.com.
2901 EXPECT_TRUE(
2902 foo_root->render_manager()->GetRenderFrameProxyHost(site_instance_a));
2904 // Verify that the a.com popup can now find the "foo" popup by name.
2905 GURL named_frame_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
2906 NavigateNamedFrame(a_com_shell->web_contents(), named_frame_url, "foo");
2907 EXPECT_TRUE(WaitForLoadStop(foo_shell->web_contents()));
2908 EXPECT_EQ(named_frame_url, foo_root->current_url());
2911 } // namespace content