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